Merge pull request #86 from bnnm/mc3-akb-cleanup

MC3, AKB, cleanup
This commit is contained in:
Christopher Snowhill 2017-04-29 18:45:34 -07:00 committed by GitHub
commit b37bdeff01
43 changed files with 2316 additions and 1258 deletions

View File

@ -18,23 +18,29 @@ extern "C" {
}
#include "foo_vgmstream.h"
/* On EOF reads we can return length 0, or ignore and return the requested length + 0-set the buffer.
* Some decoders don't check for EOF and may decode garbage if returned 0, as read_Nbit() funcs return -1.
* Only matters for metas that get num_samples wrong (bigger than total data). */
#define STREAMFILE_IGNORE_EOF 0
static size_t read_the_rest_foo(uint8_t * dest, off_t offset, size_t length, FOO_STREAMFILE * streamfile) {
size_t length_read_total=0;
/* is the beginning at least there? */
if (offset >= streamfile->offset && offset < streamfile->offset+streamfile->validsize) {
/* is the part of the requested length in the buffer? */
if (offset >= streamfile->offset && offset < streamfile->offset + streamfile->validsize) {
size_t length_read;
off_t offset_into_buffer = offset-streamfile->offset;
length_read = streamfile->validsize-offset_into_buffer;
memcpy(dest,streamfile->buffer+offset_into_buffer,length_read);
off_t offset_into_buffer = offset - streamfile->offset;
length_read = streamfile->validsize - offset_into_buffer;
memcpy(dest,streamfile->buffer + offset_into_buffer,length_read);
length_read_total += length_read;
length -= length_read;
offset += length_read;
dest += length_read;
}
/* TODO: What would make more sense here is to read the whole request
/* What would make more sense here is to read the whole request
* at once into the dest buffer, as it must be large enough, and then
* copy some part of that into our own buffer.
* The destination buffer is supposed to be much smaller than the
@ -42,17 +48,22 @@ static size_t read_the_rest_foo(uint8_t * dest, off_t offset, size_t length, FOO
* to the buffer size to avoid having to deal with things like this
* which are outside of my intended use.
*/
/* read as much of the beginning of the request as possible, proceed */
while (length>0) {
/* read the rest of the requested length */
while (length > 0) {
size_t length_to_read;
size_t length_read;
streamfile->validsize=0;
streamfile->validsize = 0; /* buffer is empty now */
/* request outside file: ignore to avoid seek/read */
if (offset > streamfile->filesize) {
streamfile->offset = streamfile->filesize;
memset(dest,0,length);
return length; /* return partially-read buffer and 0-set the rest */
#if STREAMFILE_IGNORE_EOF
memset(dest,0,length); /* dest is already shifted */
return length_read_total + length; /* partially-read + 0-set buffer */
#else
return length_read_total; /* partially-read buffer */
#endif
}
/* position to new offset */
@ -65,43 +76,49 @@ static size_t read_the_rest_foo(uint8_t * dest, off_t offset, size_t length, FOO
#ifdef PROFILE_STREAMFILE
streamfile->error_count++;
#endif
return 0; //fail miserably
return 0; /* fail miserably (fseek shouldn't fail and reach this) */
}
streamfile->offset=offset;
streamfile->offset = offset;
/* decide how much must be read this time */
if (length>streamfile->buffersize) length_to_read=streamfile->buffersize;
else length_to_read=length;
if (length > streamfile->buffersize)
length_to_read = streamfile->buffersize;
else
length_to_read = length;
/* always try to fill the buffer */
/* fill the buffer */
try {
length_read = streamfile->m_file->read(streamfile->buffer,streamfile->buffersize,*streamfile->p_abort);
} catch(...) {
#ifdef PROFILE_STREAMFILE
streamfile->error_count++;
#endif
return 0; //fail miserably
return 0; /* fail miserably */
}
streamfile->validsize=length_read;
streamfile->validsize = length_read;
#ifdef PROFILE_STREAMFILE
streamfile->bytes_read += length_read;
#endif
/* if we can't get enough to satisfy the request we give up */
/* if we can't get enough to satisfy the request (EOF) we give up */
if (length_read < length_to_read) {
memcpy(dest,streamfile->buffer,length_read);
length_read_total+=length_read;
return length_read_total;
#if STREAMFILE_IGNORE_EOF
memset(dest+length_read,0,length-length_read);
return length_read_total + length; /* partially-read + 0-set buffer */
#else
return length_read_total + length_read; /* partially-read buffer */
#endif
}
/* use the new buffer */
memcpy(dest,streamfile->buffer,length_to_read);
length_read_total+=length_to_read;
length-=length_to_read;
dest+=length_to_read;
offset+=length_to_read;
length_read_total += length_to_read;
length -= length_to_read;
dest += length_to_read;
offset += length_to_read;
}
return length_read_total;
@ -109,23 +126,32 @@ static size_t read_the_rest_foo(uint8_t * dest, off_t offset, size_t length, FOO
static size_t read_foo(FOO_STREAMFILE *streamfile, uint8_t * dest, off_t offset, size_t length) {
if (!streamfile || !dest || length<=0) return 0;
/* if entire request is within the buffer */
if (offset >= streamfile->offset && offset+length <= streamfile->offset+streamfile->validsize) {
memcpy(dest,streamfile->buffer+(offset-streamfile->offset),length);
return length;
}
if (!streamfile || !dest || length<=0)
return 0;
/* request outside file: ignore to avoid seek/read in read_the_rest_foo() */
if (offset > streamfile->filesize) {
streamfile->offset = streamfile->filesize;
memset(dest, 0, length);
#if STREAMFILE_IGNORE_EOF
memset(dest,0,length);
return length; /* 0-set buffer */
#else
return 0; /* nothing to read */
#endif
}
/* just copy if entire request is within the buffer */
if (offset >= streamfile->offset && offset + length <= streamfile->offset + streamfile->validsize) {
off_t offset_into_buffer = offset - streamfile->offset;
memcpy(dest,streamfile->buffer + offset_into_buffer,length);
return length;
}
/* request outside buffer: new fread */
return read_the_rest_foo(dest,offset,length,streamfile);
{
return read_the_rest_foo(dest,offset,length,streamfile);
}
}
STREAMFILE * open_foo_streamfile(const char * const filename, abort_callback * p_abort, t_filestats * stats) {

View File

@ -536,6 +536,7 @@ DECLARE_MULTIPLE_FILE_TYPE("LSF Audio File (*.LSF)", lsf);
DECLARE_MULTIPLE_FILE_TYPE("LWAV Audio File (*.LWAV)", lwav);
DECLARE_MULTIPLE_FILE_TYPE("MATX Audio File (*.MATX)", matx);
DECLARE_MULTIPLE_FILE_TYPE("MC3 Audio File (*.MC3)", mc3);
DECLARE_MULTIPLE_FILE_TYPE("MCA Audio File (*.MCA)", mca);
DECLARE_MULTIPLE_FILE_TYPE("MCG Audio File (*.MCG)", mcg);
DECLARE_MULTIPLE_FILE_TYPE("MDS Audio File (*.MDS)", mds);

View File

@ -1,334 +1,20 @@
CODING_OBJS=coding/adx_decoder.o \
coding/g721_decoder.o \
coding/ima_decoder.o \
coding/ngc_afc_decoder.o \
coding/ngc_dsp_decoder.o \
coding/ngc_dtk_decoder.o \
coding/pcm_decoder.o \
coding/psx_decoder.o \
coding/xa_decoder.o \
coding/eaxa_decoder.o \
coding/ogg_vorbis_decoder.o \
coding/sdx2_decoder.o \
coding/ws_decoder.o \
coding/mpeg_decoder.o \
coding/acm_decoder.o \
coding/nwa_decoder.o \
coding/msadpcm_decoder.o \
coding/aica_decoder.o \
coding/nds_procyon_decoder.o \
coding/l5_555_decoder.o \
coding/SASSC_decoder.o \
coding/g7221_decoder.o \
coding/lsf_decoder.o \
coding/mtaf_decoder.o \
coding/at3_decoder.o \
coding/g719_decoder.o \
coding/hca_decoder.o \
coding/ffmpeg_decoder.o \
coding/coding_utils.o \
coding/fsb_vorbis_decoder.o \
coding/wwise_vorbis_decoder.o \
coding/wwise_vorbis_utils.o \
coding/ogl_vorbis_decoder.o
# get all .c to find all possible .o
SRC_SRCS = $(wildcard *.c)
SRC_OBJS = $(patsubst %.c,%.o,$(SRC_SRCS))
LAYOUT_OBJS=layout/ast_blocked.o \
layout/blocked.o \
layout/halpst_blocked.o \
layout/interleave.o \
layout/nolayout.o \
layout/xa_blocked.o \
layout/caf_blocked.o \
layout/ea_block.o \
layout/wsi_blocked.o \
layout/str_snds_blocked.o \
layout/ws_aud_blocked.o \
layout/interleave_byte.o \
layout/mus_acm_layout.o \
layout/aix_layout.o \
layout/ims_block.o \
layout/de2_blocked.o \
layout/xvas_block.o \
layout/vs_blocked.o \
layout/emff_blocked.o \
layout/thp_blocked.o \
layout/gsb_blocked.o \
layout/filp_blocked.o \
layout/aax_layout.o \
layout/ivaud_layout.o \
layout/mxch_blocked.o \
layout/psx_mgav_blocked.o \
layout/ps2_adm_blocked.o \
layout/bdsp_blocked.o \
layout/tra_blocked.o \
layout/ps2_iab_blocked.o \
layout/ps2_strlr_blocked.o \
layout/scd_int_layout.o
CODING_SRCS = $(wildcard coding/*.c)
CODING_OBJS = $(patsubst %.c,%.o,$(CODING_SRCS))
META_OBJS=meta/adx.o \
meta/afc_header.o \
meta/agsc.o \
meta/ast.o \
meta/brstm.o \
meta/halpst.o \
meta/nds_strm.o \
meta/ngc_adpdtk.o \
meta/rsf.o \
meta/rs03.o \
meta/ngc_dsp_std.o \
meta/Cstr.o \
meta/gcsw.o \
meta/ps2_ads.o \
meta/ps2_npsf.o \
meta/rwsd.o \
meta/psx_cdxa.o \
meta/ps2_rxw.o \
meta/ps2_int.o \
meta/ps2_exst.o \
meta/ps2_svag.o \
meta/ps2_mib.o \
meta/ps2_mic.o \
meta/raw.o \
meta/ps2_vag.o \
meta/psx_gms.o \
meta/ps2_str.o \
meta/ps2_ild.o \
meta/ps2_pnb.o \
meta/xbox_wavm.o \
meta/xbox_xwav.o \
meta/ea_header.o \
meta/ngc_caf.o \
meta/ps2_vpk.o \
meta/genh.o \
meta/ogg_vorbis_file.o \
meta/ps2_bmdx.o \
meta/aifc.o \
meta/str_snds.o \
meta/ws_aud.o \
meta/ahx.o \
meta/ivb.o \
meta/svs.o \
meta/riff.o \
meta/pos.o \
meta/nwa.o \
meta/ps2_rws.o \
meta/ps2_hgc1.o \
meta/xss.o \
meta/ps2_sl3.o \
meta/ps2_aus.o \
meta/fsb.o \
meta/fsb5.o \
meta/rsd.o \
meta/rwx.o \
meta/xwb.o \
meta/ea_old.o \
meta/ps2_xa30.o \
meta/musc.o \
meta/musx.o \
meta/ps2_leg.o \
meta/ps2_filp.o \
meta/ps2_ikm.o \
meta/ps2_sfs.o \
meta/sat_dvi.o \
meta/ps2_bg00.o \
meta/dc_kcey.o \
meta/ps2_rstm.o \
meta/acm.o \
meta/mus_acm.o \
meta/ps2_kces.o \
meta/ps2_dxh.o \
meta/ps2_psh.o \
meta/sli.o \
meta/sfl.o \
meta/pcm.o \
meta/ps2_psw.o \
meta/rkv.o \
meta/ps2_vas.o \
meta/ps2_tec.o \
meta/ps2_enth.o \
meta/sdt.o \
meta/aix.o \
meta/ngc_tydsp.o \
meta/wvs.o \
meta/xbox_ims.o \
meta/xbox_stma.o \
meta/de2.o \
meta/dc_str.o \
meta/xbox_xmu.o \
meta/ngc_bh2pcm.o \
meta/xbox_xvas.o \
meta/sat_sap.o \
meta/sat_sap.o \
meta/dc_idvi.o \
meta/ps2_rnd.o \
meta/kraw.o \
meta/ps2_xa2.o \
meta/idsp.o \
meta/ngc_ymf.o \
meta/nds_sad.o \
meta/ps2_ccc.o \
meta/psx_fag.o \
meta/ps2_mihb.o \
meta/ngc_pdt.o \
meta/wii_mus.o \
meta/dc_asd.o \
meta/naomi_spsd.o \
meta/bgw.o \
meta/ps2_ass.o \
meta/ngc_waa_wac_wad_wam.o \
meta/seg.o \
meta/str_asr.o \
meta/zwdsp.o \
meta/gca.o \
meta/ish_isd.o \
meta/spt_spd.o \
meta/ydsp.o \
meta/gsp_gsb.o \
meta/ngc_ssm.o \
meta/msvp.o \
meta/ps2_joe.o \
meta/vgs.o \
meta/vs.o \
meta/dc_dcsw_dcs.o \
meta/wii_smp.o \
meta/ss_stream.o \
meta/emff.o \
meta/thp.o \
meta/wii_sts.o \
meta/capdsp.o \
meta/wii_sng.o \
meta/aax.o \
meta/ps2_p2bt.o \
meta/ps2_gbts.o \
meta/ngc_ffcc_str.o \
meta/sat_baka.o \
meta/nds_swav.o \
meta/vsf.o \
meta/nds_rrds.o \
meta/ps2_tk5.o \
meta/ads.o \
meta/wii_str.o \
meta/zsd.o \
meta/ps2_mcg.o \
meta/redspark.o \
meta/ps2_vgs.o \
meta/ivaud.o \
meta/ps2_sps.o \
meta/nds_hwas.o \
meta/ngc_lps.o \
meta/ps2_snd.o \
meta/naomi_adpcm.o \
meta/sd9.o \
meta/2dx9.o \
meta/ngc_dsp_ygo.o \
meta/ps2_vgv.o \
meta/ngc_gcub.o \
meta/maxis_xa.o \
meta/ngc_sck_dsp.o \
meta/apple_caff.o \
meta/pc_mxst.o \
meta/pc_sob.o \
meta/exakt_sc.o \
meta/wii_bns.o \
meta/pona.o \
meta/xbox_hlwav.o \
meta/stx.o \
meta/ps2_stm.o \
meta/myspd.o \
meta/his.o \
meta/ps2_ast.o \
meta/dmsg_segh.o \
meta/ngc_dsp_konami.o \
meta/ps2_ster.o \
meta/ps2_wb.o \
meta/bnsf.o \
meta/s14_sss.o \
meta/ps2_gcm.o \
meta/ps2_smpl.o \
meta/ps2_msa.o \
meta/pc_smp.o \
meta/p3d.o \
meta/ps2_adsc.o \
meta/psx_str_mgav.o \
meta/ngc_bo2.o \
meta/ngc_dsp_mpds.o \
meta/ps2_khv.o \
meta/ps2_voi.o \
meta/dsp_sth_str.o \
meta/ps2_b1s.o \
meta/ps2_wad.o \
meta/ps2_voi.o \
meta/ps2_lpcm.o \
meta/ps2_adm.o \
meta/dsp_bdsp.o \
meta/ps2_vms.o \
meta/ps2_xau.o \
meta/gh3_bar.o \
meta/ffw.o \
meta/ps2_jstm.o \
meta/ps3_xvag.o \
meta/ps3_cps.o \
meta/sqex_scd.o \
meta/ngc_nst_dsp.o \
meta/baf.o \
meta/ps3_msf.o \
meta/nub_vag.o \
meta/ps3_past.o \
meta/sgxd.o \
meta/ngca.o \
meta/wii_ras.o \
meta/ps2_spm.o \
meta/ps2_mtaf.o \
meta/x360_tra.o \
meta/ps2_iab.o \
meta/ps2_strlr.o \
meta/lsf.o \
meta/vawx.o \
meta/pc_snds.o \
meta/ps2_wmus.o \
meta/mattel_hyperscan.o \
meta/ios_psnd.o \
meta/pc_adp.o \
meta/excitebots.o \
meta/ps3_klbs.o \
meta/ps2_mtaf.o \
meta/tun.o \
meta/wpd.o \
meta/mn_str.o \
meta/ps2_mss.o \
meta/ps2_hsf.o \
meta/ps3_ivag.o \
meta/ps2_2pfs.o \
meta/ubi_ckd.o \
meta/ps2_vbk.o \
meta/otm.o \
meta/bcstm.o \
meta/bfstm.o \
meta/bfwav.o \
meta/g1l.o \
meta/mca.o \
meta/btsnd.o \
meta/hca.o \
meta/ps2_svag_snk.o \
meta/ffmpeg.o \
meta/mp4.o \
meta/xma.o \
meta/ps2_vds_vdm.o \
meta/x360_cxs.o \
meta/dsp_adx.o \
meta/bik.o \
meta/akb.o \
meta/x360_ast.o \
meta/wwise.o \
meta/ubi_raki.o \
meta/x360_nub.o \
meta/x360_pasx.o \
meta/sxd.o \
meta/ogl.o
LAYOUT_SRCS = $(wildcard layout/*.c)
LAYOUT_OBJS = $(patsubst %.c,%.o,$(LAYOUT_SRCS))
EXT_LIBS = ../ext_libs/clHCA.o
META_SRCS = $(wildcard meta/*.c)
META_OBJS = $(patsubst %.c,%.o,$(META_SRCS))
OBJECTS=vgmstream.o streamfile.o util.o formats.o $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS) $(EXT_LIBS)
EXT_LIBS_SRCS = $(wildcard ../ext_libs/*.c)
EXT_LIBS_OBJS = $(patsubst %.c,%.o,$(EXT_LIBS_SRCS))
OBJECTS = $(SRC_OBJS) $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS) $(EXT_LIBS_OBJS)
libvgmstream.a: $(OBJECTS)
$(AR) crs libvgmstream.a $(OBJECTS)

View File

@ -35,5 +35,6 @@ libcoding_la_SOURCES += fsb_vorbis_decoder.c
libcoding_la_SOURCES += wwise_vorbis_decoder.c
libcoding_la_SOURCES += wwise_vorbis_utils.c
libcoding_la_SOURCES += ogl_vorbis_decoder.c
libcoding_la_SOURCES += mc3_decoder.c
EXTRA_DIST = coding.h g72x_state.h clHCA.h

View File

@ -1,12 +1,10 @@
#include "../vgmstream.h"
#ifdef VGM_USE_MAIATRAC3PLUS
#include "maiatrac3plus.h"
#include "coding.h"
#include "../util.h"
void decode_at3plus(VGMSTREAM * vgmstream,
sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) {
#ifdef VGM_USE_MAIATRAC3PLUS
#include "maiatrac3plus.h"
void decode_at3plus(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) {
VGMSTREAMCHANNEL *ch = &vgmstream->ch[0];
maiatrac3plus_codec_data *data = vgmstream->codec_data;
int i;
@ -37,4 +35,31 @@ void decode_at3plus(VGMSTREAM * vgmstream,
}
}
void reset_at3plus(VGMSTREAM *vgmstream) {
maiatrac3plus_codec_data *data = vgmstream->codec_data;
if (data->handle)
Atrac3plusDecoder_closeContext(data->handle);
data->handle = Atrac3plusDecoder_openContext();
data->samples_discard = 0;
}
void seek_at3plus(VGMSTREAM *vgmstream, int32_t num_sample) {
int blocks_to_skip = num_sample / 2048;
int samples_to_discard = num_sample % 2048;
maiatrac3plus_codec_data *data = (maiatrac3plus_codec_data *)(vgmstream->codec_data);
vgmstream->loop_ch[0].offset =
vgmstream->loop_ch[0].channel_start_offset +
vgmstream->interleave_block_size * blocks_to_skip;
data->samples_discard = samples_to_discard;
}
void free_at3plus(maiatrac3plus_codec_data *data) {
if (data) {
if (data->handle) Atrac3plusDecoder_closeContext(data->handle);
free(data);
}
}
#endif

View File

@ -77,7 +77,6 @@ void decode_maxis_adpcm(VGMSTREAM * vgmstream, sample * outbuf, int channelspaci
/* sdx2_decoder */
void decode_sdx2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* sdx2_decoder */
void decode_cbd2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_cbd2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
@ -113,79 +112,93 @@ void decode_lsf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
/* mtaf_decoder */
void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int channels);
/* mc3_decoder */
void decode_mc3(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
/* hca_decoder */
void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
void reset_hca(VGMSTREAM *vgmstream);
void loop_hca(VGMSTREAM *vgmstream);
void free_hca(hca_codec_data * data);
#ifdef VGM_USE_VORBIS
/* ogg_vorbis_decoder */
void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
void reset_ogg_vorbis(VGMSTREAM *vgmstream);
void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample);
void free_ogg_vorbis(ogg_vorbis_codec_data *data);
/* fsb_vorbis_decoder */
vorbis_codec_data * init_fsb_vorbis_codec_data(STREAMFILE *streamfile, off_t start_offset, int channels, int sample_rate, uint32_t setup_id);
void decode_fsb_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels);
void free_fsb_vorbis(vorbis_codec_data *data);
void reset_fsb_vorbis(VGMSTREAM *vgmstream);
void seek_fsb_vorbis(VGMSTREAM *vgmstream, int32_t num_sample);
void free_fsb_vorbis(vorbis_codec_data *data);
/* wwise_vorbis_decoder */
vorbis_codec_data * init_wwise_vorbis_codec_data(STREAMFILE *streamfile, off_t start_offset, int channels, int sample_rate, int blocksize_0_exp, int blocksize_1_exp,
wwise_setup_type setup_type, wwise_header_type header_type, wwise_packet_type packet_type, int big_endian);
void decode_wwise_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels);
void free_wwise_vorbis(vorbis_codec_data *data);
void reset_wwise_vorbis(VGMSTREAM *vgmstream);
void seek_wwise_vorbis(VGMSTREAM *vgmstream, int32_t num_sample);
void free_wwise_vorbis(vorbis_codec_data *data);
/* ogl_vorbis_decoder */
vorbis_codec_data * init_ogl_vorbis_codec_data(STREAMFILE *streamFile, off_t start_offset, off_t * data_start_offset);
void decode_ogl_vorbis(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels);
void free_ogl_vorbis(vorbis_codec_data *data);
void reset_ogl_vorbis(VGMSTREAM *vgmstream);
void seek_ogl_vorbis(VGMSTREAM *vgmstream, int32_t num_sample);
void free_ogl_vorbis(vorbis_codec_data *data);
#endif
/* mpeg_decoder */
#ifdef VGM_USE_MPEG
/* mpeg_decoder */
mpeg_codec_data *init_mpeg_codec_data(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels);
mpeg_codec_data *init_mpeg_codec_data_interleaved(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels, int fixed_frame_size, int fsb_padding);
mpeg_codec_data *init_mpeg_codec_data_ahx(STREAMFILE *streamFile, off_t start_offset, int channel_count);
void decode_mpeg(VGMSTREAM * vgmstream, sample * outbuf, int32_t samples_to_do, int channels);
void decode_fake_mpeg2_l2(VGMSTREAMCHANNEL * stream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do);
void free_mpeg(mpeg_codec_data *data);
void reset_mpeg(VGMSTREAM *vgmstream);
void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample);
void free_mpeg(mpeg_codec_data *data);
long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data *data);
void mpeg_set_error_logging(mpeg_codec_data * data, int enable);
#endif
/* g7221_decoder */
#ifdef VGM_USE_G7221
/* g7221_decoder */
void decode_g7221(VGMSTREAM *vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel);
void reset_g7221(VGMSTREAM *vgmstream);
void free_g7221(VGMSTREAM *vgmstream);
#endif
/* g719_decoder */
#ifdef VGM_USE_G719
/* g719_decoder */
void decode_g719(VGMSTREAM *vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel);
void reset_g719(VGMSTREAM *vgmstream);
void free_g719(VGMSTREAM *vgmstream);
#endif
/* mp4_aac_decoder */
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
/* mp4_aac_decoder */
void decode_mp4_aac(mp4_aac_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
void reset_mp4_aac(VGMSTREAM *vgmstream);
void seek_mp4_aac(VGMSTREAM *vgmstream, int32_t num_sample);
void free_mp4_aac(mp4_aac_codec_data * data);
#endif
/* at3_decoder */
#ifdef VGM_USE_MAIATRAC3PLUS
/* at3_decoder */
void decode_at3plus(VGMSTREAM *vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel);
void reset_at3plus(VGMSTREAM *vgmstream);
void seek_at3plus(VGMSTREAM *vgmstream, int32_t num_sample);
void free_at3plus(maiatrac3plus_codec_data *data);
#endif
/* ffmpeg_decoder */
#ifdef VGM_USE_FFMPEG
/* ffmpeg_decoder */
void decode_ffmpeg(VGMSTREAM *stream, sample * outbuf, int32_t samples_to_do, int channels);
void reset_ffmpeg(VGMSTREAM *vgmstream);
void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample);

View File

@ -1,12 +1,10 @@
#include "../vgmstream.h"
#ifdef VGM_USE_G719
#include "coding.h"
#include "../util.h"
#ifdef VGM_USE_G719
#include "../stack_alloc.h"
void decode_g719(VGMSTREAM * vgmstream,
sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) {
void decode_g719(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) {
VGMSTREAMCHANNEL *ch = &vgmstream->ch[channel];
g719_codec_data *data = vgmstream->codec_data;
g719_codec_data *ch_data = &data[channel];
@ -26,4 +24,30 @@ void decode_g719(VGMSTREAM * vgmstream,
}
}
void reset_g719(VGMSTREAM *vgmstream) {
g719_codec_data *data = vgmstream->codec_data;
int i;
for (i = 0; i < vgmstream->channels; i++)
{
g719_reset(data[i].handle);
}
}
void free_g719(VGMSTREAM *vgmstream) {
g719_codec_data *data = (g719_codec_data *) vgmstream->codec_data;
if (data)
{
int i;
for (i = 0; i < vgmstream->channels; i++)
{
g719_free(data[i].handle);
}
free(data);
}
}
#endif

View File

@ -1,11 +1,9 @@
#include "../vgmstream.h"
#ifdef VGM_USE_G7221
#include "coding.h"
#include "../util.h"
void decode_g7221(VGMSTREAM * vgmstream,
sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) {
#ifdef VGM_USE_G7221
void decode_g7221(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel) {
VGMSTREAMCHANNEL *ch = &vgmstream->ch[channel];
g7221_codec_data *data = vgmstream->codec_data;
g7221_codec_data *ch_data = &data[channel];
@ -24,4 +22,30 @@ void decode_g7221(VGMSTREAM * vgmstream,
}
}
void reset_g7221(VGMSTREAM *vgmstream) {
g7221_codec_data *data = vgmstream->codec_data;
int i;
for (i = 0; i < vgmstream->channels; i++)
{
g7221_reset(data[i].handle);
}
}
void free_g7221(VGMSTREAM *vgmstream) {
g7221_codec_data *data = (g7221_codec_data *) vgmstream->codec_data;
if (data)
{
int i;
for (i = 0; i < vgmstream->channels; i++)
{
g7221_free(data[i].handle);
}
free(data);
}
}
#endif

View File

@ -1,4 +1,4 @@
#include "../vgmstream.h"
#include "coding.h"
void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) {
int samples_done = 0;
@ -80,3 +80,29 @@ void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do, i
free( hca_data );
}
void reset_hca(VGMSTREAM *vgmstream) {
hca_codec_data *data = vgmstream->codec_data;
/*clHCA *hca = (clHCA *)(data + 1);*/
data->curblock = 0;
data->sample_ptr = clHCA_samplesPerBlock;
data->samples_discard = 0;
}
void loop_hca(VGMSTREAM *vgmstream) {
hca_codec_data *data = (hca_codec_data *)(vgmstream->codec_data);
data->curblock = data->info.loopStart;
data->sample_ptr = clHCA_samplesPerBlock;
data->samples_discard = 0;
}
void free_hca(hca_codec_data * data) {
if (data) {
clHCA *hca = (clHCA *)(data + 1);
clHCA_done(hca);
if (data->streamfile)
close_streamfile(data->streamfile);
free(data);
}
}

183
src/coding/mc3_decoder.c Normal file
View File

@ -0,0 +1,183 @@
#include "coding.h"
#include "../util.h"
static const int step_table[4] = {
5, 1, -1, -3
};
static const int mc3_table[4][4][64] = {
{
{
2, 2, 3, 7, 15, 27, 45, 70, 104, 148, 202, 268, 347, 441, 551, 677,
821, 984, 1168, 1374, 1602, 1854, 2131, 2435, 2767, 3127, 3517, 3938, 4392, 4880, 5402, 5960,
6555, 7189, 7862, 8577, 9333, 10132, 10976, 11865, 12802, 13786, 14819, 15903, 17038, 18226, 19469, 20766,
22120, 23531, 25001, 26531, 28123, 29776, 31494, 33276, 35124, 37039, 39023, 41076, 43201, 45397, 47666, 50010
},
{
1, 1, 2, 5, 10, 18, 31, 48, 72, 101, 139, 184, 239, 303, 378, 465,
564, 677, 803, 944, 1101, 1274, 1465, 1674, 1902, 2150, 2418, 2707, 3019, 3355, 3714, 4097,
4507, 4942, 5405, 5896, 6416, 6966, 7546, 8157, 8801, 9477, 10188, 10933, 11714, 12530, 13384, 14276,
15207, 16177, 17188, 18240, 19334, 20471, 21652, 22877, 24148, 25464, 26828, 28240, 29700, 31210, 32770, 34382
},
{
0, 0, 1, 2, 4, 8, 14, 22, 32, 46, 63, 83, 108, 138, 172, 211,
256, 307, 365, 429, 500, 579, 666, 761, 864, 977, 1099, 1230, 1372, 1525, 1688, 1862,
2048, 2246, 2457, 2680, 2916, 3166, 3430, 3708, 4000, 4308, 4631, 4969, 5324, 5695, 6084, 6489,
6912, 7353, 7813, 8291, 8788, 9305, 9841, 10398, 10976, 11574, 12194, 12836, 13500, 14186, 14895, 15628
},
{
0, 0, 0, 0, 1, 3, 5, 8, 13, 18, 25, 33, 43, 55, 68, 84,
102, 123, 146, 171, 200, 231, 266, 304, 345, 390, 439, 492, 549, 610, 675, 745,
819, 898, 982, 1072, 1166, 1266, 1372, 1483, 1600, 1723, 1852, 1987, 2129, 2278, 2433, 2595,
2765, 2941, 3125, 3316, 3515, 3722, 3936, 4159, 4390, 4629, 4877, 5134, 5400, 5674, 5958, 6251
},
},
{
{
1, 1, 2, 4, 9, 17, 28, 44, 65, 92, 126, 167, 217, 276, 344, 423,
513, 615, 730, 858, 1001, 1159, 1332, 1522, 1729, 1954, 2198, 2461, 2745, 3050, 3376, 3725,
4097, 4493, 4914, 5360, 5833, 6332, 6860, 7416, 8001, 8616, 9262, 9939, 10649, 11391, 12168, 12978,
13825, 14707, 15626, 16582, 17576, 18610, 19683, 20797, 21952, 23149, 24389, 25673, 27000, 28373, 29791, 31256
},
{
0, 0, 1, 2, 5, 10, 17, 26, 39, 55, 75, 100, 130, 165, 206, 254,
308, 369, 438, 515, 600, 695, 799, 913, 1037, 1172, 1319, 1477, 1647, 1830, 2025, 2235,
2458, 2696, 2948, 3216, 3499, 3799, 4116, 4449, 4800, 5169, 5557, 5963, 6389, 6835, 7300, 7787,
8295, 8824, 9375, 9949, 10546, 11166, 11810, 12478, 13171, 13889, 14633, 15403, 16200, 17023, 17874, 18753
},
{
0, 0, 0, 1, 3, 6, 11, 17, 26, 37, 50, 67, 86, 110, 137, 169,
205, 246, 292, 343, 400, 463, 532, 608, 691, 781, 879, 984, 1098, 1220, 1350, 1490,
1638, 1797, 1965, 2144, 2333, 2533, 2744, 2966, 3200, 3446, 3704, 3975, 4259, 4556, 4867, 5191,
5530, 5882, 6250, 6632, 7030, 7444, 7873, 8319, 8781, 9259, 9755, 10269, 10800, 11349, 11916, 12502
},
{
0, 0, 0, 0, 0, 1, 2, 4, 6, 9, 12, 16, 21, 27, 34, 42,
51, 61, 73, 85, 100, 115, 133, 152, 172, 195, 219, 246, 274, 305, 337, 372,
409, 449, 491, 536, 583, 633, 686, 741, 800, 861, 926, 993, 1064, 1139, 1216, 1297,
1382, 1470, 1562, 1658, 1757, 1861, 1968, 2079, 2195, 2314, 2438, 2567, 2700, 2837, 2979, 3125
},
},
{
{
1, 1, 2, 5, 10, 18, 31, 48, 72, 101, 139, 184, 239, 303, 378, 465,
564, 677, 803, 944, 1101, 1274, 1465, 1674, 1902, 2150, 2418, 2707, 3019, 3355, 3714, 4097,
4507, 4942, 5405, 5896, 6416, 6966, 7546, 8157, 8801, 9477, 10188, 10933, 11714, 12530, 13384, 14276,
15207, 16177, 17188, 18240, 19334, 20471, 21652, 22877, 24148, 25464, 26828, 28240, 29700, 31210, 32770, 34382
},
{
1, 1, 1, 3, 7, 13, 22, 35, 52, 74, 101, 134, 173, 220, 275, 338,
410, 492, 584, 687, 801, 927, 1065, 1217, 1383, 1563, 1758, 1969, 2196, 2440, 2701, 2980,
3277, 3594, 3931, 4288, 4666, 5066, 5488, 5932, 6401, 6893, 7409, 7951, 8519, 9113, 9734, 10383,
11060, 11765, 12500, 13265, 14061, 14888, 15747, 16638, 17562, 18519, 19511, 20538, 21600, 22698, 23833, 25005
},
{
0, 0, 1, 2, 4, 8, 14, 22, 32, 46, 63, 83, 108, 138, 172, 211,
256, 307, 365, 429, 500, 579, 666, 761, 864, 977, 1099, 1230, 1372, 1525, 1688, 1862,
2048, 2246, 2457, 2680, 2916, 3166, 3430, 3708, 4000, 4308, 4631, 4969, 5324, 5695, 6084, 6489,
6912, 7353, 7813, 8291, 8788, 9305, 9841, 10398, 10976, 11574, 12194, 12836, 13500, 14186, 14895, 15628
},
{
0, 0, 0, 1, 2, 5, 8, 13, 19, 27, 37, 50, 65, 82, 103, 127,
154, 184, 219, 257, 300, 347, 399, 456, 518, 586, 659, 738, 823, 915, 1012, 1117,
1229, 1348, 1474, 1608, 1749, 1899, 2058, 2224, 2400, 2584, 2778, 2981, 3194, 3417, 3650, 3893,
4147, 4412, 4687, 4974, 5273, 5583, 5905, 6239, 6585, 6944, 7316, 7701, 8100, 8511, 8937, 9376
},
},
{
{
1, 1, 2, 5, 11, 20, 34, 53, 78, 111, 151, 201, 260, 331, 413, 508,
616, 738, 876, 1030, 1201, 1390, 1598, 1826, 2075, 2345, 2638, 2954, 3294, 3660, 4051, 4470,
4916, 5392, 5897, 6432, 6999, 7599, 8232, 8899, 9601, 10339, 11114, 11927, 12779, 13670, 14601, 15574,
16590, 17648, 18751, 19898, 21092, 22332, 23620, 24957, 26343, 27779, 29267, 30807, 32400, 34047, 35749, 37507
},
{
1, 1, 1, 3, 6, 11, 19, 31, 45, 64, 88, 117, 152, 193, 241, 296,
359, 430, 511, 601, 701, 811, 932, 1065, 1210, 1368, 1538, 1723, 1921, 2135, 2363, 2607,
2868, 3145, 3440, 3752, 4083, 4433, 4802, 5191, 5600, 6031, 6483, 6957, 7454, 7974, 8517, 9085,
9677, 10295, 10938, 11607, 12303, 13027, 13778, 14558, 15366, 16204, 17072, 17971, 18900, 19861, 20854, 21879
},
{
0, 0, 0, 1, 2, 5, 8, 13, 19, 27, 37, 50, 65, 82, 103, 127,
154, 184, 219, 257, 300, 347, 399, 456, 518, 586, 659, 738, 823, 915, 1012, 1117,
1229, 1348, 1474, 1608, 1749, 1899, 2058, 2224, 2400, 2584, 2778, 2981, 3194, 3417, 3650, 3893,
4147, 4412, 4687, 4974, 5273, 5583, 5905, 6239, 6585, 6944, 7316, 7701, 8100, 8511, 8937, 9376
},
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
},
}
};
/* MC3 3-bit ADPCM (Paradigm Entertainment games).
*
* Layout: blocks with 32b header + 32b ch1, 32b ch2, 32b ch1...
* Each 32b is a sub-block with 10 samples (3b x10) sharing a 'mode' of sorts.
* More than one block is rarely used though.
*
* Tables and original algorithm by daemon1
*/
void decode_mc3(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int i, sample_count = 0;
int32_t hist = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
/* internal interleave */
int block_samples = (vgmstream->interleave_block_size - 4) / 4 / vgmstream->channels * 10;
first_sample = first_sample % block_samples;
/* block header */
if (first_sample == 0) {
uint32_t header = (uint32_t)read_32bitLE(stream->offset, stream->streamfile);
header = (header >> channel*16); /* lower 16=ch1, upper 16b=ch2 */
step_index = header & 0x3f; /* 6b */
hist = header & 0xffc0; /* 16b sans 6b */
if (hist > 0x7fff) hist -= 0x10000; /* sign extend */
}
/* block samples */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
uint32_t subblock, mode, samples, index, sign, diff;
/* header + ch shift + sub-block number (ex. ch0 i=10: sub-block 1, ch0 i=23: sub-block 2) */
off_t subblock_offset = stream->offset + 4 + 4*channel + (i/10)*(4*vgmstream->channels);
int sample_shift = (i%10)*3;
/* expand 3b */
subblock = (uint32_t)read_32bitLE(subblock_offset, stream->streamfile);
mode = (subblock >> 30) & 0x3; /* upper 2b */
samples = (subblock) & 0x3FFFFFFF; /* lower 3b*10 */
index = (samples >> sample_shift) & 3; /* lower 2b */
sign = (samples >> sample_shift) & 4; /* upper 1b */
diff = mc3_table[mode][index][step_index];
if (sign == 0)
hist += (- 1 - diff);
else
hist += diff;
/* new step + clamp */
step_index += step_table[index];
if (step_index < 0) step_index = 0;
else if (step_index > 63) step_index = 63;
/* output */
outbuf[sample_count] = hist;
sample_count += channelspacing;
}
/* internal interleave: increment offset on complete frame */
if (i == block_samples) stream->offset += vgmstream->interleave_block_size;
stream->adpcm_history1_32 = hist;
stream->adpcm_step_index = step_index;
}

