2008-04-03 15:40:36 +02:00
|
|
|
#ifdef _MSC_VER
|
2008-04-03 15:56:50 +02:00
|
|
|
#define _CRT_SECURE_NO_DEPRECATE
|
2008-04-03 15:40:36 +02:00
|
|
|
#endif
|
|
|
|
|
2008-03-11 02:27:59 +01:00
|
|
|
#include <stdio.h>
|
2008-03-25 08:30:04 +01:00
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
2008-01-31 07:04:26 +01:00
|
|
|
#include "vgmstream.h"
|
2008-05-06 05:35:37 +02:00
|
|
|
#include "meta/meta.h"
|
|
|
|
#include "layout/layout.h"
|
|
|
|
#include "coding/coding.h"
|
2008-05-04 22:36:40 +02:00
|
|
|
|
2008-01-31 07:04:26 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* List of functions that will recognize files. These should correspond pretty
|
|
|
|
* directly to the metadata types
|
|
|
|
*/
|
2008-06-09 02:20:08 +02:00
|
|
|
VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
|
|
|
|
init_vgmstream_adx,
|
|
|
|
init_vgmstream_brstm,
|
|
|
|
init_vgmstream_nds_strm,
|
|
|
|
init_vgmstream_agsc,
|
|
|
|
init_vgmstream_ngc_adpdtk,
|
|
|
|
init_vgmstream_rsf,
|
|
|
|
init_vgmstream_afc,
|
|
|
|
init_vgmstream_ast,
|
|
|
|
init_vgmstream_halpst,
|
|
|
|
init_vgmstream_rs03,
|
|
|
|
init_vgmstream_ngc_dsp_std,
|
|
|
|
init_vgmstream_Cstr,
|
|
|
|
init_vgmstream_gcsw,
|
|
|
|
init_vgmstream_ps2_ads,
|
|
|
|
init_vgmstream_ps2_npsf,
|
|
|
|
init_vgmstream_rwsd,
|
|
|
|
init_vgmstream_cdxa,
|
|
|
|
init_vgmstream_ps2_rxw,
|
|
|
|
init_vgmstream_ps2_int,
|
|
|
|
init_vgmstream_ngc_dsp_stm,
|
|
|
|
init_vgmstream_ps2_exst,
|
|
|
|
init_vgmstream_ps2_svag,
|
|
|
|
init_vgmstream_ps2_mib,
|
|
|
|
init_vgmstream_ngc_mpdsp,
|
|
|
|
init_vgmstream_ps2_mic,
|
|
|
|
init_vgmstream_ngc_dsp_std_int,
|
|
|
|
init_vgmstream_raw,
|
|
|
|
init_vgmstream_ps2_vag,
|
|
|
|
init_vgmstream_psx_gms,
|
|
|
|
init_vgmstream_ps2_str,
|
|
|
|
init_vgmstream_ps2_ild,
|
|
|
|
init_vgmstream_ps2_pnb,
|
|
|
|
init_vgmstream_xbox_wavm,
|
|
|
|
init_vgmstream_xbox_xwav,
|
|
|
|
init_vgmstream_ngc_str,
|
|
|
|
init_vgmstream_ea,
|
|
|
|
init_vgmstream_caf,
|
|
|
|
init_vgmstream_ps2_vpk,
|
2008-06-10 03:20:54 +02:00
|
|
|
init_vgmstream_genh,
|
2008-06-15 09:59:43 +02:00
|
|
|
#ifdef VGM_USE_VORBIS
|
2008-06-15 06:01:03 +02:00
|
|
|
init_vgmstream_ogg_vorbis,
|
2008-06-15 09:59:43 +02:00
|
|
|
#endif
|
2008-06-15 11:23:34 +02:00
|
|
|
init_vgmstream_sadb,
|
2008-06-25 20:04:39 +02:00
|
|
|
init_vgmstream_ps2_bmdx,
|
2008-06-29 03:30:13 +02:00
|
|
|
init_vgmstream_wsi,
|
2008-07-01 05:23:44 +02:00
|
|
|
init_vgmstream_aifc,
|
2008-07-02 15:39:51 +02:00
|
|
|
init_vgmstream_str_snds,
|
2008-01-31 07:04:26 +01:00
|
|
|
};
|
|
|
|
|
2008-06-09 02:20:08 +02:00
|
|
|
#define INIT_VGMSTREAM_FCNS (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0]))
|
|
|
|
|
2008-03-25 08:30:04 +01:00
|
|
|
/* internal version with all parameters */
|
2008-05-20 17:18:38 +02:00
|
|
|
VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) {
|
2008-01-31 07:04:26 +01:00
|
|
|
int i;
|
2008-05-20 17:18:38 +02:00
|
|
|
|
|
|
|
if (!streamFile)
|
|
|
|
return NULL;
|
2008-01-31 07:04:26 +01:00
|
|
|
|
|
|
|
/* try a series of formats, see which works */
|
|
|
|
for (i=0;i<INIT_VGMSTREAM_FCNS;i++) {
|
2008-05-20 17:18:38 +02:00
|
|
|
VGMSTREAM * vgmstream = (init_vgmstream_fcns[i])(streamFile);
|
2008-01-31 07:04:26 +01:00
|
|
|
if (vgmstream) {
|
2008-03-25 08:30:04 +01:00
|
|
|
/* these are little hacky checks */
|
|
|
|
|
|
|
|
/* everything should have a reasonable sample rate
|
|
|
|
* (a verification of the metadata) */
|
2008-01-31 07:04:26 +01:00
|
|
|
if (!check_sample_rate(vgmstream->sample_rate)) {
|
|
|
|
close_vgmstream(vgmstream);
|
|
|
|
continue;
|
|
|
|
}
|
2008-03-25 08:30:04 +01:00
|
|
|
|
|
|
|
/* dual file stereo */
|
2008-05-17 23:52:40 +02:00
|
|
|
if (do_dfs && ((vgmstream->meta_type == meta_DSP_STD) || (vgmstream->meta_type == meta_PS2_VAGp)) && vgmstream->channels == 1) {
|
2008-05-20 17:18:38 +02:00
|
|
|
try_dual_file_stereo(vgmstream, streamFile);
|
2008-03-25 08:30:04 +01:00
|
|
|
}
|
|
|
|
|
2008-01-31 07:04:26 +01:00
|
|
|
/* save start things so we can restart for seeking */
|
2008-05-19 05:58:15 +02:00
|
|
|
/* copy the channels */
|
2008-01-31 07:04:26 +01:00
|
|
|
memcpy(vgmstream->start_ch,vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels);
|
2008-05-19 05:58:15 +02:00
|
|
|
/* copy the whole VGMSTREAM */
|
|
|
|
memcpy(vgmstream->start_vgmstream,vgmstream,sizeof(VGMSTREAM));
|
|
|
|
|
2008-01-31 07:04:26 +01:00
|
|
|
return vgmstream;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-05-20 17:18:38 +02:00
|
|
|
/* format detection and VGMSTREAM setup, uses default parameters */
|
|
|
|
VGMSTREAM * init_vgmstream(const char * const filename) {
|
|
|
|
VGMSTREAM *vgmstream = NULL;
|
|
|
|
STREAMFILE *streamFile = open_stdio_streamfile(filename);
|
|
|
|
if (streamFile) {
|
|
|
|
vgmstream = init_vgmstream_from_STREAMFILE(streamFile);
|
|
|
|
close_streamfile(streamFile);
|
|
|
|
}
|
|
|
|
return vgmstream;
|
|
|
|
}
|
|
|
|
|
|
|
|
VGMSTREAM * init_vgmstream_from_STREAMFILE(STREAMFILE *streamFile) {
|
|
|
|
return init_vgmstream_internal(streamFile,1);
|
|
|
|
}
|
|
|
|
|
2008-05-19 05:58:15 +02:00
|
|
|
/* Reset a VGMSTREAM to its state at the start of playback.
|
|
|
|
* Note that this does not reset the constituent STREAMFILES. */
|
|
|
|
void reset_vgmstream(VGMSTREAM * vgmstream) {
|
|
|
|
/* copy the vgmstream back into itself */
|
|
|
|
memcpy(vgmstream,vgmstream->start_vgmstream,sizeof(VGMSTREAM));
|
|
|
|
|
|
|
|
/* copy the initial channels */
|
|
|
|
memcpy(vgmstream->ch,vgmstream->start_ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels);
|
|
|
|
|
|
|
|
/* loop_ch is not zeroed here because there is a possibility of the
|
|
|
|
* init_vgmstream_* function doing something tricky and precomputing it.
|
|
|
|
* Otherwise hit_loop will be 0 and it will be copied over anyway when we
|
|
|
|
* really hit the loop start. */
|
2008-06-15 06:01:03 +02:00
|
|
|
|
|
|
|
#ifdef VGM_USE_VORBIS
|
|
|
|
if (vgmstream->meta_type==meta_ogg_vorbis) {
|
|
|
|
ogg_vorbis_codec_data *data =
|
|
|
|
(ogg_vorbis_codec_data *)(vgmstream->codec_data);
|
|
|
|
OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file);
|
|
|
|
|
|
|
|
ov_pcm_seek(ogg_vorbis_file, 0);
|
|
|
|
}
|
|
|
|
#endif
|
2008-05-19 05:58:15 +02:00
|
|
|
}
|
|
|
|
|
2008-01-31 07:04:26 +01:00
|
|
|
/* simply allocate memory for the VGMSTREAM and its channels */
|
|
|
|
VGMSTREAM * allocate_vgmstream(int channel_count, int looped) {
|
|
|
|
VGMSTREAM * vgmstream;
|
2008-05-19 05:58:15 +02:00
|
|
|
VGMSTREAM * start_vgmstream;
|
2008-01-31 07:04:26 +01:00
|
|
|
VGMSTREAMCHANNEL * channels;
|
|
|
|
VGMSTREAMCHANNEL * start_channels;
|
|
|
|
VGMSTREAMCHANNEL * loop_channels;
|
|
|
|
|
2008-04-02 19:50:50 +02:00
|
|
|
if (channel_count <= 0) return NULL;
|
|
|
|
|
2008-01-31 07:04:26 +01:00
|
|
|
vgmstream = calloc(1,sizeof(VGMSTREAM));
|
|
|
|
if (!vgmstream) return NULL;
|
|
|
|
|
2008-05-19 05:58:15 +02:00
|
|
|
start_vgmstream = calloc(1,sizeof(VGMSTREAM));
|
|
|
|
if (!start_vgmstream) {
|
|
|
|
free(vgmstream);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
vgmstream->start_vgmstream = start_vgmstream;
|
|
|
|
start_vgmstream->start_vgmstream = start_vgmstream;
|
|
|
|
|
2008-01-31 07:04:26 +01:00
|
|
|
channels = calloc(channel_count,sizeof(VGMSTREAMCHANNEL));
|
|
|
|
if (!channels) {
|
|
|
|
free(vgmstream);
|
2008-05-19 05:58:15 +02:00
|
|
|
free(start_vgmstream);
|
2008-01-31 07:04:26 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
vgmstream->ch = channels;
|
|
|
|
vgmstream->channels = channel_count;
|
|
|
|
|
|
|
|
start_channels = calloc(channel_count,sizeof(VGMSTREAMCHANNEL));
|
|
|
|
if (!start_channels) {
|
|
|
|
free(vgmstream);
|
2008-05-19 05:58:15 +02:00
|
|
|
free(start_vgmstream);
|
2008-01-31 07:04:26 +01:00
|
|
|
free(channels);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
vgmstream->start_ch = start_channels;
|
|
|
|
|
|
|
|
if (looped) {
|
|
|
|
loop_channels = calloc(channel_count,sizeof(VGMSTREAMCHANNEL));
|
|
|
|
if (!loop_channels) {
|
|
|
|
free(vgmstream);
|
2008-05-19 05:58:15 +02:00
|
|
|
free(start_vgmstream);
|
2008-01-31 07:04:26 +01:00
|
|
|
free(channels);
|
|
|
|
free(start_channels);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
vgmstream->loop_ch = loop_channels;
|
|
|
|
}
|
|
|
|
|
|
|
|
vgmstream->loop_flag = looped;
|
|
|
|
|
|
|
|
return vgmstream;
|
|
|
|
}
|
|
|
|
|
|
|
|
void close_vgmstream(VGMSTREAM * vgmstream) {
|
2008-05-20 22:19:46 +02:00
|
|
|
int i,j;
|
2008-01-31 07:04:26 +01:00
|
|
|
if (!vgmstream) return;
|
|
|
|
|
2008-05-20 22:19:46 +02:00
|
|
|
for (i=0;i<vgmstream->channels;i++) {
|
|
|
|
if (vgmstream->ch[i].streamfile) {
|
2008-01-31 07:04:26 +01:00
|
|
|
close_streamfile(vgmstream->ch[i].streamfile);
|
2008-05-20 22:19:46 +02:00
|
|
|
/* Multiple channels might have the same streamfile. Find the others
|
|
|
|
* that are the same as this and clear them so they won't be closed
|
|
|
|
* again. */
|
|
|
|
for (j=0;j<vgmstream->channels;j++) {
|
|
|
|
if (i!=j && vgmstream->ch[j].streamfile ==
|
|
|
|
vgmstream->ch[i].streamfile) {
|
|
|
|
vgmstream->ch[j].streamfile = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
vgmstream->ch[i].streamfile = NULL;
|
|
|
|
}
|
|
|
|
}
|
2008-01-31 07:04:26 +01:00
|
|
|
|
|
|
|
if (vgmstream->loop_ch) free(vgmstream->loop_ch);
|
|
|
|
if (vgmstream->start_ch) free(vgmstream->start_ch);
|
|
|
|
if (vgmstream->ch) free(vgmstream->ch);
|
2008-05-19 05:58:15 +02:00
|
|
|
/* the start_vgmstream is considered just data */
|
|
|
|
if (vgmstream->start_vgmstream) free(vgmstream->start_vgmstream);
|
2008-01-31 07:04:26 +01:00
|
|
|
|
2008-06-15 06:01:03 +02:00
|
|
|
#ifdef VGM_USE_VORBIS
|
|
|
|
if (vgmstream->meta_type==meta_ogg_vorbis) {
|
|
|
|
ogg_vorbis_codec_data *data =
|
|
|
|
(ogg_vorbis_codec_data *)(vgmstream->codec_data);
|
|
|
|
if (vgmstream->codec_data) {
|
|
|
|
OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file);
|
|
|
|
|
|
|
|
|
|
|
|
ov_clear(ogg_vorbis_file);
|
|
|
|
|
|
|
|
close_streamfile(data->ov_streamfile.streamfile);
|
|
|
|
free(vgmstream->codec_data);
|
|
|
|
vgmstream->codec_data = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-01-31 07:04:26 +01:00
|
|
|
free(vgmstream);
|
|
|
|
}
|
|
|
|
|
2008-05-16 22:28:36 +02:00
|
|
|
int32_t get_vgmstream_play_samples(double looptimes, double fadeseconds, double fadedelayseconds, VGMSTREAM * vgmstream) {
|
2008-01-31 07:04:26 +01:00
|
|
|
if (vgmstream->loop_flag) {
|
2008-05-16 22:28:36 +02:00
|
|
|
return vgmstream->loop_start_sample+(vgmstream->loop_end_sample-vgmstream->loop_start_sample)*looptimes+(fadedelayseconds+fadeseconds)*vgmstream->sample_rate;
|
2008-01-31 07:04:26 +01:00
|
|
|
} else return vgmstream->num_samples;
|
|
|
|
}
|
|
|
|
|
|
|
|
void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
|
|
|
switch (vgmstream->layout_type) {
|
|
|
|
case layout_interleave:
|
2008-02-04 16:20:20 +01:00
|
|
|
case layout_interleave_shortblock:
|
2008-01-31 07:04:26 +01:00
|
|
|
render_vgmstream_interleave(buffer,sample_count,vgmstream);
|
|
|
|
break;
|
2008-06-15 09:59:43 +02:00
|
|
|
#ifdef VGM_USE_VORBIS
|
2008-06-15 06:01:03 +02:00
|
|
|
case layout_ogg_vorbis:
|
2008-06-15 09:59:43 +02:00
|
|
|
#endif
|
2008-02-13 15:31:21 +01:00
|
|
|
case layout_dtk_interleave:
|
2008-02-05 01:03:39 +01:00
|
|
|
case layout_none:
|
|
|
|
render_vgmstream_nolayout(buffer,sample_count,vgmstream);
|
|
|
|
break;
|
2008-03-04 01:46:55 +01:00
|
|
|
case layout_ast_blocked:
|
2008-03-04 08:15:25 +01:00
|
|
|
case layout_halpst_blocked:
|
2008-05-10 21:59:29 +02:00
|
|
|
case layout_xa_blocked:
|
2008-06-02 19:58:08 +02:00
|
|
|
case layout_ea_blocked:
|
2008-06-03 20:41:26 +02:00
|
|
|
case layout_caf_blocked:
|
2008-06-29 03:30:13 +02:00
|
|
|
case layout_wsi_blocked:
|
2008-07-02 15:39:51 +02:00
|
|
|
case layout_str_snds_blocked:
|
2008-03-04 08:15:25 +01:00
|
|
|
render_vgmstream_blocked(buffer,sample_count,vgmstream);
|
2008-03-04 01:46:55 +01:00
|
|
|
break;
|
2008-01-31 07:04:26 +01:00
|
|
|
}
|
|
|
|
}
|
2008-02-05 03:17:35 +01:00
|
|
|
|
|
|
|
int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
|
|
|
switch (vgmstream->coding_type) {
|
|
|
|
case coding_CRI_ADX:
|
|
|
|
return 32;
|
|
|
|
case coding_NGC_DSP:
|
|
|
|
return 14;
|
|
|
|
case coding_PCM16LE:
|
|
|
|
case coding_PCM16BE:
|
|
|
|
case coding_PCM8:
|
2008-06-15 09:59:43 +02:00
|
|
|
#ifdef VGM_USE_VORBIS
|
2008-06-15 06:01:03 +02:00
|
|
|
case coding_ogg_vorbis:
|
2008-06-15 09:59:43 +02:00
|
|
|
#endif
|
2008-07-01 05:23:44 +02:00
|
|
|
case coding_SDX2:
|
2008-02-05 03:17:35 +01:00
|
|
|
return 1;
|
2008-02-05 10:21:20 +01:00
|
|
|
case coding_NDS_IMA:
|
|
|
|
return (vgmstream->interleave_block_size-4)*2;
|
2008-02-13 15:31:21 +01:00
|
|
|
case coding_NGC_DTK:
|
|
|
|
return 28;
|
2008-02-14 23:10:08 +01:00
|
|
|
case coding_G721:
|
2008-07-02 03:41:20 +02:00
|
|
|
case coding_DVI_IMA:
|
2008-02-14 23:10:08 +01:00
|
|
|
return 1;
|
2008-03-03 22:38:11 +01:00
|
|
|
case coding_NGC_AFC:
|
|
|
|
return 16;
|
2008-05-05 00:10:30 +02:00
|
|
|
case coding_PSX:
|
2008-06-25 22:39:15 +02:00
|
|
|
case coding_invert_PSX:
|
2008-05-10 21:59:29 +02:00
|
|
|
case coding_XA:
|
2008-05-05 00:10:30 +02:00
|
|
|
return 28;
|
2008-05-24 00:52:02 +02:00
|
|
|
case coding_XBOX:
|
|
|
|
return 64;
|
2008-06-02 19:58:08 +02:00
|
|
|
case coding_EAXA:
|
|
|
|
return 28;
|
2008-02-05 03:17:35 +01:00
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-05 10:21:20 +01:00
|
|
|
int get_vgmstream_samples_per_shortframe(VGMSTREAM * vgmstream) {
|
|
|
|
switch (vgmstream->coding_type) {
|
|
|
|
case coding_NDS_IMA:
|
|
|
|
return (vgmstream->interleave_smallblock_size-4)*2;
|
|
|
|
default:
|
|
|
|
return get_vgmstream_samples_per_frame(vgmstream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-05 03:17:35 +01:00
|
|
|
int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
|
|
|
switch (vgmstream->coding_type) {
|
|
|
|
case coding_CRI_ADX:
|
|
|
|
return 18;
|
|
|
|
case coding_NGC_DSP:
|
|
|
|
return 8;
|
|
|
|
case coding_PCM16LE:
|
|
|
|
case coding_PCM16BE:
|
|
|
|
return 2;
|
|
|
|
case coding_PCM8:
|
2008-07-01 05:23:44 +02:00
|
|
|
case coding_SDX2:
|
2008-02-05 03:17:35 +01:00
|
|
|
return 1;
|
2008-02-05 10:21:20 +01:00
|
|
|
case coding_NDS_IMA:
|
|
|
|
return vgmstream->interleave_block_size;
|
2008-02-13 15:31:21 +01:00
|
|
|
case coding_NGC_DTK:
|
|
|
|
return 32;
|
2008-07-02 03:41:20 +02:00
|
|
|
case coding_DVI_IMA:
|
2008-02-14 23:10:08 +01:00
|
|
|
case coding_G721:
|
|
|
|
return 0;
|
2008-03-03 22:38:11 +01:00
|
|
|
case coding_NGC_AFC:
|
|
|
|
return 9;
|
2008-05-05 00:10:30 +02:00
|
|
|
case coding_PSX:
|
2008-06-25 22:39:15 +02:00
|
|
|
case coding_invert_PSX:
|
2008-05-05 00:10:30 +02:00
|
|
|
return 16;
|
2008-05-10 21:59:29 +02:00
|
|
|
case coding_XA:
|
2008-05-11 20:11:55 +02:00
|
|
|
return 14*vgmstream->channels;
|
2008-05-24 00:52:02 +02:00
|
|
|
case coding_XBOX:
|
2008-06-10 03:20:54 +02:00
|
|
|
return 36;
|
2008-06-02 19:58:08 +02:00
|
|
|
case coding_EAXA:
|
|
|
|
return 1; // the frame is variant in size
|
2008-02-05 03:17:35 +01:00
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-05 10:21:20 +01:00
|
|
|
int get_vgmstream_shortframe_size(VGMSTREAM * vgmstream) {
|
|
|
|
switch (vgmstream->coding_type) {
|
|
|
|
case coding_NDS_IMA:
|
|
|
|
return vgmstream->interleave_smallblock_size;
|
|
|
|
default:
|
|
|
|
return get_vgmstream_frame_size(vgmstream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-05 03:17:35 +01:00
|
|
|
void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to_do, sample * buffer) {
|
|
|
|
int chan;
|
|
|
|
|
|
|
|
switch (vgmstream->coding_type) {
|
|
|
|
case coding_CRI_ADX:
|
|
|
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
|
|
|
decode_adx(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
|
|
|
vgmstream->channels,vgmstream->samples_into_block,
|
|
|
|
samples_to_do);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case coding_NGC_DSP:
|
|
|
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
2008-03-03 22:38:11 +01:00
|
|
|
decode_ngc_dsp(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
2008-02-05 03:17:35 +01:00
|
|
|
vgmstream->channels,vgmstream->samples_into_block,
|
|
|
|
samples_to_do);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case coding_PCM16LE:
|
|
|
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
|
|
|
decode_pcm16LE(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
|
|
|
vgmstream->channels,vgmstream->samples_into_block,
|
|
|
|
samples_to_do);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case coding_PCM16BE:
|
|
|
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
|
|
|
decode_pcm16BE(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
|
|
|
vgmstream->channels,vgmstream->samples_into_block,
|
|
|
|
samples_to_do);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case coding_PCM8:
|
|
|
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
|
|
|
decode_pcm8(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
|
|
|
vgmstream->channels,vgmstream->samples_into_block,
|
|
|
|
samples_to_do);
|
|
|
|
}
|
|
|
|
break;
|
2008-02-05 10:21:20 +01:00
|
|
|
case coding_NDS_IMA:
|
|
|
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
|
|
|
decode_nds_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
|
|
|
vgmstream->channels,vgmstream->samples_into_block,
|
|
|
|
samples_to_do);
|
|
|
|
}
|
2008-05-24 00:52:02 +02:00
|
|
|
break;
|
|
|
|
case coding_XBOX:
|
|
|
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
|
|
|
decode_xbox_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
|
|
|
vgmstream->channels,vgmstream->samples_into_block,
|
|
|
|
samples_to_do,chan);
|
|
|
|
}
|
2008-02-05 10:21:20 +01:00
|
|
|
break;
|
2008-02-13 15:31:21 +01:00
|
|
|
case coding_NGC_DTK:
|
|
|
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
|
|
|
decode_ngc_dtk(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
|
|
|
vgmstream->channels,vgmstream->samples_into_block,
|
|
|
|
samples_to_do,chan);
|
|
|
|
}
|
|
|
|
break;
|
2008-02-14 23:10:08 +01:00
|
|
|
case coding_G721:
|
|
|
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
|
|
|
decode_g721(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
|
|
|
vgmstream->channels,vgmstream->samples_into_block,
|
|
|
|
samples_to_do);
|
|
|
|
}
|
|
|
|
break;
|
2008-03-03 22:38:11 +01:00
|
|
|
case coding_NGC_AFC:
|
|
|
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
|
|
|
decode_ngc_afc(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
|
|
|
vgmstream->channels,vgmstream->samples_into_block,
|
|
|
|
samples_to_do);
|
|
|
|
}
|
|
|
|
break;
|
2008-05-04 22:36:40 +02:00
|
|
|
case coding_PSX:
|
|
|
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
|
|
|
decode_psx(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
|
|
|
vgmstream->channels,vgmstream->samples_into_block,
|
|
|
|
samples_to_do);
|
|
|
|
}
|
2008-06-25 22:39:15 +02:00
|
|
|
break;
|
|
|
|
case coding_invert_PSX:
|
|
|
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
|
|
|
decode_invert_psx(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
|
|
|
vgmstream->channels,vgmstream->samples_into_block,
|
|
|
|
samples_to_do);
|
|
|
|
}
|
2008-05-04 22:36:40 +02:00
|
|
|
break;
|
2008-05-10 21:59:29 +02:00
|
|
|
case coding_XA:
|
|
|
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
|
|
|
decode_xa(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
|
|
|
vgmstream->channels,vgmstream->samples_into_block,
|
|
|
|
samples_to_do);
|
|
|
|
}
|
|
|
|
break;
|
2008-06-02 19:58:08 +02:00
|
|
|
case coding_EAXA:
|
|
|
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
|
|
|
decode_eaxa(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
|
|
|
vgmstream->channels,vgmstream->samples_into_block,
|
|
|
|
samples_to_do,chan);
|
|
|
|
}
|
|
|
|
break;
|
2008-06-15 06:01:03 +02:00
|
|
|
#ifdef VGM_USE_VORBIS
|
|
|
|
case coding_ogg_vorbis:
|
|
|
|
decode_ogg_vorbis(vgmstream->codec_data,
|
|
|
|
buffer+samples_written*vgmstream->channels,samples_to_do,
|
|
|
|
vgmstream->channels);
|
|
|
|
break;
|
|
|
|
#endif
|
2008-07-01 05:23:44 +02:00
|
|
|
case coding_SDX2:
|
|
|
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
|
|
|
decode_sdx2(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
|
|
|
vgmstream->channels,vgmstream->samples_into_block,
|
|
|
|
samples_to_do);
|
|
|
|
}
|
|
|
|
break;
|
2008-07-02 03:41:20 +02:00
|
|
|
case coding_DVI_IMA:
|
|
|
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
|
|
|
decode_dvi_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
|
|
|
vgmstream->channels,vgmstream->samples_into_block,
|
|
|
|
samples_to_do);
|
|
|
|
}
|
|
|
|
break;
|
2008-02-05 03:17:35 +01:00
|
|
|
}
|
|
|
|
}
|
2008-02-05 07:21:57 +01:00
|
|
|
|
|
|
|
int vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMSTREAM * vgmstream) {
|
|
|
|
int samples_to_do;
|
|
|
|
int samples_left_this_block;
|
|
|
|
|
|
|
|
samples_left_this_block = samples_this_block - vgmstream->samples_into_block;
|
|
|
|
samples_to_do = samples_left_this_block;
|
|
|
|
|
|
|
|
/* fun loopy crap */
|
|
|
|
/* Why did I think this would be any simpler? */
|
|
|
|
if (vgmstream->loop_flag) {
|
|
|
|
/* are we going to hit the loop end during this block? */
|
|
|
|
if (vgmstream->current_sample+samples_left_this_block > vgmstream->loop_end_sample) {
|
|
|
|
/* only do to just before it */
|
|
|
|
samples_to_do = vgmstream->loop_end_sample-vgmstream->current_sample;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* are we going to hit the loop start during this block? */
|
|
|
|
if (!vgmstream->hit_loop && vgmstream->current_sample+samples_left_this_block > vgmstream->loop_start_sample) {
|
|
|
|
/* only do to just before it */
|
|
|
|
samples_to_do = vgmstream->loop_start_sample-vgmstream->current_sample;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if it's a framed encoding don't do more than one frame */
|
|
|
|
if (samples_per_frame>1 && (vgmstream->samples_into_block%samples_per_frame)+samples_to_do>samples_per_frame) samples_to_do=samples_per_frame-(vgmstream->samples_into_block%samples_per_frame);
|
|
|
|
|
|
|
|
return samples_to_do;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return 1 if we just looped */
|
|
|
|
int vgmstream_do_loop(VGMSTREAM * vgmstream) {
|
|
|
|
/* if (vgmstream->loop_flag) {*/
|
|
|
|
/* is this the loop end? */
|
|
|
|
if (vgmstream->current_sample==vgmstream->loop_end_sample) {
|
2008-04-02 18:11:53 +02:00
|
|
|
/* against everything I hold sacred, preserve adpcm
|
|
|
|
* history through loop for certain types */
|
2008-03-31 22:17:07 +02:00
|
|
|
if (vgmstream->meta_type == meta_DSP_STD ||
|
2008-04-02 18:11:53 +02:00
|
|
|
vgmstream->meta_type == meta_DSP_RS03 ||
|
2008-05-06 00:45:21 +02:00
|
|
|
vgmstream->meta_type == meta_DSP_CSTR ||
|
2008-06-25 22:39:15 +02:00
|
|
|
vgmstream->coding_type == coding_PSX ||
|
|
|
|
vgmstream->coding_type == coding_invert_PSX) {
|
2008-03-31 22:17:07 +02:00
|
|
|
int i;
|
|
|
|
for (i=0;i<vgmstream->channels;i++) {
|
|
|
|
vgmstream->loop_ch[i].adpcm_history1_16 = vgmstream->ch[i].adpcm_history1_16;
|
|
|
|
vgmstream->loop_ch[i].adpcm_history2_16 = vgmstream->ch[i].adpcm_history2_16;
|
2008-05-11 20:11:55 +02:00
|
|
|
vgmstream->loop_ch[i].adpcm_history1_32 = vgmstream->ch[i].adpcm_history1_32;
|
|
|
|
vgmstream->loop_ch[i].adpcm_history2_32 = vgmstream->ch[i].adpcm_history2_32;
|
2008-03-31 22:17:07 +02:00
|
|
|
}
|
2008-03-25 08:30:04 +01:00
|
|
|
}
|
2008-05-17 00:52:31 +02:00
|
|
|
#ifdef DEBUG
|
2008-04-02 18:11:53 +02:00
|
|
|
{
|
2008-03-31 22:17:07 +02:00
|
|
|
int i;
|
|
|
|
for (i=0;i<vgmstream->channels;i++) {
|
2008-04-02 18:11:53 +02:00
|
|
|
fprintf(stderr,"ch%d hist: %04x %04x loop hist: %04x %04x\n",i,
|
|
|
|
vgmstream->ch[i].adpcm_history1_16,vgmstream->ch[i].adpcm_history2_16,
|
|
|
|
vgmstream->loop_ch[i].adpcm_history1_16,vgmstream->loop_ch[i].adpcm_history2_16);
|
|
|
|
fprintf(stderr,"ch%d offset: %x loop offset: %x\n",i,
|
|
|
|
vgmstream->ch[i].offset,
|
|
|
|
vgmstream->loop_ch[i].offset);
|
2008-03-31 22:17:07 +02:00
|
|
|
}
|
2008-04-02 18:11:53 +02:00
|
|
|
}
|
|
|
|
#endif
|
2008-06-15 06:01:03 +02:00
|
|
|
|
|
|
|
#ifdef VGM_USE_VORBIS
|
|
|
|
if (vgmstream->meta_type==meta_ogg_vorbis) {
|
|
|
|
ogg_vorbis_codec_data *data =
|
|
|
|
(ogg_vorbis_codec_data *)(vgmstream->codec_data);
|
|
|
|
OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file);
|
|
|
|
|
|
|
|
ov_pcm_seek_lap(ogg_vorbis_file, vgmstream->loop_sample);
|
|
|
|
}
|
|
|
|
#endif
|
2008-02-05 07:21:57 +01:00
|
|
|
/* restore! */
|
|
|
|
memcpy(vgmstream->ch,vgmstream->loop_ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels);
|
|
|
|
vgmstream->current_sample=vgmstream->loop_sample;
|
|
|
|
vgmstream->samples_into_block=vgmstream->loop_samples_into_block;
|
2008-03-04 01:46:55 +01:00
|
|
|
vgmstream->current_block_size=vgmstream->loop_block_size;
|
|
|
|
vgmstream->current_block_offset=vgmstream->loop_block_offset;
|
|
|
|
vgmstream->next_block_offset=vgmstream->loop_next_block_offset;
|
2008-02-05 07:21:57 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* is this the loop start? */
|
|
|
|
if (!vgmstream->hit_loop && vgmstream->current_sample==vgmstream->loop_start_sample) {
|
|
|
|
/* save! */
|
|
|
|
memcpy(vgmstream->loop_ch,vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels);
|
|
|
|
|
|
|
|
vgmstream->loop_sample=vgmstream->current_sample;
|
|
|
|
vgmstream->loop_samples_into_block=vgmstream->samples_into_block;
|
2008-03-04 01:46:55 +01:00
|
|
|
vgmstream->loop_block_size=vgmstream->current_block_size;
|
|
|
|
vgmstream->loop_block_offset=vgmstream->current_block_offset;
|
|
|
|
vgmstream->loop_next_block_offset=vgmstream->next_block_offset;
|
2008-02-05 07:21:57 +01:00
|
|
|
vgmstream->hit_loop=1;
|
|
|
|
}
|
2008-03-31 22:17:07 +02:00
|
|
|
/*}*/
|
|
|
|
return 0;
|
2008-02-05 07:21:57 +01:00
|
|
|
}
|
2008-02-05 07:44:44 +01:00
|
|
|
|
2008-03-11 02:27:59 +01:00
|
|
|
/* build a descriptive string */
|
|
|
|
void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
|
|
|
#define TEMPSIZE 256
|
|
|
|
char temp[TEMPSIZE];
|
|
|
|
|
2008-02-05 07:44:44 +01:00
|
|
|
if (!vgmstream) {
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"NULL VGMSTREAM");
|
|
|
|
concatn(length,desc,temp);
|
2008-02-05 07:44:44 +01:00
|
|
|
return;
|
|
|
|
}
|
2008-03-11 02:27:59 +01:00
|
|
|
|
|
|
|
snprintf(temp,TEMPSIZE,"sample rate %d Hz\n"
|
|
|
|
"channels: %d\n",
|
|
|
|
vgmstream->sample_rate,vgmstream->channels);
|
|
|
|
concatn(length,desc,temp);
|
|
|
|
|
2008-02-05 07:44:44 +01:00
|
|
|
if (vgmstream->loop_flag) {
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"loop start: %d samples (%.2lf seconds)\n"
|
|
|
|
"loop end: %d samples (%.2lf seconds)\n",
|
|
|
|
vgmstream->loop_start_sample,
|
|
|
|
(double)vgmstream->loop_start_sample/vgmstream->sample_rate,
|
|
|
|
vgmstream->loop_end_sample,
|
|
|
|
(double)vgmstream->loop_end_sample/vgmstream->sample_rate);
|
|
|
|
concatn(length,desc,temp);
|
2008-02-05 07:44:44 +01:00
|
|
|
}
|
|
|
|
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"stream total samples: %d (%.2lf seconds)\n",
|
|
|
|
vgmstream->num_samples,
|
|
|
|
(double)vgmstream->num_samples/vgmstream->sample_rate);
|
|
|
|
concatn(length,desc,temp);
|
|
|
|
|
|
|
|
snprintf(temp,TEMPSIZE,"encoding: ");
|
|
|
|
concatn(length,desc,temp);
|
|
|
|
|
2008-02-05 07:44:44 +01:00
|
|
|
switch (vgmstream->coding_type) {
|
|
|
|
case coding_PCM16BE:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"Big Endian 16-bit PCM");
|
2008-02-05 07:44:44 +01:00
|
|
|
break;
|
|
|
|
case coding_PCM16LE:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"Little Endian 16-bit PCM");
|
2008-02-05 07:44:44 +01:00
|
|
|
break;
|
|
|
|
case coding_PCM8:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"8-bit PCM");
|
2008-02-05 07:44:44 +01:00
|
|
|
break;
|
|
|
|
case coding_NGC_DSP:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"Gamecube \"DSP\" 4-bit ADPCM");
|
2008-02-05 07:44:44 +01:00
|
|
|
break;
|
|
|
|
case coding_CRI_ADX:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"CRI ADX 4-bit ADPCM");
|
2008-02-05 07:44:44 +01:00
|
|
|
break;
|
2008-02-05 10:21:20 +01:00
|
|
|
case coding_NDS_IMA:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"NDS-style 4-bit IMA ADPCM");
|
2008-02-05 10:21:20 +01:00
|
|
|
break;
|
2008-02-13 15:31:21 +01:00
|
|
|
case coding_NGC_DTK:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"Gamecube \"ADP\"/\"DTK\" 4-bit ADPCM");
|
2008-02-14 23:10:08 +01:00
|
|
|
break;
|
|
|
|
case coding_G721:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"CCITT G.721 4-bit ADPCM");
|
2008-02-13 15:31:21 +01:00
|
|
|
break;
|
2008-03-03 22:38:11 +01:00
|
|
|
case coding_NGC_AFC:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"Gamecube \"AFC\" 4-bit ADPCM");
|
2008-03-03 22:38:11 +01:00
|
|
|
break;
|
2008-05-04 22:36:40 +02:00
|
|
|
case coding_PSX:
|
|
|
|
snprintf(temp,TEMPSIZE,"Playstation 4-bit ADPCM");
|
|
|
|
break;
|
2008-06-25 22:39:15 +02:00
|
|
|
case coding_invert_PSX:
|
|
|
|
snprintf(temp,TEMPSIZE,"Inverted (?) Playstation 4-bit ADPCM");
|
|
|
|
break;
|
2008-05-11 03:49:52 +02:00
|
|
|
case coding_XA:
|
|
|
|
snprintf(temp,TEMPSIZE,"CD-ROM XA 4-bit ADPCM");
|
2008-05-24 00:52:02 +02:00
|
|
|
break;
|
|
|
|
case coding_XBOX:
|
|
|
|
snprintf(temp,TEMPSIZE,"XBOX 4-bit IMA ADPCM");
|
2008-06-02 19:58:08 +02:00
|
|
|
break;
|
|
|
|
case coding_EAXA:
|
|
|
|
snprintf(temp,TEMPSIZE,"Electronic Arts XA Based 4-bit ADPCM");
|
2008-05-11 03:49:52 +02:00
|
|
|
break;
|
2008-06-15 09:59:43 +02:00
|
|
|
#ifdef VGM_USE_VORBIS
|
2008-06-15 08:04:44 +02:00
|
|
|
case coding_ogg_vorbis:
|
|
|
|
snprintf(temp,TEMPSIZE,"Vorbis");
|
|
|
|
break;
|
2008-06-15 09:59:43 +02:00
|
|
|
#endif
|
2008-07-01 05:23:44 +02:00
|
|
|
case coding_SDX2:
|
|
|
|
snprintf(temp,TEMPSIZE,"Squareroot-delta-exact (SDX2) 8-bit DPCM");
|
|
|
|
break;
|
2008-07-02 03:41:20 +02:00
|
|
|
case coding_DVI_IMA:
|
|
|
|
snprintf(temp,TEMPSIZE,"Intel DVI 4-bit IMA ADPCM");
|
|
|
|
break;
|
2008-02-05 07:44:44 +01:00
|
|
|
default:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"CANNOT DECODE");
|
2008-02-05 07:44:44 +01:00
|
|
|
}
|
2008-03-11 02:27:59 +01:00
|
|
|
concatn(length,desc,temp);
|
|
|
|
|
|
|
|
snprintf(temp,TEMPSIZE,"\nlayout: ");
|
|
|
|
concatn(length,desc,temp);
|
2008-02-05 07:44:44 +01:00
|
|
|
|
|
|
|
switch (vgmstream->layout_type) {
|
|
|
|
case layout_none:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"flat (no layout)");
|
2008-02-05 07:44:44 +01:00
|
|
|
break;
|
|
|
|
case layout_interleave:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"interleave");
|
2008-02-05 07:44:44 +01:00
|
|
|
break;
|
|
|
|
case layout_interleave_shortblock:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"interleave with short last block");
|
2008-02-05 07:44:44 +01:00
|
|
|
break;
|
2008-02-13 15:31:21 +01:00
|
|
|
case layout_dtk_interleave:
|
2008-04-02 18:11:53 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"ADP/DTK nibble interleave");
|
2008-02-13 15:31:21 +01:00
|
|
|
break;
|
2008-03-04 01:46:55 +01:00
|
|
|
case layout_ast_blocked:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"AST blocked");
|
2008-03-04 01:46:55 +01:00
|
|
|
break;
|
2008-03-04 08:15:25 +01:00
|
|
|
case layout_halpst_blocked:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"HALPST blocked");
|
2008-05-10 21:59:29 +02:00
|
|
|
break;
|
|
|
|
case layout_xa_blocked:
|
2008-05-11 03:49:52 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"CD-ROM XA");
|
2008-06-02 19:58:08 +02:00
|
|
|
break;
|
|
|
|
case layout_ea_blocked:
|
|
|
|
snprintf(temp,TEMPSIZE,"Electronic Arts Audio Blocks");
|
2008-06-03 20:41:26 +02:00
|
|
|
break;
|
|
|
|
case layout_caf_blocked:
|
|
|
|
snprintf(temp,TEMPSIZE,"CAF blocked");
|
2008-03-04 08:15:25 +01:00
|
|
|
break;
|
2008-06-29 03:30:13 +02:00
|
|
|
case layout_wsi_blocked:
|
|
|
|
snprintf(temp,TEMPSIZE,".wsi blocked");
|
|
|
|
break;
|
2008-06-15 09:59:43 +02:00
|
|
|
#ifdef VGM_USE_VORBIS
|
2008-06-15 08:04:44 +02:00
|
|
|
case layout_ogg_vorbis:
|
|
|
|
snprintf(temp,TEMPSIZE,"Ogg");
|
|
|
|
break;
|
2008-06-15 09:59:43 +02:00
|
|
|
#endif
|
2008-07-02 15:39:51 +02:00
|
|
|
case layout_str_snds_blocked:
|
|
|
|
snprintf(temp,TEMPSIZE,".str SNDS blocked");
|
2008-07-02 05:57:21 +02:00
|
|
|
break;
|
2008-02-05 07:44:44 +01:00
|
|
|
default:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"INCONCEIVABLE");
|
2008-02-05 07:44:44 +01:00
|
|
|
}
|
2008-03-11 02:27:59 +01:00
|
|
|
concatn(length,desc,temp);
|
|
|
|
|
|
|
|
snprintf(temp,TEMPSIZE,"\n");
|
|
|
|
concatn(length,desc,temp);
|
2008-02-05 07:44:44 +01:00
|
|
|
|
|
|
|
if (vgmstream->layout_type == layout_interleave || vgmstream->layout_type == layout_interleave_shortblock) {
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"interleave: %#x bytes\n",
|
2008-05-18 19:17:49 +02:00
|
|
|
(int32_t)vgmstream->interleave_block_size);
|
2008-03-11 02:27:59 +01:00
|
|
|
concatn(length,desc,temp);
|
|
|
|
|
2008-02-05 07:44:44 +01:00
|
|
|
if (vgmstream->layout_type == layout_interleave_shortblock) {
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"last block interleave: %#x bytes\n",
|
2008-05-18 19:17:49 +02:00
|
|
|
(int32_t)vgmstream->interleave_smallblock_size);
|
2008-03-11 02:27:59 +01:00
|
|
|
concatn(length,desc,temp);
|
2008-02-05 07:44:44 +01:00
|
|
|
}
|
|
|
|
}
|
2008-03-03 22:38:11 +01:00
|
|
|
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"metadata from: ");
|
|
|
|
concatn(length,desc,temp);
|
|
|
|
|
2008-03-03 22:38:11 +01:00
|
|
|
switch (vgmstream->meta_type) {
|
|
|
|
case meta_RSTM:
|
2008-04-02 18:11:53 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"Nintendo RSTM header");
|
2008-03-03 22:38:11 +01:00
|
|
|
break;
|
|
|
|
case meta_STRM:
|
2008-04-02 18:11:53 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"Nintendo STRM header");
|
2008-03-03 22:38:11 +01:00
|
|
|
break;
|
|
|
|
case meta_ADX_03:
|
2008-04-02 18:11:53 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"CRI ADX header type 03");
|
2008-03-03 22:38:11 +01:00
|
|
|
break;
|
|
|
|
case meta_ADX_04:
|
2008-04-02 18:11:53 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"CRI ADX header type 04");
|
2008-03-03 22:38:11 +01:00
|
|
|
break;
|
2008-05-03 21:45:19 +02:00
|
|
|
case meta_ADX_05:
|
|
|
|
snprintf(temp,TEMPSIZE,"CRI ADX header type 05");
|
|
|
|
break;
|
2008-03-03 22:38:11 +01:00
|
|
|
case meta_DSP_AGSC:
|
2008-04-02 18:11:53 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"Retro Studios AGSC header");
|
2008-03-03 22:38:11 +01:00
|
|
|
break;
|
|
|
|
case meta_NGC_ADPDTK:
|
2008-04-02 18:11:53 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"assumed Nintendo ADP by .adp extension and valid first frame");
|
2008-03-03 22:38:11 +01:00
|
|
|
break;
|
|
|
|
case meta_RSF:
|
2008-04-02 18:11:53 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"assumed Retro Studios RSF by .rsf extension and valid first bytes");
|
2008-03-03 22:38:11 +01:00
|
|
|
break;
|
|
|
|
case meta_AFC:
|
2008-04-02 18:11:53 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"Nintendo AFC header");
|
2008-03-03 22:38:11 +01:00
|
|
|
break;
|
2008-03-04 01:46:55 +01:00
|
|
|
case meta_AST:
|
2008-04-02 18:11:53 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"Nintendo AST header");
|
2008-03-04 01:46:55 +01:00
|
|
|
break;
|
2008-03-04 08:15:25 +01:00
|
|
|
case meta_HALPST:
|
2008-04-02 18:11:53 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"HAL Laboratory HALPST header");
|
2008-03-04 08:15:25 +01:00
|
|
|
break;
|
2008-03-25 08:30:04 +01:00
|
|
|
case meta_DSP_RS03:
|
|
|
|
snprintf(temp,TEMPSIZE,"Retro Studios RS03 header");
|
|
|
|
break;
|
|
|
|
case meta_DSP_STD:
|
2008-04-02 18:11:53 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"Standard Nintendo DSP header");
|
|
|
|
break;
|
|
|
|
case meta_DSP_CSTR:
|
|
|
|
snprintf(temp,TEMPSIZE,"Namco Cstr header");
|
2008-03-25 08:30:04 +01:00
|
|
|
break;
|
2008-04-02 19:50:50 +02:00
|
|
|
case meta_GCSW:
|
|
|
|
snprintf(temp,TEMPSIZE,"GCSW header");
|
|
|
|
break;
|
2008-05-04 22:36:40 +02:00
|
|
|
case meta_PS2_SShd:
|
2008-05-13 22:03:51 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"SShd header");
|
2008-05-06 00:45:21 +02:00
|
|
|
break;
|
|
|
|
case meta_PS2_NPSF:
|
2008-05-13 22:03:51 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"Namco Production Sound File (NPSF) header");
|
2008-05-04 22:36:40 +02:00
|
|
|
break;
|
2008-05-06 03:01:06 +02:00
|
|
|
case meta_RWSD:
|
|
|
|
snprintf(temp,TEMPSIZE,"Nintendo RWSD header (single stream)");
|
|
|
|
break;
|
2008-05-10 21:59:29 +02:00
|
|
|
case meta_PSX_XA:
|
2008-05-13 22:03:51 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"RIFF/CDXA header");
|
2008-05-11 20:11:55 +02:00
|
|
|
break;
|
|
|
|
case meta_PS2_RXW:
|
2008-05-13 22:03:51 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"RXWS header)");
|
2008-05-11 23:27:10 +02:00
|
|
|
break;
|
|
|
|
case meta_PS2_RAW:
|
2008-05-12 15:31:48 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"assumed RAW Interleaved PCM by .int extension");
|
|
|
|
break;
|
|
|
|
case meta_DSP_STM:
|
|
|
|
snprintf(temp,TEMPSIZE,"Nintendo STM header");
|
2008-05-10 21:59:29 +02:00
|
|
|
break;
|
2008-05-13 13:47:51 +02:00
|
|
|
case meta_PS2_EXST:
|
2008-05-13 22:03:51 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"EXST header");
|
2008-05-13 13:47:51 +02:00
|
|
|
break;
|
2008-05-13 21:53:31 +02:00
|
|
|
case meta_PS2_SVAG:
|
2008-05-13 22:03:51 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"Konami SVAG header");
|
2008-05-13 21:53:31 +02:00
|
|
|
break;
|
2008-05-14 22:44:19 +02:00
|
|
|
case meta_PS2_MIB:
|
|
|
|
snprintf(temp,TEMPSIZE,"assumed MIB Interleaved file by .mib extension");
|
|
|
|
break;
|
|
|
|
case meta_PS2_MIB_MIH:
|
|
|
|
snprintf(temp,TEMPSIZE,"assumed MIB with MIH Info Header file by .mib+.mih extension");
|
|
|
|
break;
|
2008-05-15 00:26:44 +02:00
|
|
|
case meta_DSP_MPDSP:
|
|
|
|
snprintf(temp,TEMPSIZE,"Single DSP header stereo by .mpdsp extension");
|
|
|
|
break;
|
2008-05-15 20:57:03 +02:00
|
|
|
case meta_PS2_MIC:
|
|
|
|
snprintf(temp,TEMPSIZE,"assume KOEI MIC file by .mic extension");
|
|
|
|
break;
|
2008-05-16 00:06:33 +02:00
|
|
|
case meta_DSP_JETTERS:
|
|
|
|
snprintf(temp,TEMPSIZE,"Double DSP header stereo by _lr.dsp extension");
|
|
|
|
break;
|
|
|
|
case meta_DSP_MSS:
|
|
|
|
snprintf(temp,TEMPSIZE,"Double DSP header stereo by .mss extension");
|
|
|
|
break;
|
|
|
|
case meta_DSP_GCM:
|
|
|
|
snprintf(temp,TEMPSIZE,"Double DSP header stereo by .gcm extension");
|
|
|
|
break;
|
2008-05-17 01:14:47 +02:00
|
|
|
case meta_RSTM_SPM:
|
|
|
|
snprintf(temp,TEMPSIZE,"Nintendo RSTM header and .brstmspm extension");
|
|
|
|
break;
|
2008-05-17 19:26:20 +02:00
|
|
|
case meta_RAW:
|
|
|
|
snprintf(temp,TEMPSIZE,"assumed RAW PCM file by .raw extension");
|
2008-05-17 23:52:40 +02:00
|
|
|
break;
|
|
|
|
case meta_PS2_VAGi:
|
|
|
|
snprintf(temp,TEMPSIZE,"Sony VAG Interleaved header (VAGi)");
|
|
|
|
break;
|
|
|
|
case meta_PS2_VAGp:
|
|
|
|
snprintf(temp,TEMPSIZE,"Sony VAG Mono header (VAGp)");
|
2008-05-28 13:36:17 +02:00
|
|
|
break;
|
|
|
|
case meta_PS2_VAGs:
|
|
|
|
snprintf(temp,TEMPSIZE,"Sony VAG Stereo header (VAGp)");
|
2008-05-20 20:09:05 +02:00
|
|
|
break;
|
|
|
|
case meta_PS2_VAGm:
|
|
|
|
snprintf(temp,TEMPSIZE,"Sony VAG Mono header (VAGm)");
|
2008-05-17 23:52:40 +02:00
|
|
|
break;
|
|
|
|
case meta_PS2_pGAV:
|
|
|
|
snprintf(temp,TEMPSIZE,"Sony VAG Stereo Little Endian header (pGAV)");
|
2008-05-19 13:39:30 +02:00
|
|
|
break;
|
|
|
|
case meta_PSX_GMS:
|
|
|
|
snprintf(temp,TEMPSIZE,"assumed Grandia GMS file by .gms extension");
|
2008-05-20 20:09:05 +02:00
|
|
|
break;
|
|
|
|
case meta_PS2_STR:
|
|
|
|
snprintf(temp,TEMPSIZE,"assumed STR + STH File by .str & .sth extension");
|
2008-05-21 23:26:52 +02:00
|
|
|
break;
|
|
|
|
case meta_PS2_ILD:
|
|
|
|
snprintf(temp,TEMPSIZE,"ILD header");
|
2008-05-22 21:08:49 +02:00
|
|
|
break;
|
|
|
|
case meta_PS2_PNB:
|
2008-05-24 00:52:02 +02:00
|
|
|
snprintf(temp,TEMPSIZE,"assumed PNB (PsychoNauts Bgm File) by .pnb extension");
|
|
|
|
break;
|
|
|
|
case meta_XBOX_WAVM:
|
|
|
|
snprintf(temp,TEMPSIZE,"assumed Xbox WAVM file by .wavm extension");
|
2008-05-24 17:11:32 +02:00
|
|
|
break;
|
|
|
|
case meta_XBOX_RIFF:
|
|
|
|
snprintf(temp,TEMPSIZE,"Xbox RIFF/WAVE file with 0x0069 Codec ID");
|
2008-05-28 20:13:35 +02:00
|
|
|
break;
|
|
|
|
case meta_DSP_STR:
|
|
|
|
snprintf(temp,TEMPSIZE,"assumed Conan Gamecube STR File by .str extension");
|
2008-06-02 19:58:08 +02:00
|
|
|
break;
|
|
|
|
case meta_EAXA_R2:
|
|
|
|
snprintf(temp,TEMPSIZE,"Electronic Arts XA R2");
|
|
|
|
break;
|
|
|
|
case meta_EAXA_R3:
|
|
|
|
snprintf(temp,TEMPSIZE,"Electronic Arts XA R3");
|
|
|
|
break;
|
|
|
|
case meta_EAXA_PSX:
|
|
|
|
snprintf(temp,TEMPSIZE,"Electronic Arts With PSX ADPCM");
|
2008-06-03 20:41:26 +02:00
|
|
|
break;
|
|
|
|
case meta_CFN:
|
|
|
|
snprintf(temp,TEMPSIZE,"Namco CAF Header");
|
2008-06-07 23:11:33 +02:00
|
|
|
break;
|
|
|
|
case meta_PS2_VPK:
|
|
|
|
snprintf(temp,TEMPSIZE,"VPK Header");
|
2008-05-17 19:26:20 +02:00
|
|
|
break;
|
2008-06-10 03:20:54 +02:00
|
|
|
case meta_GENH:
|
|
|
|
snprintf(temp,TEMPSIZE,"GENH Generic Header");
|
2008-06-09 02:20:08 +02:00
|
|
|
break;
|
2008-06-15 09:59:43 +02:00
|
|
|
#ifdef VGM_USE_VORBIS
|
2008-06-15 08:04:44 +02:00
|
|
|
case meta_ogg_vorbis:
|
|
|
|
snprintf(temp,TEMPSIZE,"Ogg Vorbis");
|
|
|
|
break;
|
2008-06-15 09:59:43 +02:00
|
|
|
#endif
|
2008-06-15 11:23:34 +02:00
|
|
|
case meta_DSP_SADB:
|
|
|
|
snprintf(temp,TEMPSIZE,"sadb header");
|
|
|
|
break;
|
2008-06-25 18:42:13 +02:00
|
|
|
case meta_PS2_BMDX:
|
|
|
|
snprintf(temp,TEMPSIZE,"Beatmania .bmdx header");
|
|
|
|
break;
|
2008-06-29 03:30:13 +02:00
|
|
|
case meta_DSP_WSI:
|
|
|
|
snprintf(temp,TEMPSIZE,".wsi header");
|
|
|
|
break;
|
2008-07-01 05:23:44 +02:00
|
|
|
case meta_AIFC:
|
|
|
|
snprintf(temp,TEMPSIZE,"Audio Interchange File Format AIFF-C");
|
|
|
|
break;
|
2008-07-01 18:11:59 +02:00
|
|
|
case meta_AIFF:
|
|
|
|
snprintf(temp,TEMPSIZE,"Audio Interchange File Format");
|
|
|
|
break;
|
2008-07-02 15:39:51 +02:00
|
|
|
case meta_STR_SNDS:
|
|
|
|
snprintf(temp,TEMPSIZE,".str SNDS SHDR chunk");
|
2008-07-02 05:57:21 +02:00
|
|
|
break;
|
2008-03-03 22:38:11 +01:00
|
|
|
default:
|
2008-03-11 02:27:59 +01:00
|
|
|
snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET");
|
2008-03-03 22:38:11 +01:00
|
|
|
}
|
2008-03-11 02:27:59 +01:00
|
|
|
concatn(length,desc,temp);
|
2008-02-05 07:44:44 +01:00
|
|
|
}
|
2008-03-25 08:30:04 +01:00
|
|
|
|
|
|
|
/* */
|
|
|
|
#define DFS_PAIR_COUNT 4
|
|
|
|
const char * const dfs_pairs[DFS_PAIR_COUNT][2] = {
|
2008-04-04 03:24:57 +02:00
|
|
|
{"L","R"},
|
|
|
|
{"l","r"},
|
2008-03-25 08:30:04 +01:00
|
|
|
{"_0","_1"},
|
2008-04-04 03:24:57 +02:00
|
|
|
{"left","right"},
|
2008-03-25 08:30:04 +01:00
|
|
|
};
|
|
|
|
|
2008-05-20 17:18:38 +02:00
|
|
|
void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFile) {
|
|
|
|
char filename[260];
|
|
|
|
char filename2[260];
|
2008-03-25 08:30:04 +01:00
|
|
|
char * ext;
|
|
|
|
int dfs_name= -1; /*-1=no stereo, 0=opened_stream is left, 1=opened_stream is right */
|
|
|
|
VGMSTREAM * new_stream = NULL;
|
2008-05-20 17:18:38 +02:00
|
|
|
STREAMFILE *dual_stream = NULL;
|
2008-03-25 08:30:04 +01:00
|
|
|
int i,j;
|
|
|
|
|
|
|
|
if (opened_stream->channels != 1) return;
|
2008-05-18 00:00:10 +02:00
|
|
|
|
2008-05-20 17:18:38 +02:00
|
|
|
streamFile->get_name(streamFile,filename,sizeof(filename));
|
|
|
|
|
2008-05-18 00:00:10 +02:00
|
|
|
/* vgmstream's layout stuff currently assumes a single file */
|
|
|
|
// fastelbja : no need ... this one works ok with dual file
|
|
|
|
//if (opened_stream->layout != layout_none) return;
|
2008-03-25 08:30:04 +01:00
|
|
|
|
|
|
|
/* we need at least a base and a name ending to replace */
|
|
|
|
if (strlen(filename)<2) return;
|
|
|
|
|
|
|
|
strcpy(filename2,filename);
|
|
|
|
|
|
|
|
/* look relative to the extension; */
|
|
|
|
ext = (char *)filename_extension(filename2);
|
|
|
|
|
|
|
|
/* we treat the . as part of the extension */
|
|
|
|
if (ext-filename2 >= 1 && ext[-1]=='.') ext--;
|
|
|
|
|
|
|
|
for (i=0; dfs_name==-1 && i<DFS_PAIR_COUNT; i++) {
|
|
|
|
for (j=0; dfs_name==-1 && j<2; j++) {
|
|
|
|
/* find a postfix on the name */
|
|
|
|
if (!memcmp(ext-strlen(dfs_pairs[i][j]),
|
|
|
|
dfs_pairs[i][j],
|
|
|
|
strlen(dfs_pairs[i][j]))) {
|
|
|
|
int other_name=j^1;
|
|
|
|
int moveby;
|
|
|
|
dfs_name=j;
|
|
|
|
|
|
|
|
/* move the extension */
|
|
|
|
moveby = strlen(dfs_pairs[i][other_name]) -
|
|
|
|
strlen(dfs_pairs[i][dfs_name]);
|
|
|
|
memmove(ext+moveby,ext,strlen(ext)+1); /* terminator, too */
|
|
|
|
|
|
|
|
/* make the new name */
|
|
|
|
memcpy(ext+moveby-strlen(dfs_pairs[i][other_name]),dfs_pairs[i][other_name],strlen(dfs_pairs[i][other_name]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* did we find a name for the other file? */
|
|
|
|
if (dfs_name==-1) goto fail;
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
printf("input is: %s\n"
|
2008-03-31 22:17:07 +02:00
|
|
|
"other file would be: %s\n",
|
|
|
|
filename,filename2);
|
2008-03-25 08:30:04 +01:00
|
|
|
#endif
|
|
|
|
|
2008-05-20 17:18:38 +02:00
|
|
|
dual_stream = streamFile->open(streamFile,filename2,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
2008-06-26 04:08:26 +02:00
|
|
|
if (!dual_stream) goto fail;
|
|
|
|
|
2008-05-20 17:18:38 +02:00
|
|
|
new_stream = init_vgmstream_internal(dual_stream,
|
2008-03-25 08:30:04 +01:00
|
|
|
0 /* don't do dual file on this, to prevent recursion */
|
|
|
|
);
|
2008-05-20 17:18:38 +02:00
|
|
|
close_streamfile(dual_stream);
|
2008-03-25 08:30:04 +01:00
|
|
|
|
|
|
|
/* see if we were able to open the file, and if everything matched nicely */
|
|
|
|
if (new_stream &&
|
|
|
|
new_stream->channels == 1 &&
|
|
|
|
/* we have seen legitimate pairs where these are off by one... */
|
|
|
|
/* but leaving it commented out until I can find those and recheck */
|
|
|
|
/* abs(new_stream->num_samples-opened_stream->num_samples <= 1) && */
|
|
|
|
new_stream->num_samples == opened_stream->num_samples &&
|
|
|
|
new_stream->sample_rate == opened_stream->sample_rate &&
|
|
|
|
new_stream->meta_type == opened_stream->meta_type &&
|
|
|
|
new_stream->coding_type == opened_stream->coding_type &&
|
|
|
|
new_stream->layout_type == opened_stream->layout_type &&
|
|
|
|
new_stream->loop_flag == opened_stream->loop_flag &&
|
|
|
|
/* check these even if there is no loop, because they should then
|
|
|
|
* be zero in both */
|
|
|
|
new_stream->loop_start_sample == opened_stream->loop_start_sample &&
|
|
|
|
new_stream->loop_end_sample == opened_stream->loop_end_sample &&
|
|
|
|
/* check even if the layout doesn't use them, because it is
|
|
|
|
* difficult to determine when it does, and they should be zero
|
|
|
|
* otherwise, anyway */
|
|
|
|
new_stream->interleave_block_size == opened_stream->interleave_block_size &&
|
2008-05-19 05:58:15 +02:00
|
|
|
new_stream->interleave_smallblock_size == opened_stream->interleave_smallblock_size) {
|
2008-03-25 08:30:04 +01:00
|
|
|
/* We seem to have a usable, matching file. Merge in the second channel. */
|
|
|
|
VGMSTREAMCHANNEL * new_chans;
|
|
|
|
VGMSTREAMCHANNEL * new_loop_chans = NULL;
|
|
|
|
VGMSTREAMCHANNEL * new_start_chans = NULL;
|
|
|
|
|
|
|
|
/* build the channels */
|
|
|
|
new_chans = calloc(2,sizeof(VGMSTREAMCHANNEL));
|
|
|
|
if (!new_chans) goto fail;
|
|
|
|
|
|
|
|
memcpy(&new_chans[dfs_name],&opened_stream->ch[0],sizeof(VGMSTREAMCHANNEL));
|
|
|
|
memcpy(&new_chans[dfs_name^1],&new_stream->ch[0],sizeof(VGMSTREAMCHANNEL));
|
|
|
|
|
|
|
|
/* loop and start will be initialized later, we just need to
|
|
|
|
* allocate them here */
|
|
|
|
new_start_chans = calloc(2,sizeof(VGMSTREAMCHANNEL));
|
|
|
|
if (!new_start_chans) {
|
|
|
|
free(new_chans);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opened_stream->loop_ch) {
|
|
|
|
new_loop_chans = calloc(2,sizeof(VGMSTREAMCHANNEL));
|
|
|
|
if (!new_loop_chans) {
|
|
|
|
free(new_chans);
|
|
|
|
free(new_start_chans);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove the existing structures */
|
|
|
|
/* not using close_vgmstream as that would close the file */
|
|
|
|
free(opened_stream->ch);
|
|
|
|
free(new_stream->ch);
|
|
|
|
|
|
|
|
free(opened_stream->start_ch);
|
|
|
|
free(new_stream->start_ch);
|
|
|
|
|
|
|
|
if (opened_stream->loop_ch) {
|
|
|
|
free(opened_stream->loop_ch);
|
|
|
|
free(new_stream->loop_ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fill in the new structures */
|
|
|
|
opened_stream->ch = new_chans;
|
|
|
|
opened_stream->start_ch = new_start_chans;
|
|
|
|
opened_stream->loop_ch = new_loop_chans;
|
|
|
|
|
|
|
|
/* stereo! */
|
|
|
|
opened_stream->channels = 2;
|
|
|
|
|
|
|
|
/* discard the second VGMSTREAM */
|
|
|
|
free(new_stream);
|
|
|
|
}
|
|
|
|
fail:
|
2008-05-20 17:18:38 +02:00
|
|
|
return;
|
2008-03-25 08:30:04 +01:00
|
|
|
}
|