View File

@ -82,4 +82,29 @@ void decode_mp4_aac(mp4_aac_codec_data * data, sample * outbuf, int32_t samples_
data->sample_ptr = samples_remain;
}
}
void reset_mp4_aac(VGMSTREAM *vgmstream) {
mp4_aac_codec_data *data = vgmstream->codec_data;
data->sampleId = 0;
data->sample_ptr = data->samples_per_frame;
data->samples_discard = 0;
}
void seek_mp4_aac(VGMSTREAM *vgmstream, int32_t num_sample) {
mp4_aac_codec_data *data = (mp4_aac_codec_data *)(vgmstream->codec_data);
data->sampleId = 0;
data->sample_ptr = data->samples_per_frame;
data->samples_discard = num_sample;
}
void free_mp4_aac(mp4_aac_codec_data * data) {
if (data) {
if (data->h_aacdecoder) aacDecoder_Close(data->h_aacdecoder);
if (data->h_mp4file) MP4Close(data->h_mp4file, 0);
if (data->if_file.streamfile) close_streamfile(data->if_file.streamfile);
free(data);
}
}
#endif

View File

@ -1,9 +1,8 @@
#include "../vgmstream.h"
#include "coding.h"
#include "../util.h"
#ifdef VGM_USE_VORBIS
#include <vorbis/vorbisfile.h>
#include "coding.h"
#include "../util.h"
void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) {
int samples_done = 0;
@ -21,4 +20,30 @@ void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t sa
swap_samples_le(outbuf, samples_to_do*channels);
}
void reset_ogg_vorbis(VGMSTREAM *vgmstream) {
ogg_vorbis_codec_data *data = vgmstream->codec_data;
OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file);
ov_pcm_seek(ogg_vorbis_file, 0);
}
void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) {
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, num_sample);
}
void free_ogg_vorbis(ogg_vorbis_codec_data *data) {
if (!data) {
OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file);
ov_clear(ogg_vorbis_file);
close_streamfile(data->ov_streamfile.streamfile);
free(data);
}
}
#endif

View File

@ -149,6 +149,7 @@ static const char* extension_list[] = {
"lwav", //fake extension, for looping
"matx",
"mc3",
"mca",
"mcg",
"mds",
@ -403,7 +404,7 @@ static const coding_info coding_info_list[] = {
{coding_HEVAG, "Playstation Vita HEVAG 4-bit ADPCM"},
{coding_XA, "CD-ROM XA 4-bit ADPCM"},
{coding_XBOX, "XBOX 4-bit IMA ADPCM"},
{coding_INT_XBOX, "XBOX 4-bit IMA ADPCM (interleaved)"},
{coding_XBOX_int, "XBOX 4-bit IMA ADPCM (interleaved)"},
{coding_EA_XA, "Electronic Arts 4-bit ADPCM (XA based)"},
{coding_EA_ADPCM, "Electronic Arts R1 4-bit ADPCM (XA based)"},
{coding_SDX2, "Squareroot-delta-exact (SDX2) 8-bit DPCM"},
@ -411,20 +412,20 @@ static const coding_info coding_info_list[] = {
{coding_CBD2, "Cuberoot-delta-exact (CBD2) 8-bit DPCM"},
{coding_CBD2_int, "Cuberoot-delta-exact (CBD2) 8-bit DPCM with 1 byte interleave"},
{coding_DVI_IMA, "Intel DVI 4-bit IMA ADPCM"},
{coding_INT_DVI_IMA, "Interleaved Intel DVI 4-bit IMA ADPCM"},
{coding_DVI_IMA_int, "Intel DVI 4-bit IMA ADPCM (interleaved)"},
{coding_EACS_IMA, "EACS 4-bit IMA ADPCM"},
{coding_MAXIS_ADPCM, "Maxis XA (EA ADPCM Variant)"},
{coding_INT_IMA, "Interleaved 4-bit IMA ADPCM"},
{coding_IMA, "4-bit IMA ADPCM"},
{coding_IMA_int, "IMA 4-bit ADPCM (interleaved)"},
{coding_IMA, "IMA 4-bit ADPCM"},
{coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"},
{coding_RAD_IMA, "'Radical' 4-bit IMA ADPCM"},
{coding_RAD_IMA_mono, "'Radical' 4-bit IMA ADPCM (mono)"},
{coding_RAD_IMA, "Radical 4-bit IMA ADPCM"},
{coding_RAD_IMA_mono, "Radical 4-bit IMA ADPCM (mono)"},
{coding_APPLE_IMA4, "Apple Quicktime 4-bit IMA ADPCM"},
{coding_SNDS_IMA, "Heavy Iron .snds 4-bit IMA ADPCM"},
{coding_OTNS_IMA, "Omikron: The Nomad Soul 4-bit IMA ADPCM"},
{coding_FSB_IMA, "FSB multichannel 4-bit IMA ADPCM"},
{coding_WWISE_IMA, "Audiokinetic Wwise 4-bit IMA ADPCM"},
{coding_WS, "Westwood Studios ADPCM"},
{coding_WS, "Westwood Studios VBR ADPCM"},
{coding_ACM, "InterPlay ACM"},
{coding_NWA0, "NWA DPCM Level 0"},
{coding_NWA1, "NWA DPCM Level 1"},
@ -439,6 +440,8 @@ static const coding_info coding_info_list[] = {
{coding_SASSC, "Activision / EXAKT SASSC 8-bit DPCM"},
{coding_LSF, "lsf 4-bit ADPCM"},
{coding_MTAF, "Konami MTAF 4-bit ADPCM"},
{coding_MC3, "Paradigm MC3 3-bit ADPCM"},
#ifdef VGM_USE_VORBIS
{coding_ogg_vorbis, "Ogg Vorbis"},
{coding_fsb_vorbis, "FSB Vorbis"},
@ -847,6 +850,7 @@ static const meta_info meta_info_list[] = {
{meta_UBI_RAKI, "Ubisoft RAKI header"},
{meta_SXD, "Sony SXD header"},
{meta_OGL, "Shin'en OGL header"},
{meta_MC3, "Paradigm MC3 header"},
#ifdef VGM_USE_VORBIS
{meta_OGG_VORBIS, "Ogg Vorbis"},

View File

@ -444,6 +444,10 @@
RelativePath=".\meta\maxis_xa.c"
>
</File>
<File
RelativePath=".\meta\mc3.c"
>
</File>
<File
RelativePath=".\meta\mca.c"
>
@ -1330,6 +1334,10 @@
RelativePath=".\coding\lsf_decoder.c"
>
</File>
<File
RelativePath=".\coding\mc3_decoder.c"
>
</File>
<File
RelativePath=".\coding\mpeg_decoder.c"
>

View File

@ -225,6 +225,7 @@
<ClCompile Include="meta\ivb.c" />
<ClCompile Include="meta\kraw.c" />
<ClCompile Include="meta\maxis_xa.c" />
<ClCompile Include="meta\mc3.c" />
<ClCompile Include="meta\mca.c" />
<ClCompile Include="meta\msvp.c" />
<ClCompile Include="meta\mus_acm.c">
@ -412,6 +413,7 @@
<ClCompile Include="coding\hca_decoder.c" />
<ClCompile Include="coding\ima_decoder.c" />
<ClCompile Include="coding\l5_555_decoder.c" />
<ClCompile Include="coding\mc3_decoder.c" />
<ClCompile Include="coding\mpeg_decoder.c" />
<ClCompile Include="coding\msadpcm_decoder.c" />
<ClCompile Include="coding\nds_procyon_decoder.c" />

View File

@ -247,6 +247,9 @@
<ClCompile Include="meta\maxis_xa.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\mc3.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\mca.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -781,6 +784,9 @@
<ClCompile Include="coding\l5_555_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\mc3_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\mpeg_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>

View File

@ -1,69 +0,0 @@
#include "meta.h"
#include "../util.h"
/* 2DX (found in beatmaniaIIDX16 - EMPRESS (Arcade) */
VGMSTREAM * init_vgmstream_2dx(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag;
int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("2dx",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x0,streamFile) != 0x32445839) /* 2DX9 */
goto fail;
if (read_32bitBE(0x18,streamFile) != 0x52494646) /* RIFF */
goto fail;
if (read_32bitBE(0x20,streamFile) != 0x57415645) /* WAVE */
goto fail;
if (read_32bitBE(0x24,streamFile) != 0x666D7420) /* fmt */
goto fail;
if (read_32bitBE(0x6a,streamFile) != 0x64617461) /* data */
goto fail;
loop_flag = 0;
channel_count = read_16bitLE(0x2e,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x72;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x30,streamFile);
vgmstream->coding_type = coding_MSADPCM;
vgmstream->num_samples = read_32bitLE(0x66,streamFile);
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = read_16bitLE(0x38,streamFile);
vgmstream->meta_type = meta_2DX9;
/* 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;
}

View File

@ -260,5 +260,6 @@ libmeta_la_SOURCES += x360_pasx.c
libmeta_la_SOURCES += x360_nub.c
libmeta_la_SOURCES += sxd.c
libmeta_la_SOURCES += ogl.c
libmeta_la_SOURCES += mc3.c
EXTRA_DIST = meta.h

View File

@ -59,7 +59,7 @@ VGMSTREAM * init_vgmstream_ads(STREAMFILE *streamFile) {
start_offset = 0x28;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x0c,streamFile);
vgmstream->coding_type = coding_INT_XBOX;
vgmstream->coding_type = coding_XBOX_int;
vgmstream->num_samples = (read_32bitBE(0x24,streamFile) / 36 *64 / vgmstream->channels)-64; // to avoid the "pop" at the loop point
vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
vgmstream->interleave_block_size = 0x24;

View File

@ -36,11 +36,12 @@ fail:
/* AKB - found in SQEX iOS games */
VGMSTREAM * init_vgmstream_akb_multi(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
size_t filesize;
off_t start_offset, extra_data_offset = 0;
size_t file_size, header_size, extra_header_size = 0, extra_data_size = 0;
int loop_flag = 0, channel_count, codec;
/* check extensions */
/* .akb.bytes is the usual extension in later games */
if ( !check_extensions(streamFile, "akb") )
goto fail;
@ -49,41 +50,58 @@ VGMSTREAM * init_vgmstream_akb_multi(STREAMFILE *streamFile) {
goto fail;
channel_count = read_8bit(0x0d,streamFile);
loop_flag = read_32bitLE(0x18,streamFile) > 0;
loop_flag = read_32bitLE(0x18,streamFile) > 0; /* loop end */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* 0x04: version? (iPad/IPhone?) 0x24: file_id? */
filesize = read_32bitLE(0x08,streamFile);
/* 0x04 (2): version (iPad/IPhone?) */
header_size = read_16bitLE(0x06,streamFile);
file_size = read_32bitLE(0x08,streamFile);
codec = read_8bit(0x0c,streamFile);
vgmstream->sample_rate = (uint16_t)read_16bitLE(0x0e,streamFile);
vgmstream->num_samples = read_32bitLE(0x10,streamFile);
vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x18,streamFile);
/* 0x0c: some size based on codec 0x10+: unk stuff? 0xc0+: data stuff? */
vgmstream->loop_end_sample = read_32bitLE(0x18,streamFile);
vgmstream->meta_type = meta_AKB;
/* should be ok but not exact (probably more complex, see AKB2) */
if ( header_size >= 0x44) { /* v2 */
/* 0x10+: config? (pan, volume), 0x24: file_id? */
extra_data_size = read_16bitLE(0x1c,streamFile);
extra_header_size = read_16bitLE(0x28,streamFile);
extra_data_offset = header_size + extra_header_size;
start_offset = extra_data_offset + extra_data_size;
/* ~num_samples at extra_data_offset + 0x04/0x0c? */
}
else { /* v0 */
start_offset = header_size;
}
switch (codec) {
#if 0
case 0x02: { /* some kind of ADPCM or PCM [various SFX] */
start_offset = 0xC4;
vgmstream->coding_type = coding_APPLE_IMA4;
vgmstream->layout_type = channel_count==1 ? layout_none : layout_interleave;
vgmstream->interleave_block_size = 0x100;
case 0x02: { /* MSAPDCM [various SFX] */
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = read_16bitLE(extra_data_offset + 0x02,streamFile);
/* adjusted samples; bigger or smaller than base samples, but seems more accurate
* (base samples may have more than possible and read over file size otherwise, very strange)
* loop_end seems to exist even with loop disabled */
vgmstream->num_samples = read_32bitLE(extra_data_offset + 0x04, streamFile);
vgmstream->loop_start_sample = read_32bitLE(extra_data_offset + 0x08, streamFile);
vgmstream->loop_end_sample = read_32bitLE(extra_data_offset + 0x0c, streamFile);
break;
}
#endif
#ifdef VGM_USE_FFMPEG
case 0x05: { /* ogg vorbis [Final Fantasy VI, Dragon Quest II-VI] */
case 0x05: { /* Ogg Vorbis [Final Fantasy VI, Dragon Quest II-VI] */
/* Starting from an offset in the current libvorbis code is a bit hard so just use FFmpeg.
* Decoding seems to produce the same output with (inaudible) +-1 lower byte differences here and there. */
* Decoding seems to produce the same output with (inaudible) +-1 lower byte differences due to rounding. */
ffmpeg_codec_data *ffmpeg_data;
start_offset = 0xCC;
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,filesize-start_offset);
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,file_size-start_offset);
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
@ -98,8 +116,7 @@ VGMSTREAM * init_vgmstream_akb_multi(STREAMFILE *streamFile) {
/* init_vgmstream_akb above has priority, but this works fine too */
ffmpeg_codec_data *ffmpeg_data;
start_offset = 0x20;
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,filesize-start_offset);
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,file_size-start_offset);
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
@ -115,7 +132,6 @@ VGMSTREAM * init_vgmstream_akb_multi(STREAMFILE *streamFile) {
}
#endif
/* AAC @20 in some cases? (see above) */
default:
goto fail;
}
@ -141,6 +157,7 @@ VGMSTREAM * init_vgmstream_akb2_multi(STREAMFILE *streamFile) {
int akb_header_size, sound_index = 0, sound_offset_data, sound, sound_header_size, material_offset_data, material_index = 0, material, extradata, encryption_flag;
/* check extensions */
/* .akb.bytes is the usual extension in later games */
if ( !check_extensions(streamFile, "akb") )
goto fail;
@ -161,7 +178,7 @@ VGMSTREAM * init_vgmstream_akb2_multi(STREAMFILE *streamFile) {
header_offset = material;
channel_count = read_8bit(header_offset+0x02,streamFile);
loop_flag = read_32bitLE(header_offset+0x14,streamFile) > 0;
loop_flag = read_32bitLE(header_offset+0x14,streamFile) > 0; /* loop end */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
@ -175,17 +192,23 @@ VGMSTREAM * init_vgmstream_akb2_multi(STREAMFILE *streamFile) {
* Actual num_samples would be loop_end_sample+1, but more testing is needed */
vgmstream->num_samples = read_32bitLE(header_offset+0x0c,streamFile);
vgmstream->loop_start_sample = read_32bitLE(header_offset+0x10,streamFile);
vgmstream->loop_end_sample = read_32bitLE(header_offset+0x14,streamFile);
vgmstream->loop_end_sample = read_32bitLE(header_offset+0x14,streamFile);
vgmstream->meta_type = meta_AKB;
switch (codec) {
case 0x02: { /* msadpcm [The Irregular at Magic High School Lost Zero (Android)] */
case 0x02: { /* MSAPDCM [The Irregular at Magic High School Lost Zero (Android)] */
if (encryption_flag) goto fail;
vgmstream->num_samples = read_32bitLE(extradata + 0x04, streamFile);
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = read_16bitLE(extradata + 0x02, streamFile);
/* adjusted samples; bigger or smaller than base samples, but seems more accurate
* (base samples may have more than possible and read over file size otherwise, very strange)
* loop_end seems to exist even with loop disabled */
vgmstream->num_samples = read_32bitLE(extradata + 0x04, streamFile);
vgmstream->loop_start_sample = read_32bitLE(extradata + 0x08, streamFile);
vgmstream->loop_end_sample = read_32bitLE(extradata + 0x0c, streamFile);
break;
}

View File

@ -75,7 +75,7 @@ VGMSTREAM * init_vgmstream_bcstm(STREAMFILE *streamFile) {
if (seek_offset == 0) goto fail;
if ((uint32_t)read_32bitBE(seek_offset, streamFile) != 0x5345454B) { /* "SEEK" If this header doesn't exist, assuming that the file is IMA */
ima = 1;
coding_type = coding_INT_IMA;
coding_type = coding_IMA_int;
}
else
coding_type = coding_NGC_DSP;

View File

@ -29,7 +29,7 @@ VGMSTREAM * init_vgmstream_dc_idvi(STREAMFILE *streamFile) {
vgmstream->channels = channel_count;
start_offset = 0x800;
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
vgmstream->coding_type = coding_INT_DVI_IMA;
vgmstream->coding_type = coding_DVI_IMA_int;
vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset);
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(0x0C,streamFile);

View File

@ -165,17 +165,27 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
{
if (coding == coding_SDX2) {
coding = coding_SDX2_int;
vgmstream->coding_type = coding_SDX2_int;
}
//todo if 0 do this too (most codecs seem to enter an infinite loop otherwise)
if(vgmstream->interleave_block_size==0xffffffff)
vgmstream->layout_type=layout_none;
if (vgmstream->interleave_block_size==0xffffffff) {
vgmstream->layout_type = layout_none;
}
else {
vgmstream->layout_type = layout_interleave;
if(coding==coding_DVI_IMA)
coding=coding_INT_DVI_IMA;
if(coding==coding_IMA)
coding=coding_INT_IMA;
if (coding == coding_DVI_IMA)
coding = coding_DVI_IMA_int;
if (coding == coding_IMA)
coding = coding_IMA_int;
}
/* to avoid endless loops */
if (!interleave && (
coding == coding_PSX ||
coding == coding_PSX_badflags ||
coding == coding_IMA_int ||
coding == coding_DVI_IMA_int ||
coding == coding_SDX2_int) ) {
goto fail;
}
} else {
vgmstream->layout_type = layout_none;
@ -191,11 +201,15 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
break;
case coding_MS_IMA:
if (!interleave) goto fail; /* creates garbage */
vgmstream->interleave_block_size = interleave;
vgmstream->layout_type = layout_none;
break;
case coding_MSADPCM:
if (channel_count != 2) goto fail;
if (channel_count > 2) goto fail;
if (!interleave) goto fail; /* creates garbage */
vgmstream->interleave_block_size = interleave;
vgmstream->layout_type = layout_none;
break;
@ -208,9 +222,11 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
break;
case coding_NGC_DSP:
if (dsp_interleave_type == 0) {
if (!interleave) goto fail;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
} else if (dsp_interleave_type == 1) {
if (!interleave) goto fail;
vgmstream->layout_type = layout_interleave_byte;
vgmstream->interleave_block_size = interleave;
} else if (dsp_interleave_type == 2) {

View File

@ -36,7 +36,7 @@ VGMSTREAM * init_vgmstream_ivaud(STREAMFILE *streamFile) {
block_table_offset = read_32bitLE(0,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(block_table_offset + 0x04,streamFile);
vgmstream->coding_type = coding_INT_IMA;
vgmstream->coding_type = coding_IMA_int;
vgmstream->layout_type = layout_ivaud_blocked;
vgmstream->meta_type = meta_PC_IVAUD;

46
src/meta/mc3.c Normal file
View File

@ -0,0 +1,46 @@
#include "meta.h"
/* MC3 - from Paradigm games [Spy Hunter, MX Rider, Terminator 3] */
VGMSTREAM * init_vgmstream_mc3(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
/* check extension, case insensitive */
if ( !check_extensions(streamFile,"mc3"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4D504333) /* "MPC3" */
goto fail;
if (read_32bitBE(0x04,streamFile) != 0x00011400) /* version? */
goto fail;
start_offset = 0x1c;
loop_flag = 0;
channel_count = read_32bitLE(0x08, streamFile);
if (channel_count > 2) goto fail; /* not seen, decoder must be adapted */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->coding_type = coding_MC3;
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_MC3;
vgmstream->sample_rate = read_32bitLE(0x0c, streamFile);
vgmstream->num_samples = read_32bitLE(0x10, streamFile) * 10; /* sizes in sub-blocks of 10 samples (without headers) */
vgmstream->interleave_block_size = (read_32bitLE(0x14, streamFile) * 4 * channel_count) + 4;
if (read_32bitLE(0x18, streamFile) + start_offset != get_streamfile_size(streamFile))
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;
}

View File

@ -686,4 +686,6 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ogl(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_mc3(STREAMFILE *streamFile);
#endif /*_META_H*/

View File

@ -28,7 +28,7 @@ VGMSTREAM * init_vgmstream_nds_hwas(STREAMFILE *streamFile) {
start_offset = 0x200;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
vgmstream->coding_type = coding_INT_IMA;
vgmstream->coding_type = coding_IMA_int;
vgmstream->num_samples = read_32bitLE(0x14,streamFile);
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(0x10,streamFile);

View File

@ -27,7 +27,7 @@ VGMSTREAM * init_vgmstream_sadl(STREAMFILE *streamFile) {
switch (read_8bit(0x33,streamFile)&0xf0)
{
case 0x70:
coding_type = coding_INT_IMA;
coding_type = coding_IMA_int;
break;
case 0xb0:
coding_type = coding_NDS_PROCYON;
@ -61,7 +61,7 @@ VGMSTREAM * init_vgmstream_sadl(STREAMFILE *streamFile) {
vgmstream->coding_type = coding_type;
if (coding_type == coding_INT_IMA)
if (coding_type == coding_IMA_int)
vgmstream->num_samples =
(read_32bitLE(0x40,streamFile)-start_offset)/channel_count*2;
else if (coding_type == coding_NDS_PROCYON)
@ -72,7 +72,7 @@ VGMSTREAM * init_vgmstream_sadl(STREAMFILE *streamFile) {
if (loop_flag)
{
if (coding_type == coding_INT_IMA)
if (coding_type == coding_IMA_int)
vgmstream->loop_start_sample = (read_32bitLE(0x54,streamFile)-start_offset)/channel_count*2;
else
vgmstream->loop_start_sample = (read_32bitLE(0x54,streamFile)-start_offset)/channel_count/16*30;

View File

@ -134,7 +134,7 @@ VGMSTREAM * init_vgmstream_nds_strm_ffta2(STREAMFILE *streamFile) {
start_offset = 0x2C;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x0C,streamFile);
vgmstream->coding_type = coding_INT_IMA;
vgmstream->coding_type = coding_IMA_int;
vgmstream->num_samples = (read_32bitLE(0x04,streamFile)-start_offset);
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(0x20,streamFile);

View File

@ -49,7 +49,7 @@ VGMSTREAM * init_vgmstream_nds_swav(STREAMFILE *streamFile) {
bits_per_sample = 16;
break;
case 2:
coding_type = coding_INT_IMA;
coding_type = coding_IMA_int;
bits_per_sample = 4;
break;
default:
@ -74,7 +74,7 @@ VGMSTREAM * init_vgmstream_nds_swav(STREAMFILE *streamFile) {
vgmstream->loop_start_sample;
}
if (coding_type == coding_INT_IMA) {
if (coding_type == coding_IMA_int) {
/* handle IMA frame header */
vgmstream->loop_start_sample -= 32 / bits_per_sample;
vgmstream->loop_end_sample -= 32 / bits_per_sample;

View File

@ -10,7 +10,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_mpds(STREAMFILE *streamFile) {
/* check extension, case insensitive */
/* .adp: Big Air Freestyle */
/* .dsp: Big Air Freestyle */
/* .mds: Terminator 3 The Redemption, Mission Impossible: Operation Surma */
if (!check_extensions(streamFile, "dsp,mds")) goto fail;
@ -18,7 +18,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_mpds(STREAMFILE *streamFile) {
if (read_32bitBE(0x00,streamFile) != 0x4D504453) /* "MPDS" */
goto fail;
short_mpds = read_32bitBE(0x04,streamFile) != 0x00010000 && read_32bitBE(0x0c,streamFile) == 0x00000002; /* version byte? */
short_mpds = read_32bitBE(0x04,streamFile) != 0x00010000 && check_extensions(streamFile, "mds"); /* version byte? */
channel_count = short_mpds ?
read_16bitBE(0x0a, streamFile) :
@ -51,12 +51,13 @@ VGMSTREAM * init_vgmstream_ngc_dsp_mpds(STREAMFILE *streamFile) {
vgmstream->sample_rate = (uint16_t)read_16bitBE(0x08,streamFile);
vgmstream->interleave_block_size = channel_count==1 ? 0 : 0x200;
#if 0 //todo unknown coeffs, maybe depends on stuff @ 0x10? (but looks like some kind of size)
#if 0 //unknown coeffs/hist, related to data after 0x0c? (only coefs 0..7 seem to be needed)
{
off_t offset = 0x0c;
int i,ch;
for (ch=0; ch < vgmstream->channels; ch++) {
for (i=0; i < 16; i++)
vgmstream->ch[ch].adpcm_coef[i] = mpds_coefs[i];
vgmstream->ch[ch].adpcm_coef[i] = read_16bitBE(offset + i*2);
}
}
#endif

View File

@ -31,7 +31,7 @@ VGMSTREAM * init_vgmstream_ps2_snd(STREAMFILE *streamFile) {
vgmstream->sample_rate = (uint16_t)read_16bitLE(0xe,streamFile);
if(read_8bit(0x08,streamFile)==1) {
vgmstream->coding_type = coding_INT_DVI_IMA;
vgmstream->coding_type = coding_DVI_IMA_int;
}
else
vgmstream->coding_type = coding_PCM16LE;

View File

@ -33,7 +33,7 @@ VGMSTREAM * init_vgmstream_ps2_stm(STREAMFILE *streamFile) {
start_offset = 0x800;
vgmstream->sample_rate = (uint16_t)read_32bitLE(0xc,streamFile);
vgmstream->coding_type = coding_INT_DVI_IMA;
vgmstream->coding_type = coding_DVI_IMA_int;
vgmstream->num_samples = read_32bitLE(0x18,streamFile);

View File

@ -29,7 +29,7 @@ VGMSTREAM * init_vgmstream_dvi(STREAMFILE *streamFile) {
vgmstream->channels = channel_count;
start_offset = read_32bitBE(0x04,streamFile);
vgmstream->sample_rate = 44100;
vgmstream->coding_type = coding_INT_DVI_IMA;
vgmstream->coding_type = coding_DVI_IMA_int;
vgmstream->num_samples = read_32bitBE(0x08,streamFile);

View File

@ -34,7 +34,7 @@ VGMSTREAM * init_vgmstream_xbox_stma(STREAMFILE *streamFile) {
/* fill in the vital statistics */
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x0C,streamFile);
vgmstream->coding_type = coding_INT_DVI_IMA;
vgmstream->coding_type = coding_DVI_IMA_int;
vgmstream->num_samples = read_32bitLE(0x18,streamFile)*2/vgmstream->channels;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size=0x40;

View File

@ -117,7 +117,8 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* for Techland's XWB with no data */
if (xwb.base_offset == 0) goto fail;
if (xwb.data_offset + xwb.data_size != get_streamfile_size(streamFile)) goto fail;
/* some BlazBlue Centralfiction songs have padding after data size */
if (xwb.data_offset + xwb.data_size > get_streamfile_size(streamFile)) goto fail;
/* read base entry (WAVEBANKDATA) */
off = xwb.base_offset;

View File

@ -5,15 +5,23 @@
#include "util.h"
#include "vgmstream.h"
/* On EOF reads we can return length 0, or ignore and return the requested length + 0-set the buffer.
* Some decoders don't check for EOF and may decode garbage if returned 0, as read_Nbit() funcs return -1.
* Only matters for metas that get num_samples wrong (bigger than total data). */
#define STREAMFILE_IGNORE_EOF 0
/* buffered file reader */
typedef struct {
STREAMFILE sf;
FILE * infile;
STREAMFILE sf; /* callbacks */
FILE * infile; /* actual FILE */
char name[PATH_LIMIT];
off_t offset;
size_t validsize;
uint8_t * buffer;
size_t buffersize;
size_t filesize;
off_t offset; /* current offset */
size_t validsize; /* current buffer size */
uint8_t * buffer; /* data buffer */
size_t buffersize; /* max buffer size */
size_t filesize; /* cached file size (max offset) */
#ifdef VGM_DEBUG_OUTPUT
int error_notified;
#endif
@ -28,19 +36,20 @@ static STREAMFILE * open_stdio_streamfile_buffer_by_FILE(FILE *infile,const char
static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOSTREAMFILE * streamfile) {
size_t length_read_total=0;
/* is the beginning at least there? */
if (offset >= streamfile->offset && offset < streamfile->offset+streamfile->validsize) {
/* is the part of the requested length in the buffer? */
if (offset >= streamfile->offset && offset < streamfile->offset + streamfile->validsize) {
size_t length_read;
off_t offset_into_buffer = offset-streamfile->offset;
length_read = streamfile->validsize-offset_into_buffer;
memcpy(dest,streamfile->buffer+offset_into_buffer,length_read);
off_t offset_into_buffer = offset - streamfile->offset;
length_read = streamfile->validsize - offset_into_buffer;
memcpy(dest,streamfile->buffer + offset_into_buffer,length_read);
length_read_total += length_read;
length -= length_read;
offset += length_read;
dest += length_read;
}
/* TODO: What would make more sense here is to read the whole request
/* What would make more sense here is to read the whole request
* at once into the dest buffer, as it must be large enough, and then
* copy some part of that into our own buffer.
* The destination buffer is supposed to be much smaller than the
@ -48,23 +57,29 @@ static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOST
* to the buffer size to avoid having to deal with things like this
* which are outside of my intended use.
*/
/* read as much of the beginning of the request as possible, proceed */
while (length>0) {
/* read the rest of the requested length */
while (length > 0) {
size_t length_to_read;
size_t length_read;
streamfile->validsize=0;
streamfile->validsize = 0; /* buffer is empty now */
/* request outside file: ignore to avoid seek/read */
if (offset > streamfile->filesize) {
#ifdef VGM_DEBUG_OUTPUT
streamfile->offset = streamfile->filesize;
#ifdef VGM_DEBUG_OUTPUT
if (!streamfile->error_notified) {
VGM_LOG("ERROR: reading outside filesize, at offset 0x%lx + 0x%x (buggy meta?)\n", offset, length);
VGM_LOG("ERROR: reading over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length);
streamfile->error_notified = 1;
}
#endif
streamfile->offset = streamfile->filesize;
memset(dest,0,length);
return length; /* return partially-read buffer and 0-set the rest */
#endif
#if STREAMFILE_IGNORE_EOF
memset(dest,0,length); /* dest is already shifted */
return length_read_total + length; /* partially-read + 0-set buffer */
#else
return length_read_total; /* partially-read buffer */
#endif
}
/* position to new offset */
@ -73,18 +88,19 @@ static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOST
#ifdef PROFILE_STREAMFILE
streamfile->error_count++;
#endif
return 0; //fail miserably
return 0; /* fail miserably (fseek shouldn't fail and reach this) */
}
streamfile->offset=offset;
streamfile->offset = offset;
/* decide how much must be read this time */
if (length>streamfile->buffersize) length_to_read=streamfile->buffersize;
else length_to_read=length;
if (length > streamfile->buffersize)
length_to_read = streamfile->buffersize;
else
length_to_read = length;
/* always try to fill the buffer */
length_read = fread(streamfile->buffer,1,streamfile->buffersize,streamfile->infile);
streamfile->validsize=length_read;
/* fill the buffer */
length_read = fread(streamfile->buffer,sizeof(uint8_t),streamfile->buffersize,streamfile->infile);
streamfile->validsize = length_read;
#ifdef PROFILE_STREAMFILE
if (ferror(streamfile->infile)) {
@ -95,19 +111,24 @@ static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOST
streamfile->bytes_read += length_read;
#endif
/* if we can't get enough to satisfy the request we give up */
/* if we can't get enough to satisfy the request (EOF) we give up */
if (length_read < length_to_read) {
memcpy(dest,streamfile->buffer,length_read);
length_read_total+=length_read;
return length_read_total;
#if STREAMFILE_IGNORE_EOF
memset(dest+length_read,0,length-length_read);
return length_read_total + length; /* partially-read + 0-set buffer */
#else
return length_read_total + length_read; /* partially-read buffer */
#endif
}
/* use the new buffer */
memcpy(dest,streamfile->buffer,length_to_read);
length_read_total+=length_to_read;
length-=length_to_read;
dest+=length_to_read;
offset+=length_to_read;
length_read_total += length_to_read;
length -= length_to_read;
dest += length_to_read;
offset += length_to_read;
}
return length_read_total;
@ -115,25 +136,32 @@ static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOST
static size_t read_stdio(STDIOSTREAMFILE *streamfile,uint8_t * dest, off_t offset, size_t length) {
if (!streamfile || !dest || length<=0) return 0;
/* if entire request is within the buffer */
if (offset >= streamfile->offset && offset+length <= streamfile->offset+streamfile->validsize) {
memcpy(dest,streamfile->buffer+(offset-streamfile->offset),length);
return length;
}
if (!streamfile || !dest || length<=0)
return 0;
/* request outside file: ignore to avoid seek/read in read_the_rest() */
if (offset > streamfile->filesize) {
streamfile->offset = streamfile->filesize;
#ifdef VGM_DEBUG_OUTPUT
if (!streamfile->error_notified) {
VGM_LOG("ERROR: reading outside filesize, at offset over 0x%lx (buggy meta?)\n", offset);
VGM_LOG("ERROR: offset over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length);
streamfile->error_notified = 1;
}
#endif
streamfile->offset = streamfile->filesize;
#if STREAMFILE_IGNORE_EOF
memset(dest,0,length);
return length; /* 0-set buffer */
#else
return 0; /* nothing to read */
#endif
}
/* just copy if entire request is within the buffer */
if (offset >= streamfile->offset && offset + length <= streamfile->offset + streamfile->validsize) {
off_t offset_into_buffer = offset - streamfile->offset;
memcpy(dest,streamfile->buffer + offset_into_buffer,length);
return length;
}
@ -523,4 +551,3 @@ int find_chunk(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, in
return 0;
}

View File

@ -18,8 +18,7 @@ static void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFi
/*
* List of functions that will recognize files. These should correspond pretty
* directly to the metadata types
* List of functions that will recognize files.
*/
VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_adx,
@ -354,6 +353,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_xma,
init_vgmstream_sxd,
init_vgmstream_ogl,
init_vgmstream_mc3,
#ifdef VGM_USE_FFMPEG
init_vgmstream_mp4_aac_ffmpeg,
@ -373,22 +373,20 @@ VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) {
fcns_size = (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0]));
/* try a series of formats, see which works */
for (i=0;i<fcns_size;i++) {
for (i=0; i < fcns_size; i++) {
/* call init function and see if valid VGMSTREAM was returned */
VGMSTREAM * vgmstream = (init_vgmstream_fcns[i])(streamFile);
if (vgmstream) {
/* these are little hacky checks */
/* fail if there is nothing to play
* (without this check vgmstream can generate empty files) */
/* fail if there is nothing to play (without this check vgmstream can generate empty files) */
if (vgmstream->num_samples <= 0) {
VGM_LOG("VGMSTREAM: wrong num_samples (ns=%i)\n", vgmstream->num_samples);
VGM_LOG("VGMSTREAM: wrong num_samples (ns=%i / 0x%08x)\n", vgmstream->num_samples, vgmstream->num_samples);
close_vgmstream(vgmstream);
continue;
}
/* everything should have a reasonable sample rate
* (a verification of the metadata) */
/* everything should have a reasonable sample rate (a verification of the metadata) */
if (!check_sample_rate(vgmstream->sample_rate)) {
VGM_LOG("VGMSTREAM: wrong sample rate (sr=%i)\n", vgmstream->sample_rate);
close_vgmstream(vgmstream);
@ -479,11 +477,7 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
#ifdef VGM_USE_VORBIS
if (vgmstream->coding_type==coding_ogg_vorbis) {
ogg_vorbis_codec_data *data = vgmstream->codec_data;
OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file);
ov_pcm_seek(ogg_vorbis_file, 0);
reset_ogg_vorbis(vgmstream);
}
if (vgmstream->coding_type==coding_fsb_vorbis) {
@ -498,59 +492,40 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
reset_ogl_vorbis(vgmstream);
}
#endif
if (vgmstream->coding_type==coding_CRI_HCA) {
hca_codec_data *data = vgmstream->codec_data;
/*clHCA *hca = (clHCA *)(data + 1);*/
data->curblock = 0;
data->sample_ptr = clHCA_samplesPerBlock;
data->samples_discard = 0;
reset_hca(vgmstream);
}
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
if (vgmstream->coding_type==coding_MP4_AAC) {
mp4_aac_codec_data *data = vgmstream->codec_data;
data->sampleId = 0;
data->sample_ptr = data->samples_per_frame;
data->samples_discard = 0;
reset_mp4_aac(vgmstream);
}
#endif
#ifdef VGM_USE_MPEG
if (vgmstream->layout_type==layout_mpeg ||
vgmstream->layout_type==layout_fake_mpeg) {
reset_mpeg(vgmstream);
}
#endif
#ifdef VGM_USE_G7221
if (vgmstream->coding_type==coding_G7221 ||
vgmstream->coding_type==coding_G7221C) {
g7221_codec_data *data = vgmstream->codec_data;
int i;
for (i = 0; i < vgmstream->channels; i++)
{
g7221_reset(data[i].handle);
}
reset_g7221(vgmstream);
}
#endif
#ifdef VGM_USE_G719
if (vgmstream->coding_type==coding_G719) {
g719_codec_data *data = vgmstream->codec_data;
int i;
for (i = 0; i < vgmstream->channels; i++)
{
g719_reset(data[i].handle);
}
reset_g719(vgmstream);
}
#endif
#ifdef VGM_USE_MAIATRAC3PLUS
if (vgmstream->coding_type==coding_AT3plus) {
maiatrac3plus_codec_data *data = vgmstream->codec_data;
if (data->handle) Atrac3plusDecoder_closeContext(data->handle);
data->handle = Atrac3plusDecoder_openContext();
data->samples_discard = 0;
reset_at3plus(vgmstream);
}
#endif
@ -680,20 +655,13 @@ VGMSTREAM * allocate_vgmstream(int channel_count, int looped) {
void close_vgmstream(VGMSTREAM * vgmstream) {
int i,j;
if (!vgmstream) return;
if (!vgmstream)
return;
#ifdef VGM_USE_VORBIS
if (vgmstream->coding_type==coding_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;
}
free_ogg_vorbis(vgmstream->codec_data);
vgmstream->codec_data = NULL;
}
if (vgmstream->coding_type==coding_fsb_vorbis) {
@ -713,43 +681,28 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
#endif
if (vgmstream->coding_type==coding_CRI_HCA) {
hca_codec_data *data = (hca_codec_data *) vgmstream->codec_data;
if (vgmstream->codec_data) {
clHCA *hca = (clHCA *)(data + 1);
clHCA_done(hca);
if (data->streamfile) close_streamfile(data->streamfile);
free(vgmstream->codec_data);
vgmstream->codec_data = NULL;
}
free_hca(vgmstream->codec_data);
vgmstream->codec_data = NULL;
}
#ifdef VGM_USE_FFMPEG
if (vgmstream->coding_type==coding_FFmpeg) {
ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data;
if (vgmstream->codec_data) {
free_ffmpeg(data);
vgmstream->codec_data = NULL;
}
free_ffmpeg(vgmstream->codec_data);
vgmstream->codec_data = NULL;
}
#endif
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
if (vgmstream->coding_type==coding_MP4_AAC) {
mp4_aac_codec_data *data = (mp4_aac_codec_data *) vgmstream->codec_data;
if (vgmstream->codec_data) {
if (data->h_aacdecoder) aacDecoder_Close(data->h_aacdecoder);
if (data->h_mp4file) MP4Close(data->h_mp4file, 0);
if (data->if_file.streamfile) close_streamfile(data->if_file.streamfile);
free(vgmstream->codec_data);
vgmstream->codec_data = NULL;
}
free_mp4_aac(vgmstream->codec_data);
vgmstream->codec_data = NULL;
}
#endif
#ifdef VGM_USE_MPEG
if (vgmstream->layout_type==layout_fake_mpeg||
if (vgmstream->layout_type==layout_fake_mpeg ||
vgmstream->layout_type==layout_mpeg) {
free_mpeg((mpeg_codec_data *)vgmstream->codec_data);
free_mpeg(vgmstream->codec_data);
vgmstream->codec_data = NULL;
}
#endif
@ -757,52 +710,22 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
#ifdef VGM_USE_G7221
if (vgmstream->coding_type == coding_G7221 ||
vgmstream->coding_type == coding_G7221C) {
g7221_codec_data *data = (g7221_codec_data *) vgmstream->codec_data;
if (data)
{
int i;
for (i = 0; i < vgmstream->channels; i++)
{
g7221_free(data[i].handle);
}
free(data);
}
free_g7221(vgmstream);
vgmstream->codec_data = NULL;
}
#endif
#ifdef VGM_USE_G719
if (vgmstream->coding_type == coding_G719) {
g719_codec_data *data = (g719_codec_data *) vgmstream->codec_data;
if (data)
{
int i;
for (i = 0; i < vgmstream->channels; i++)
{
g719_free(data[i].handle);
}
free(data);
}
free_g719(vgmstream);
vgmstream->codec_data = NULL;
}
#endif
#ifdef VGM_USE_MAIATRAC3PLUS
if (vgmstream->coding_type == coding_AT3plus) {
maiatrac3plus_codec_data *data = (maiatrac3plus_codec_data *) vgmstream->codec_data;
if (data)
{
if (data->handle) Atrac3plusDecoder_closeContext(data->handle);
free(data);
}
free_at3plus(vgmstream->codec_data);
vgmstream->codec_data = NULL;
}
#endif
@ -884,9 +807,7 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
vgmstream->coding_type == coding_NWA5
) {
nwa_codec_data *data = (nwa_codec_data *) vgmstream->codec_data;
close_nwa(data->nwa);
free(data);
vgmstream->codec_data = NULL;
@ -1070,8 +991,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_IMA:
case coding_OTNS_IMA:
return 1;
case coding_INT_IMA:
case coding_INT_DVI_IMA:
case coding_IMA_int:
case coding_DVI_IMA_int:
case coding_AICA:
return 2;
case coding_NGC_AFC:
@ -1085,7 +1006,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_PSX_cfg:
return (vgmstream->interleave_block_size - 1) * 2; /* decodes 1 byte into 2 bytes */
case coding_XBOX:
case coding_INT_XBOX:
case coding_XBOX_int:
case coding_FSB_IMA:
return 64;
case coding_EA_XA:
@ -1094,8 +1015,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_EA_ADPCM:
return 14*vgmstream->channels;
case coding_WS:
/* only works if output sample size is 8 bit, which is always
is for WS ADPCM */
/* only works if output sample size is 8 bit, which always is for WS ADPCM */
return vgmstream->ws_output_size;
case coding_MSADPCM:
return (vgmstream->interleave_block_size-(7-1)*vgmstream->channels)*2/vgmstream->channels;
@ -1135,6 +1055,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
return 54;
case coding_MTAF:
return 0x80*2;
case coding_MC3:
return 10;
case coding_CRI_HCA:
return clHCA_samplesPerBlock;
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
@ -1220,7 +1142,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
case coding_XA:
return 14*vgmstream->channels;
case coding_XBOX:
case coding_INT_XBOX:
case coding_XBOX_int:
case coding_FSB_IMA:
return 36;
case coding_MAXIS_ADPCM:
@ -1231,8 +1153,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
return 1; // the frame is variant in size
case coding_WS:
return vgmstream->current_block_size;
case coding_INT_IMA:
case coding_INT_DVI_IMA:
case coding_IMA_int:
case coding_DVI_IMA_int:
case coding_AICA:
return 1;
case coding_APPLE_IMA4:
@ -1255,6 +1177,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
case coding_MSADPCM:
case coding_MTAF:
return vgmstream->interleave_block_size;
case coding_MC3:
return 4;
default:
return 0;
}
@ -1395,7 +1319,7 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
samples_to_do,chan);
}
break;
case coding_INT_XBOX:
case coding_XBOX_int:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_int_xbox_ima(vgmstream,&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
@ -1581,7 +1505,7 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
}
break;
case coding_DVI_IMA:
case coding_INT_DVI_IMA:
case coding_DVI_IMA_int:
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,
@ -1596,7 +1520,7 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
}
break;
case coding_IMA:
case coding_INT_IMA:
case coding_IMA_int:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
@ -1777,6 +1701,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
chan, vgmstream->channels);
}
break;
case coding_MC3:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_mc3(vgmstream, &vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels, vgmstream->samples_into_block, samples_to_do,
chan);
}
break;
}
}
@ -1805,135 +1736,122 @@ int vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMST
}
/* 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);
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) {
/* against everything I hold sacred, preserve adpcm
* history through loop for certain types */
if (vgmstream->meta_type == meta_DSP_STD ||
vgmstream->meta_type == meta_DSP_RS03 ||
vgmstream->meta_type == meta_DSP_CSTR ||
vgmstream->coding_type == coding_PSX ||
vgmstream->coding_type == coding_PSX_bmdx ||
vgmstream->coding_type == coding_PSX_badflags) {
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;
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;
}
}
/* todo preserve ADPCM (ex hevag) history? */
/*if (vgmstream->loop_flag) return 0;*/
if (vgmstream->coding_type==coding_CRI_HCA) {
hca_codec_data *data = (hca_codec_data *)(vgmstream->codec_data);
data->curblock = data->info.loopStart;
data->sample_ptr = clHCA_samplesPerBlock;
data->samples_discard = 0;
/* is this the loop end? */
if (vgmstream->current_sample==vgmstream->loop_end_sample) {
/* against everything I hold sacred, preserve adpcm
* history through loop for certain types */
if (vgmstream->meta_type == meta_DSP_STD ||
vgmstream->meta_type == meta_DSP_RS03 ||
vgmstream->meta_type == meta_DSP_CSTR ||
vgmstream->coding_type == coding_PSX ||
vgmstream->coding_type == coding_PSX_bmdx ||
vgmstream->coding_type == coding_PSX_badflags) {
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;
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;
}
}
/* prepare certain codecs' internal state for looping */
if (vgmstream->coding_type==coding_CRI_HCA) {
loop_hca(vgmstream);
}
#ifdef VGM_USE_VORBIS
if (vgmstream->coding_type==coding_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);
}
if (vgmstream->coding_type==coding_ogg_vorbis) {
seek_ogg_vorbis(vgmstream, vgmstream->loop_sample);
}
if (vgmstream->coding_type==coding_fsb_vorbis) {
seek_fsb_vorbis(vgmstream, vgmstream->loop_start_sample);
}
if (vgmstream->coding_type==coding_fsb_vorbis) {
seek_fsb_vorbis(vgmstream, vgmstream->loop_start_sample);
}
if (vgmstream->coding_type==coding_wwise_vorbis) {
seek_wwise_vorbis(vgmstream, vgmstream->loop_start_sample);
}
if (vgmstream->coding_type==coding_wwise_vorbis) {
seek_wwise_vorbis(vgmstream, vgmstream->loop_start_sample);
}
if (vgmstream->coding_type==coding_ogl_vorbis) {
seek_ogl_vorbis(vgmstream, vgmstream->loop_start_sample);
}
if (vgmstream->coding_type==coding_ogl_vorbis) {
seek_ogl_vorbis(vgmstream, vgmstream->loop_start_sample);
}
#endif
#ifdef VGM_USE_FFMPEG
if (vgmstream->coding_type==coding_FFmpeg) {
seek_ffmpeg(vgmstream, vgmstream->loop_start_sample);
}
if (vgmstream->coding_type==coding_FFmpeg) {
seek_ffmpeg(vgmstream, vgmstream->loop_start_sample);
}
#endif
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
if (vgmstream->coding_type==coding_MP4_AAC) {
mp4_aac_codec_data *data = (mp4_aac_codec_data *)(vgmstream->codec_data);
data->sampleId = 0;
data->sample_ptr = data->samples_per_frame;
data->samples_discard = vgmstream->loop_sample;
}
if (vgmstream->coding_type==coding_MP4_AAC) {
seek_mp4_aac(vgmstream, vgmstream->loop_sample);
}
#endif
#ifdef VGM_USE_MAIATRAC3PLUS
if (vgmstream->coding_type==coding_AT3plus) {
int blocks_to_skip = vgmstream->loop_sample / 2048;
int samples_to_discard = vgmstream->loop_sample % 2048;
maiatrac3plus_codec_data *data = (maiatrac3plus_codec_data *)(vgmstream->codec_data);
vgmstream->loop_ch[0].offset =
vgmstream->loop_ch[0].channel_start_offset +
vgmstream->interleave_block_size * blocks_to_skip;
data->samples_discard = samples_to_discard;
}
if (vgmstream->coding_type==coding_AT3plus) {
seek_at3plus(vgmstream, vgmstream->loop_sample);
}
#endif
#ifdef VGM_USE_MPEG
/* won't work for fake MPEG */
if (vgmstream->layout_type==layout_mpeg) {
seek_mpeg(vgmstream, vgmstream->loop_sample);
}
if (vgmstream->layout_type==layout_mpeg) {
seek_mpeg(vgmstream, vgmstream->loop_sample); /* won't work for fake MPEG */
}
#endif
if (vgmstream->coding_type == coding_NWA0 ||
vgmstream->coding_type == coding_NWA1 ||
vgmstream->coding_type == coding_NWA2 ||
vgmstream->coding_type == coding_NWA3 ||
vgmstream->coding_type == coding_NWA4 ||
vgmstream->coding_type == coding_NWA5)
{
nwa_codec_data *data = vgmstream->codec_data;
seek_nwa(data->nwa, vgmstream->loop_sample);
}
/* 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;
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;
return 1;
if (vgmstream->coding_type == coding_NWA0 ||
vgmstream->coding_type == coding_NWA1 ||
vgmstream->coding_type == coding_NWA2 ||
vgmstream->coding_type == coding_NWA3 ||
vgmstream->coding_type == coding_NWA4 ||
vgmstream->coding_type == coding_NWA5)
{
nwa_codec_data *data = vgmstream->codec_data;
seek_nwa(data->nwa, vgmstream->loop_sample);
}
/* 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;
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;
/* 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);
return 1; /* looped */
}
vgmstream->loop_sample=vgmstream->current_sample;
vgmstream->loop_samples_into_block=vgmstream->samples_into_block;
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;
vgmstream->hit_loop=1;
}
/*}*/
return 0;
/* 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;
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;
vgmstream->hit_loop = 1;
}
return 0; /* not looped */
}
/* build a descriptive string */
@ -1943,18 +1861,22 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
const char* description;
if (!vgmstream) {
snprintf(temp,TEMPSIZE,"NULL VGMSTREAM");
snprintf(temp,TEMPSIZE,
"NULL VGMSTREAM");
concatn(length,desc,temp);
return;
}
snprintf(temp,TEMPSIZE,"sample rate: %d Hz\n"
snprintf(temp,TEMPSIZE,
"sample rate: %d Hz\n"
"channels: %d\n",
vgmstream->sample_rate,vgmstream->channels);
vgmstream->sample_rate,
vgmstream->channels);
concatn(length,desc,temp);
if (vgmstream->loop_flag) {
snprintf(temp,TEMPSIZE,"loop start: %d samples (%.4f seconds)\n"
snprintf(temp,TEMPSIZE,
"loop start: %d samples (%.4f seconds)\n"
"loop end: %d samples (%.4f seconds)\n",
vgmstream->loop_start_sample,
(double)vgmstream->loop_start_sample/vgmstream->sample_rate,
@ -1963,12 +1885,14 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
concatn(length,desc,temp);
}
snprintf(temp,TEMPSIZE,"stream total samples: %d (%.4f seconds)\n",
snprintf(temp,TEMPSIZE,
"stream total samples: %d (%.4f seconds)\n",
vgmstream->num_samples,
(double)vgmstream->num_samples/vgmstream->sample_rate);
concatn(length,desc,temp);
snprintf(temp,TEMPSIZE,"encoding: ");
snprintf(temp,TEMPSIZE,
"encoding: ");
concatn(length,desc,temp);
switch (vgmstream->coding_type) {
#ifdef VGM_USE_FFMPEG
@ -1976,9 +1900,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data;
if (vgmstream->codec_data) {
if (data->codec && data->codec->long_name) {
snprintf(temp,TEMPSIZE,data->codec->long_name);
snprintf(temp,TEMPSIZE,"%s",data->codec->long_name);
} else if (data->codec && data->codec->name) {
snprintf(temp,TEMPSIZE,data->codec->name);
snprintf(temp,TEMPSIZE,"%s",data->codec->name);
} else {
snprintf(temp,TEMPSIZE,"FFmpeg (unknown codec)");
}
@ -1992,56 +1916,79 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
description = get_vgmstream_coding_description(vgmstream->coding_type);
if (!description)
description = "CANNOT DECODE";
strncpy(temp,description,TEMPSIZE);
snprintf(temp,TEMPSIZE,"%s",description);
break;
}
concatn(length,desc,temp);
snprintf(temp,TEMPSIZE,"\nlayout: ");
snprintf(temp,TEMPSIZE,
"\nlayout: ");
concatn(length,desc,temp);
switch (vgmstream->layout_type) {
default:
description = get_vgmstream_layout_description(vgmstream->layout_type);
if (!description)
description = "INCONCEIVABLE";
strncpy(temp,description,TEMPSIZE);
snprintf(temp,TEMPSIZE,"%s",description);
break;
}
concatn(length,desc,temp);
snprintf(temp,TEMPSIZE,"\n");
snprintf(temp,TEMPSIZE,
"\n");
concatn(length,desc,temp);
if (vgmstream->layout_type == layout_interleave
|| vgmstream->layout_type == layout_interleave_shortblock
|| vgmstream->layout_type == layout_interleave_byte) {
snprintf(temp,TEMPSIZE,"interleave: %#x bytes\n",
snprintf(temp,TEMPSIZE,
"interleave: %#x bytes\n",
(int32_t)vgmstream->interleave_block_size);
concatn(length,desc,temp);
if (vgmstream->layout_type == layout_interleave_shortblock) {
snprintf(temp,TEMPSIZE,"last block interleave: %#x bytes\n",
snprintf(temp,TEMPSIZE,
"last block interleave: %#x bytes\n",
(int32_t)vgmstream->interleave_smallblock_size);
concatn(length,desc,temp);
}
}
snprintf(temp,TEMPSIZE,"metadata from: ");
concatn(length,desc,temp);
/* codecs with blocks + headers (there are more, this is a start) */
if (vgmstream->layout_type == layout_none && vgmstream->interleave_block_size > 0) {
switch (vgmstream->coding_type) {
case coding_MSADPCM:
case coding_MS_IMA:
case coding_MC3:
case coding_WWISE_IMA:
snprintf(temp,TEMPSIZE,
"block size: %#x bytes\n",
(int32_t)vgmstream->interleave_block_size);
concatn(length,desc,temp);
break;
default:
break;
}
}
snprintf(temp,TEMPSIZE,
"metadata from: ");
concatn(length,desc,temp);
switch (vgmstream->meta_type) {
default:
description = get_vgmstream_meta_description(vgmstream->meta_type);
if (!description)
description = "THEY SHOULD HAVE SENT A POET";
strncpy(temp,description,TEMPSIZE);
snprintf(temp,TEMPSIZE,"%s",description);
break;
}
concatn(length,desc,temp);
/* only interesting if more than one */
if (vgmstream->num_streams > 1) {
snprintf(temp,TEMPSIZE,"\nnumber of streams: %d",vgmstream->num_streams);
snprintf(temp,TEMPSIZE,
"\nnumber of streams: %d",
vgmstream->num_streams);
concatn(length,desc,temp);
}
}

View File

@ -13,9 +13,10 @@ enum { PATH_LIMIT = 32768 };
* done by external libraries.
* If someone wants to do a standalone build, they can do it by simply
* removing these defines (and the references to the libraries in the Makefile) */
#ifndef VGM_DISABLE_VORBIS
#define VGM_USE_VORBIS
#endif
/* can be disabled to decode with FFmpeg instead */
#ifndef VGM_DISABLE_MPEG
#define VGM_USE_MPEG
#endif
@ -106,16 +107,16 @@ typedef enum {
coding_NDS_PROCYON, /* Procyon Studio ADPCM */
coding_XBOX, /* XBOX IMA ADPCM */
coding_INT_XBOX, /* XBOX IMA ADPCM (interleaved) */
coding_XBOX_int, /* XBOX IMA ADPCM (interleaved) */
coding_IMA, /* IMA ADPCM (low nibble first) */
coding_INT_IMA, /* IMA ADPCM (interleaved) */
coding_IMA_int, /* IMA ADPCM (interleaved) */
coding_DVI_IMA, /* DVI IMA ADPCM (high nibble first), aka ADP4 */
coding_INT_DVI_IMA, /* DVI IMA ADPCM (Interleaved) */
coding_DVI_IMA_int, /* DVI IMA ADPCM (Interleaved) */
coding_NDS_IMA, /* IMA ADPCM w/ NDS layout */
coding_EACS_IMA,
coding_MS_IMA, /* Microsoft IMA */
coding_RAD_IMA, /* "Radical ADPCM" IMA */
coding_RAD_IMA_mono, /* "Radical ADPCM" IMA, mono (for interleave) */
coding_RAD_IMA, /* Radical IMA ADPCM */
coding_RAD_IMA_mono, /* Radical IMA ADPCM, mono (for interleave) */
coding_APPLE_IMA4, /* Apple Quicktime IMA4 */
coding_DAT4_IMA, /* Eurocom 'DAT4' IMA ADPCM */
coding_SNDS_IMA, /* Heavy Iron Studios .snds IMA ADPCM */
@ -130,6 +131,7 @@ typedef enum {
coding_SASSC, /* Activision EXAKT SASSC DPCM */
coding_LSF, /* lsf ADPCM (Fastlane Street Racing iPhone)*/
coding_MTAF, /* Konami MTAF ADPCM (IMA-derived) */
coding_MC3, /* Paradigm MC3 3-bit ADPCM */
/* others */
coding_SDX2, /* SDX2 2:1 Squareroot-Delta-Exact compression DPCM */
@ -605,6 +607,7 @@ typedef enum {
meta_UBI_RAKI, /* Ubisoft RAKI header (Rayman Legends, Just Dance 2017) */
meta_SXD, /* Sony SXD (Gravity Rush, Freedom Wars PSV) */
meta_OGL, /* Shin'en Wii/WiiU (Jett Rocket (Wii), FAST Racing NEO (WiiU)) */
meta_MC3, /* Paradigm games (T3 PS2, MX Rider PS2, MI: Operation Surma PS2) */
#ifdef VGM_USE_VORBIS
meta_OGG_VORBIS, /* Ogg Vorbis */

View File

@ -1,103 +1,137 @@
#ifndef NULLSOFT_WINAMP_IN2H
#define NULLSOFT_WINAMP_IN2H
#include "out.h"
// note: exported symbol is now winampGetInModule2.
#define IN_VER 0x100
#define IN_UNICODE 0x0F000000
#ifdef UNICODE_INPUT_PLUGIN
#define in_char wchar_t
#define IN_VER (IN_UNICODE | 0x100)
#else
#define in_char char
#define IN_VER 0x100
#endif
#define IN_MODULE_FLAG_USES_OUTPUT_PLUGIN 1
// By default, Winamp assumes that your input plugin wants to use Winamp's EQ, and doesn't do replay gain
// if you handle any of these yourself (EQ, Replay Gain adjustments), then set these flags accordingly
#define IN_MODULE_FLAG_EQ 2 // set this if you do your own EQ
#define IN_MODULE_FLAG_REPLAYGAIN 8 // set this if you adjusted volume for replay gain
// for tracks with no replay gain metadata, you should clear this flag
// UNLESS you handle "non_replaygain" gain adjustment yourself
#define IN_MODULE_FLAG_REPLAYGAIN_PREAMP 16 // use this if you queried for the replay gain preamp parameter and used it
// this parameter is new to 5.54
typedef struct
{
int version; // module type (IN_VER)
char *description; // description of module, with version string
int version; // module type (IN_VER)
char *description; // description of module, with version string
HWND hMainWindow; // winamp's main window (filled in by winamp)
HINSTANCE hDllInstance; // DLL instance handle (Also filled in by winamp)
HWND hMainWindow; // winamp's main window (filled in by winamp)
HINSTANCE hDllInstance; // DLL instance handle (Also filled in by winamp)
char *FileExtensions; // "mp3\0Layer 3 MPEG\0mp2\0Layer 2 MPEG\0mpg\0Layer 1 MPEG\0"
// May be altered from Config, so the user can select what they want
int is_seekable; // is this stream seekable?
int UsesOutputPlug; // does this plug-in use the output plug-ins? (musn't ever change, ever :)
char *FileExtensions; // "mp3\0Layer 3 MPEG\0mp2\0Layer 2 MPEG\0mpg\0Layer 1 MPEG\0"
// May be altered from Config, so the user can select what they want
void (*Config)(HWND hwndParent); // configuration dialog
void (*About)(HWND hwndParent); // about dialog
int is_seekable; // is this stream seekable?
int UsesOutputPlug; // does this plug-in use the output plug-ins? (musn't ever change, ever :)
// note that this has turned into a "flags" field
// see IN_MODULE_FLAG_*
void (*Init)(); // called at program init
void (*Quit)(); // called at program quit
void (*Config)(HWND hwndParent); // configuration dialog
void (*About)(HWND hwndParent); // about dialog
void (*GetFileInfo)(char *file, char *title, int *length_in_ms); // if file == NULL, current playing is used
int (*InfoBox)(char *file, HWND hwndParent);
int (*IsOurFile)(char *fn); // called before extension checks, to allow detection of mms://, etc
// playback stuff
int (*Play)(char *fn); // return zero on success, -1 on file-not-found, some other value on other (stopping winamp) error
void (*Pause)(); // pause stream
void (*UnPause)(); // unpause stream
int (*IsPaused)(); // ispaused? return 1 if paused, 0 if not
void (*Stop)(); // stop (unload) stream
void (*Init)(); // called at program init
void (*Quit)(); // called at program quit
// time stuff
int (*GetLength)(); // get length in ms
int (*GetOutputTime)(); // returns current output time in ms. (usually returns outMod->GetOutputTime()
void (*SetOutputTime)(int time_in_ms); // seeks to point in stream (in ms). Usually you signal yoru thread to seek, which seeks and calls outMod->Flush()..
#define GETFILEINFO_TITLE_LENGTH 2048
void (*GetFileInfo)(const in_char *file, in_char *title, int *length_in_ms); // if file == NULL, current playing is used
// volume stuff
void (*SetVolume)(int volume); // from 0 to 255.. usually just call outMod->SetVolume
void (*SetPan)(int pan); // from -127 to 127.. usually just call outMod->SetPan
// in-window builtin vis stuff
#define INFOBOX_EDITED 0
#define INFOBOX_UNCHANGED 1
int (*InfoBox)(const in_char *file, HWND hwndParent);
void (*SAVSAInit)(int maxlatency_in_ms, int srate); // call once in Play(). maxlatency_in_ms should be the value returned from outMod->Open()
// call after opening audio device with max latency in ms and samplerate
void (*SAVSADeInit)(); // call in Stop()
int (*IsOurFile)(const in_char *fn); // called before extension checks, to allow detection of mms://, etc
// playback stuff
int (*Play)(const in_char *fn); // return zero on success, -1 on file-not-found, some other value on other (stopping winamp) error
void (*Pause)(); // pause stream
void (*UnPause)(); // unpause stream
int (*IsPaused)(); // ispaused? return 1 if paused, 0 if not
void (*Stop)(); // stop (unload) stream
// time stuff
int (*GetLength)(); // get length in ms
int (*GetOutputTime)(); // returns current output time in ms. (usually returns outMod->GetOutputTime()
void (*SetOutputTime)(int time_in_ms); // seeks to point in stream (in ms). Usually you signal your thread to seek, which seeks and calls outMod->Flush()..
// volume stuff
void (*SetVolume)(int volume); // from 0 to 255.. usually just call outMod->SetVolume
void (*SetPan)(int pan); // from -127 to 127.. usually just call outMod->SetPan
// in-window builtin vis stuff
void (*SAVSAInit)(int maxlatency_in_ms, int srate); // call once in Play(). maxlatency_in_ms should be the value returned from outMod->Open()
// call after opening audio device with max latency in ms and samplerate
void (*SAVSADeInit)(); // call in Stop()
// simple vis supplying mode
void (*SAAddPCMData)(void *PCMData, int nch, int bps, int timestamp);
// sets the spec data directly from PCM data
// quick and easy way to get vis working :)
// needs at least 576 samples :)
// simple vis supplying mode
void (*SAAddPCMData)(void *PCMData, int nch, int bps, int timestamp);
// sets the spec data directly from PCM data
// quick and easy way to get vis working :)
// needs at least 576 samples :)
// advanced vis supplying mode, only use if you're cool. Use SAAddPCMData for most stuff.
int (*SAGetMode)(); // gets csa (the current type (4=ws,2=osc,1=spec))
// use when calling SAAdd()
void (*SAAdd)(void *data, int timestamp, int csa); // sets the spec data, filled in by winamp
// advanced vis supplying mode, only use if you're cool. Use SAAddPCMData for most stuff.
int (*SAGetMode)(); // gets csa (the current type (4=ws,2=osc,1=spec))
// use when calling SAAdd()
int (*SAAdd)(void *data, int timestamp, int csa); // sets the spec data, filled in by winamp
// vis stuff (plug-in)
// simple vis supplying mode
void (*VSAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); // sets the vis data directly from PCM data
// quick and easy way to get vis working :)
// needs at least 576 samples :)
// vis stuff (plug-in)
// simple vis supplying mode
void (*VSAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); // sets the vis data directly from PCM data
// quick and easy way to get vis working :)
// needs at least 576 samples :)
// advanced vis supplying mode, only use if you're cool. Use VSAAddPCMData for most stuff.
int (*VSAGetMode)(int *specNch, int *waveNch); // use to figure out what to give to VSAAdd
void (*VSAAdd)(void *data, int timestamp); // filled in by winamp, called by plug-in
// advanced vis supplying mode, only use if you're cool. Use VSAAddPCMData for most stuff.
int (*VSAGetMode)(int *specNch, int *waveNch); // use to figure out what to give to VSAAdd
int (*VSAAdd)(void *data, int timestamp); // filled in by winamp, called by plug-in
// call this in Play() to tell the vis plug-ins the current output params.
void (*VSASetInfo)(int nch, int srate);
// call this in Play() to tell the vis plug-ins the current output params.
void (*VSASetInfo)(int srate, int nch); // <-- Correct (benski, dec 2005).. old declaration had the params backwards
// dsp plug-in processing:
// (filled in by winamp, called by input plug)
// dsp plug-in processing:
// (filled in by winamp, calld by input plug)
// returns 1 if active (which means that the number of samples returned by dsp_dosamples
// could be greater than went in.. Use it to estimate if you'll have enough room in the
// output buffer
int (*dsp_isactive)();
// returns 1 if active (which means that the number of samples returned by dsp_dosamples
// could be greater than went in.. Use it to estimate if you'll have enough room in the
// output buffer
int (*dsp_isactive)();
// returns number of samples to output. This can be as much as twice numsamples.
// be sure to allocate enough buffer for samples, then.
int (*dsp_dosamples)(short int *samples, int numsamples, int bps, int nch, int srate);
// returns number of samples to output. This can be as much as twice numsamples.
// be sure to allocate enough buffer for samples, then.
int (*dsp_dosamples)(short int *samples, int numsamples, int bps, int nch, int srate);
// eq stuff
void (*EQSet)(int on, char data[10], int preamp); // 0-64 each, 31 is +0, 0 is +12, 63 is -12. Do nothing to ignore.
// eq stuff
void (*EQSet)(int on, char data[10], int preamp); // 0-64 each, 31 is +0, 0 is +12, 63 is -12. Do nothing to ignore.
// info setting (filled in by winamp)
void (*SetInfo)(int bitrate, int srate, int stereo, int synched); // if -1, changes ignored? :)
// info setting (filled in by winamp)
void (*SetInfo)(int bitrate, int srate, int stereo, int synched); // if -1, changes ignored? :)
Out_Module *outMod; // filled in by winamp, optionally used :)
Out_Module *outMod; // filled in by winamp, optionally used :)
} In_Module;
// return values from the winampUninstallPlugin(HINSTANCE hdll, HWND parent, int param)
// which determine if we can uninstall the plugin immediately or on winamp restart
//
// uninstall support was added from 5.0+ and uninstall now support from 5.5+
// it is down to you to ensure that if uninstall now is returned that it will not cause a crash
// (ie don't use if you've been subclassing the main window)
#define IN_PLUGIN_UNINSTALL_NOW 0x1
#define IN_PLUGIN_UNINSTALL_REBOOT 0x0
#endif

View File

@ -5,6 +5,11 @@
** Copyright (c) 1998, Justin Frankel/Nullsoft Inc.
*/
/* Winamp uses wchar_t filenames when this is on, so extra steps are needed.
* To open unicode filenames it needs to use _wfopen, inside a WA_STREAMFILE to pass around */
//#define UNICODE_INPUT_PLUGIN
#ifdef _MSC_VER
#define _CRT_SECURE_NO_DEPRECATE
#endif
@ -22,6 +27,7 @@
#include "wa_ipc.h"
#include "resource.h"
#ifndef VERSION
#include "../version.h"
#endif
@ -33,14 +39,13 @@
#define PLUGIN_DESCRIPTION "vgmstream plugin " VERSION " " __DATE__
#define INI_NAME "plugin.ini"
/* post when playback stops */
#define WM_WA_MPEG_EOF WM_USER+2
In_Module input_module; /* the input module, declared at the bottom of this file */
DWORD WINAPI __stdcall decode(void *arg);
char lastfn[MAX_PATH+1] = {0}; /* name of the currently playing file */
short sample_buffer[576*2*2]; /* 576 16-bit samples, stereo, possibly doubled in size for DSP */
#define DEFAULT_FADE_SECONDS "10.00"
#define DEFAULT_FADE_DELAY_SECONDS "0.00"
@ -56,6 +61,18 @@ short sample_buffer[576*2*2]; /* 576 16-bit samples, stereo, possibly doubled in
#define LOOP_FOREVER_INI_ENTRY "loop_forever"
#define IGNORE_LOOP_INI_ENTRY "ignore_loop"
char *priority_strings[] = {"Idle","Lowest","Below Normal","Normal","Above Normal","Highest (not recommended)","Time Critical (not recommended)"};
int priority_values[] = {THREAD_PRIORITY_IDLE,THREAD_PRIORITY_LOWEST,THREAD_PRIORITY_BELOW_NORMAL,THREAD_PRIORITY_NORMAL,THREAD_PRIORITY_ABOVE_NORMAL,THREAD_PRIORITY_HIGHEST,THREAD_PRIORITY_TIME_CRITICAL};
#define WINAMP_MAX_PATH 32768 /* originally 260+1 */
in_char lastfn[WINAMP_MAX_PATH] = {0}; /* name of the currently playing file */
/* Winamp Play extension list, needed to accept/play and associate extensions in Windows */
#define EXTENSION_LIST_SIZE VGM_EXTENSION_LIST_CHAR_SIZE * 6
#define EXT_BUFFER_SIZE 200
char working_extension_list[EXTENSION_LIST_SIZE] = {0};
/* plugin config */
double fade_seconds;
double fade_delay_seconds;
double loop_count;
@ -63,11 +80,11 @@ int thread_priority;
int loop_forever;
int ignore_loop;
char *priority_strings[] = {"Idle","Lowest","Below Normal","Normal","Above Normal","Highest (not recommended)","Time Critical (not recommended)"};
int priority_values[] = {THREAD_PRIORITY_IDLE,THREAD_PRIORITY_LOWEST,THREAD_PRIORITY_BELOW_NORMAL,THREAD_PRIORITY_NORMAL,THREAD_PRIORITY_ABOVE_NORMAL,THREAD_PRIORITY_HIGHEST,THREAD_PRIORITY_TIME_CRITICAL};
/* plugin state */
VGMSTREAM * vgmstream = NULL;
HANDLE decode_thread_handle = INVALID_HANDLE_VALUE;
short sample_buffer[576*2*2]; /* 576 16-bit samples, stereo, possibly doubled in size for DSP */
int paused = 0;
int decode_abort = 0;
int seek_needed_samples = -1;
@ -76,15 +93,110 @@ int decode_pos_samples = 0;
int stream_length_samples = 0;
int fade_samples = 0;
/* Winamp Play extension list, needed to accept/play and associate extensions in Windows */
#define EXTENSION_LIST_SIZE VGM_EXTENSION_LIST_CHAR_SIZE * 6
char working_extension_list[EXTENSION_LIST_SIZE] = {0};
#define EXT_BUFFER_SIZE 200
/* ***************************************** */
static void add_extension(int length, char * dst, const char * src);
static void build_extension_list();
/* Winamp INI reader */
static void GetINIFileName(char * iniFile) {
/* if we're running on a newer winamp version that better supports
* saving of settings to a per-user directory, use that directory - if not
* then just revert to the old behaviour */
if(IsWindow(input_module.hMainWindow) && SendMessage(input_module.hMainWindow, WM_WA_IPC,0,IPC_GETVERSION) >= 0x5000) {
char * iniDir = (char *)SendMessage(input_module.hMainWindow, WM_WA_IPC, 0, IPC_GETINIDIRECTORY);
strncpy(iniFile, iniDir, WINAMP_MAX_PATH);
strncat(iniFile, "\\Plugins\\", WINAMP_MAX_PATH);
/* can't be certain that \Plugins already exists in the user dir */
CreateDirectory(iniFile,NULL);
strncat(iniFile, INI_NAME, WINAMP_MAX_PATH);
}
else {
char * lastSlash;
GetModuleFileName(NULL, iniFile, WINAMP_MAX_PATH);
lastSlash = strrchr(iniFile, '\\');
*(lastSlash + 1) = 0;
strncat(iniFile, "Plugins\\" INI_NAME,WINAMP_MAX_PATH);
}
}
/* Adds ext to Winamp's extension list */
static void add_extension(int length, char * dst, const char * ext) {
char buf[EXT_BUFFER_SIZE];
char ext_upp[EXT_BUFFER_SIZE];
int ext_len, written;
int i,j;
if (length <= 1)
return;
ext_len = strlen(ext);
/* find end of dst (double \0), saved in i */
for (i=0; i<length-2 && (dst[i] || dst[i+1]); i++)
;
/* check if end reached or not enough room to add */
if (i == length-2 || i + EXT_BUFFER_SIZE+2 > length-2 || ext_len * 3 + 20+2 > EXT_BUFFER_SIZE) {
dst[i]='\0';
dst[i+1]='\0';
return;
}
if (i > 0)
i++;
/* uppercase ext */
for (j=0; j < ext_len; j++)
ext_upp[j] = toupper(ext[j]);
ext_upp[j] = '\0';
/* copy new extension + double null terminate */
written = sprintf(buf, "%s%c%s Audio File (*.%s)%c", ext,'\0',ext_upp,ext_upp,'\0'); /*ex: "vgmstream\0vgmstream Audio File (*.VGMSTREAM)\0" */
for (j=0; j < written; i++,j++)
dst[i] = buf[j];
dst[i]='\0';
dst[i+1]='\0';
}
/* Creates Winamp's extension list, a single string that ends with \0\0.
* Each extension must be in this format: "extension\0Description\0" */
static void build_extension_list() {
const char ** ext_list;
int ext_list_len;
int i;
working_extension_list[0]='\0';
working_extension_list[1]='\0';
ext_list = vgmstream_get_formats();
ext_list_len = vgmstream_get_formats_length();
for (i=0; i < ext_list_len; i++) {
add_extension(EXTENSION_LIST_SIZE, working_extension_list, ext_list[i]);
}
}
/* unicode utils */
static void copy_title(in_char * dst, int dst_size, const in_char * src) {
#ifdef UNICODE_INPUT_PLUGIN
in_char *p = (in_char*)src + wcslen(src); /* find end */
while (*p != '\\' && p >= src) /* and find last "\" */
p--;
p++;
wcscpy(dst,p); /* copy filename only */
#else
in_char *p = (in_char*)src + strlen(src); /* find end */
while (*p != '\\' && p >= src) /* and find last "\" */
p--;
p++;
strcpy(dst,p); /* copy filename only */
#endif
}
/* ***************************************** */
/* about dialog */
void about(HWND hwndParent) {
MessageBox(hwndParent,
PLUGIN_DESCRIPTION "\n"
@ -92,36 +204,10 @@ void about(HWND hwndParent) {
"http://sourceforge.net/projects/vgmstream"
,"about in_vgmstream",MB_OK);
}
void quit() {}
void GetINIFileName(char * iniFile) {
/* if we're running on a newer winamp version that better supports
* saving of settings to a per-user directory, use that directory - if not
* then just revert to the old behaviour */
if(IsWindow(input_module.hMainWindow) && SendMessage(input_module.hMainWindow, WM_WA_IPC,0,IPC_GETVERSION) >= 0x5000) {
char * iniDir = (char *)SendMessage(input_module.hMainWindow, WM_WA_IPC, 0, IPC_GETINIDIRECTORY);
strncpy(iniFile, iniDir, MAX_PATH);
strncat(iniFile, "\\Plugins\\", MAX_PATH);
/* can't be certain that \Plugins already exists in the user dir */
CreateDirectory(iniFile,NULL);
strncat(iniFile, INI_NAME, MAX_PATH);
}
else {
char * lastSlash;
GetModuleFileName(NULL, iniFile, MAX_PATH);
lastSlash = strrchr(iniFile, '\\');
*(lastSlash + 1) = 0;
strncat(iniFile, "Plugins\\" INI_NAME,MAX_PATH);
}
}
/* called at program init */
void init() {
char iniFile[MAX_PATH+1];
char iniFile[WINAMP_MAX_PATH];
char buf[256];
int consumed;
@ -167,19 +253,25 @@ void init() {
build_extension_list();
}
/* we don't recognize protocols */
int isourfile(char *fn) { return 0; }
/* called at program quit */
void quit() {
}
/* called before extension checks, to allow detection of mms://, etc */
int isourfile(const in_char *fn) {
return 0; /* we don't recognize protocols */
}
/* request to start playing a file */
int play(char *fn)
{
int play(const in_char *fn) {
int max_latency;
/* don't lose a pointer! */
if (vgmstream) {
/* TODO: this should either pop up an error box or close the file */
return 1;
return 1; /* error */
}
/* open the stream, set up */
vgmstream = init_vgmstream(fn);
/* were we able to open it? */
@ -191,11 +283,11 @@ int play(char *fn)
if (vgmstream->channels <= 0) {
close_vgmstream(vgmstream);
vgmstream=NULL;
return 1;
return 1; /* error */
}
/* Remember that name, friends! */
strncpy(lastfn,fn,MAX_PATH);
strncpy(lastfn,fn,WINAMP_MAX_PATH);
/* open the output plugin */
max_latency = input_module.outMod->Open(vgmstream->sample_rate,vgmstream->channels,
@ -204,7 +296,7 @@ int play(char *fn)
if (max_latency < 0) {
close_vgmstream(vgmstream);
vgmstream=NULL;
return 1;
return 1; /* error */
}
/* Set info display */
@ -234,15 +326,27 @@ int play(char *fn)
SetThreadPriority(decode_thread_handle,priority_values[thread_priority]);
return 0;
return 0; /* success */
}
/* pausing... */
void pause() { paused=1; input_module.outMod->Pause(1); }
void unpause() {paused=0; input_module.outMod->Pause(0); }
int ispaused() { return paused; }
/* pause stream */
void pause() {
paused=1;
input_module.outMod->Pause(1);
}
/* stop playback */
/* unpause stream */
void unpause() {
paused=0;
input_module.outMod->Pause(0);
}
/* ispaused? return 1 if paused, 0 if not */
int ispaused() {
return paused;
}
/* stop (unload) stream */
void stop() {
if (decode_thread_handle != INVALID_HANDLE_VALUE) {
decode_abort=1;
@ -265,31 +369,34 @@ void stop() {
input_module.SAVSADeInit();
}
/* get current stream length */
/* get length in ms */
int getlength() {
return stream_length_samples*1000LL/vgmstream->sample_rate;
}
/* get current output time */
/* current output time in ms */
int getoutputtime() {
return decode_pos_ms+(input_module.outMod->GetOutputTime()-input_module.outMod->GetWrittenTime());
}
/* seek */
/* seeks to point in stream (in ms) */
void setoutputtime(int t) {
if (vgmstream)
seek_needed_samples = (long long)t * vgmstream->sample_rate / 1000LL;
}
/* pass these commands through */
void setvolume(int volume) { input_module.outMod->SetVolume(volume); }
void setpan(int pan) { input_module.outMod->SetPan(pan); }
void setvolume(int volume) {
input_module.outMod->SetVolume(volume);
}
void setpan(int pan) {
input_module.outMod->SetPan(pan);
}
/* display information */
int infoDlg(char *fn, HWND hwnd) {
int infoDlg(const in_char *fn, HWND hwnd) {
VGMSTREAM * infostream = NULL;
char description[1024];
description[0]='\0';
char description[1024] = {0};
concatn(sizeof(description),description,PLUGIN_DESCRIPTION "\n\n");
@ -297,7 +404,7 @@ int infoDlg(char *fn, HWND hwnd) {
if (!vgmstream) return 0;
describe_vgmstream(vgmstream,description,sizeof(description));
} else {
infostream = init_vgmstream(fn);
infostream = init_vgmstream((char*)fn);
if (!infostream) return 0;
describe_vgmstream(infostream,description,sizeof(description));
close_vgmstream(infostream);
@ -309,43 +416,44 @@ int infoDlg(char *fn, HWND hwnd) {
}
/* retrieve information on this or possibly another file */
void getfileinfo(char *filename, char *title, int *length_in_ms) {
if (!filename || !*filename) /* currently playing file*/
void getfileinfo(const in_char *filename, in_char *title, int *length_in_ms) {
if (!filename || !*filename) /* no filename = use currently playing file */
{
if (!vgmstream) return;
if (length_in_ms) *length_in_ms=getlength();
if (title)
{
char *p=lastfn+strlen(lastfn);
while (*p != '\\' && p >= lastfn) p--;
strcpy(title,++p);
if (!vgmstream)
return;
if (length_in_ms)
*length_in_ms = getlength();
if (title) {
copy_title(title,GETFILEINFO_TITLE_LENGTH, lastfn);
}
}
else /* some other file */
{
VGMSTREAM * infostream;
if (length_in_ms)
{
if (length_in_ms) {
*length_in_ms=-1000;
if ((infostream=init_vgmstream(filename)))
{
if ((infostream=init_vgmstream(filename))) {
*length_in_ms = get_vgmstream_play_samples(loop_count,fade_seconds,fade_delay_seconds,infostream)*1000LL/infostream->sample_rate;
close_vgmstream(infostream);
infostream=NULL;
}
}
if (title)
{
char *p=filename+strlen(filename);
while (*p != '\\' && p >= filename) p--;
strcpy(title,++p);
if (title) {
copy_title(title,GETFILEINFO_TITLE_LENGTH, filename);
}
}
}
/* nothin' */
void eq_set(int on, char data[10], int preamp) {}
/* eq stuff */
void eq_set(int on, char data[10], int preamp) {
/* nothin' */
}
/* the decode thread */
DWORD WINAPI __stdcall decode(void *arg) {
@ -439,7 +547,7 @@ DWORD WINAPI __stdcall decode(void *arg) {
INT_PTR CALLBACK configDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
char buf[256];
char iniFile[MAX_PATH+1];
char iniFile[WINAMP_MAX_PATH];
static int mypri;
HANDLE hSlider;
@ -587,12 +695,16 @@ INT_PTR CALLBACK configDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara
return TRUE;
}
/* configuration dialog */
void config(HWND hwndParent) {
/* defined in resource.rc */
DialogBox(input_module.hDllInstance, (const char *)IDD_CONFIG, hwndParent, configDlgProc);
}
In_Module input_module =
{
/* *********************************** */
/* main plugin def */
In_Module input_module = {
IN_VER,
PLUGIN_DESCRIPTION,
0, /* hMainWindow */
@ -624,68 +736,6 @@ In_Module input_module =
0 // out_mod
};
__declspec( dllexport ) In_Module * winampGetInModule2()
{
__declspec( dllexport ) In_Module * winampGetInModule2() {
return &input_module;
}
/**
* Creates Winamp's extension list, a single string that ends with \0\0.
* Each extension must be in this format: "extension\0Description\0"
*/
static void build_extension_list() {
const char ** ext_list;
int ext_list_len;
int i;
working_extension_list[0]='\0';
working_extension_list[1]='\0';
ext_list = vgmstream_get_formats();
ext_list_len = vgmstream_get_formats_length();
for (i=0; i < ext_list_len; i++) {
add_extension(EXTENSION_LIST_SIZE, working_extension_list, ext_list[i]);
}
}
/**
* Adds ext to Winamp's extension list.
*/
static void add_extension(int length, char * dst, const char * ext) {
char buf[EXT_BUFFER_SIZE];
char ext_upp[EXT_BUFFER_SIZE];
int ext_len, written;
int i,j;
if (length <= 1)
return;
ext_len = strlen(ext);
/* find end of dst (double \0), saved in i */
for (i=0; i<length-2 && (dst[i] || dst[i+1]); i++)
;
/* check if end reached or not enough room to add */
if (i == length-2 || i + EXT_BUFFER_SIZE+2 > length-2 || ext_len * 3 + 20+2 > EXT_BUFFER_SIZE) {
dst[i]='\0';
dst[i+1]='\0';
return;
}
if (i > 0)
i++;
/* uppercase ext */
for (j=0; j < ext_len; j++)
ext_upp[j] = toupper(ext[j]);
ext_upp[j] = '\0';
/* copy new extension + double null terminate */
written = sprintf(buf, "%s%c%s Audio File (*.%s)%c", ext,'\0',ext_upp,ext_upp,'\0'); /*ex: "vgmstream\0vgmstream Audio File (*.VGMSTREAM)\0" */
for (j=0; j < written; i++,j++)
dst[i] = buf[j];
dst[i]='\0';
dst[i+1]='\0';
}

View File

@ -1,52 +1,73 @@
#ifndef NULLSOFT_OUTH
#define NULLSOFT_OUTH
#include <windows.h>
#include <stddef.h>
// ids:
// waveout: 32
// gapless: 64
// xfade: 63
// disk: 33
// dsound: 38
// NULL: 65
// mm2: 69
#if (_MSC_VER <= 1200)
typedef int intptr_t;
#endif
#define OUT_VER 0x10
typedef struct
{
int version; // module version (OUT_VER)
char *description; // description of module, with version string
int id; // module id. each input module gets its own. non-nullsoft modules should
// be >= 65536.
int version; // module version (OUT_VER)
char *description; // description of module, with version string
intptr_t id; // module id. each input module gets its own. non-nullsoft modules should
// be >= 65536.
HWND hMainWindow; // winamp's main window (filled in by winamp)
HINSTANCE hDllInstance; // DLL instance handle (filled in by winamp)
HWND hMainWindow; // winamp's main window (filled in by winamp)
HINSTANCE hDllInstance; // DLL instance handle (filled in by winamp)
void (*Config)(HWND hwndParent); // configuration dialog
void (*About)(HWND hwndParent); // about dialog
void (*Config)(HWND hwndParent); // configuration dialog
void (*About)(HWND hwndParent); // about dialog
void (*Init)(); // called when loaded
void (*Quit)(); // called when unloaded
void (*Init)(); // called when loaded
void (*Quit)(); // called when unloaded
int (*Open)(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms);
// returns >=0 on success, <0 on failure
// NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins.
// ... so don't expect the max latency returned to be what you asked for.
// returns max latency in ms (0 for diskwriters, etc)
// bufferlenms and prebufferms must be in ms. 0 to use defaults.
// prebufferms must be <= bufferlenms
int (*Open)(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms);
// returns >=0 on success, <0 on failure
void (*Close)(); // close the ol' output device.
// NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins.
// ... so don't expect the max latency returned to be what you asked for.
// returns max latency in ms (0 for diskwriters, etc)
// bufferlenms and prebufferms must be in ms. 0 to use defaults.
// prebufferms must be <= bufferlenms
// pass bufferlenms==-666 to tell the output plugin that it's clock is going to be used to sync video
// out_ds turns off silence-eating when -666 is passed
int (*Write)(char *buf, int len);
// 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data.
// 1 returns not able to write (yet). Non-blocking, always.
void (*Close)(); // close the ol' output device.
int (*CanWrite)(); // returns number of bytes possible to write at a given time.
// Never will decrease unless you call Write (or Close, heh)
int (*Write)(char *buf, int len);
// 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data.
// 1 returns not able to write (yet). Non-blocking, always.
int (*IsPlaying)(); // non0 if output is still going or if data in buffers waiting to be
// written (i.e. closing while IsPlaying() returns 1 would truncate the song
int (*CanWrite)(); // returns number of bytes possible to write at a given time.
// Never will decrease unless you call Write (or Close, heh)
int (*Pause)(int pause); // returns previous pause state
int (*IsPlaying)(); // non0 if output is still going or if data in buffers waiting to be
// written (i.e. closing while IsPlaying() returns 1 would truncate the song
void (*SetVolume)(int volume); // volume is 0-255
void (*SetPan)(int pan); // pan is -128 to 128
int (*Pause)(int pause); // returns previous pause state
void (*Flush)(int t); // flushes buffers and restarts output at time t (in ms)
// (used for seeking)
void (*SetVolume)(int volume); // volume is 0-255
void (*SetPan)(int pan); // pan is -128 to 128
int (*GetOutputTime)(); // returns played time in MS
int (*GetWrittenTime)(); // returns time written in MS (used for synching up vis stuff)
void (*Flush)(int t); // flushes buffers and restarts output at time t (in ms)
// (used for seeking)
int (*GetOutputTime)(); // returns played time in MS
int (*GetWrittenTime)(); // returns time written in MS (used for synching up vis stuff)
} Out_Module;
#endif

File diff suppressed because it is too large Load Diff