mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-18 07:44:43 +01:00
riff wav reading, and .pos (companion to .wav with loop info)
git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@293 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
parent
97ebe328c8
commit
d210bc5bfc
@ -101,6 +101,8 @@ File types supported by this version of vgmstream:
|
||||
- .ivb (PS2 ADPCM)
|
||||
- .amts (GC DSP ADPCM)
|
||||
- .svs (PS2 ADPCM)
|
||||
- .wav (8/16 bit PCM)
|
||||
- .pos (8/16 bit PCM)
|
||||
|
||||
Enjoy!
|
||||
-hcs
|
||||
|
@ -67,7 +67,9 @@ META_OBJS=meta/adx_header.o \
|
||||
meta/ws_aud.o \
|
||||
meta/ahx.o \
|
||||
meta/ivb.o \
|
||||
meta/svs.o
|
||||
meta/svs.o \
|
||||
meta/riff.o \
|
||||
meta/pos.o
|
||||
|
||||
OBJECTS=vgmstream.o streamfile.o util.o $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS)
|
||||
|
||||
|
@ -366,6 +366,14 @@
|
||||
RelativePath=".\meta\svs.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\riff.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\pos.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
|
@ -4,6 +4,6 @@ AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir)
|
||||
AM_MAKEFLAGS=-f Makefile.unix
|
||||
|
||||
libmeta_la_LDFLAGS =
|
||||
libmeta_la_SOURCES = Cstr.c adx_header.c afc_header.c agsc.c ast.c brstm.c ea_header.c gcsw.c halpst.c nds_strm.c ngc_adpdtk.c ngc_caf.c ngc_dsp_std.c ps2_ads.c ps2_exst.c ps2_ild.c ps2_int.c ps2_mib.c ps2_mic.c ps2_npsf.c ps2_pnb.c ps2_rxw.c ps2_str.c ps2_svag.c ps2_vag.c ps2_vpk.c psx_cdxa.c raw.c rs03.c rsf.c rwsd.c psx_gms.c xbox_xwav.c xbox_wavm.c genh.c ogg_vorbis_file.c ps2_bmdx.c aifc.c str_snds.c ws_aud.c ahx.c ivb.c svs.c
|
||||
libmeta_la_SOURCES = Cstr.c adx_header.c afc_header.c agsc.c ast.c brstm.c ea_header.c gcsw.c halpst.c nds_strm.c ngc_adpdtk.c ngc_caf.c ngc_dsp_std.c ps2_ads.c ps2_exst.c ps2_ild.c ps2_int.c ps2_mib.c ps2_mic.c ps2_npsf.c ps2_pnb.c ps2_rxw.c ps2_str.c ps2_svag.c ps2_vag.c ps2_vpk.c psx_cdxa.c raw.c rs03.c rsf.c rwsd.c psx_gms.c xbox_xwav.c xbox_wavm.c genh.c ogg_vorbis_file.c ps2_bmdx.c aifc.c str_snds.c ws_aud.c ahx.c ivb.c svs.c riff.c pos.c
|
||||
|
||||
EXTRA_DIST = meta.h
|
||||
|
@ -107,4 +107,8 @@ VGMSTREAM * init_vgmstream_ivb(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_svs(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_riff(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_pos(STREAMFILE * streamFile);
|
||||
|
||||
#endif
|
||||
|
58
src/meta/pos.c
Normal file
58
src/meta/pos.c
Normal file
@ -0,0 +1,58 @@
|
||||
#include <ctype.h>
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#define DIRSEP '\\'
|
||||
#else
|
||||
#define DIRSEP '/'
|
||||
#endif
|
||||
|
||||
/* .pos is a tiny file with loop points, and the same base name as a .wav */
|
||||
|
||||
VGMSTREAM * init_vgmstream_pos(STREAMFILE *streamFile) {
|
||||
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamFileWAV = NULL;
|
||||
char filename[260];
|
||||
char filenameWAV[260];
|
||||
|
||||
int i;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("pos",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check for .WAV file */
|
||||
strcpy(filenameWAV,filename);
|
||||
strcpy(filenameWAV+strlen(filenameWAV)-3,"wav");
|
||||
for (i=strlen(filenameWAV);i>=0&&filenameWAV[i]!=DIRSEP;i--)
|
||||
filenameWAV[i]=toupper(filenameWAV[i]);
|
||||
|
||||
streamFileWAV = streamFile->open(streamFile,filenameWAV,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!streamFileWAV) goto fail;
|
||||
|
||||
/* let the real initer do the parsing */
|
||||
vgmstream = init_vgmstream_riff(streamFileWAV);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* install loops */
|
||||
if (!vgmstream->loop_flag) {
|
||||
vgmstream->loop_flag = 1;
|
||||
vgmstream->loop_ch = calloc(vgmstream->channels,
|
||||
sizeof(VGMSTREAMCHANNEL));
|
||||
if (!vgmstream->loop_ch) goto fail;
|
||||
}
|
||||
|
||||
vgmstream->loop_start_sample = read_32bitLE(0,streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitLE(4,streamFile);
|
||||
vgmstream->meta_type = meta_RIFF_WAVE_POS;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (streamFileWAV) close_streamfile(streamFileWAV);
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
154
src/meta/riff.c
Normal file
154
src/meta/riff.c
Normal file
@ -0,0 +1,154 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* Resource Interchange File Format */
|
||||
/* only the bare minimum needed to read PCM wavs */
|
||||
|
||||
VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[260];
|
||||
|
||||
off_t file_size = -1;
|
||||
int channel_count = 0;
|
||||
int sample_count = 0;
|
||||
int sample_rate = 0;
|
||||
int coding_type = -1;
|
||||
off_t start_offset = -1;
|
||||
int interleave = -1;
|
||||
|
||||
int loop_flag = 0;
|
||||
int32_t loop_start = -1;
|
||||
int32_t loop_end = -1;
|
||||
uint32_t riff_size;
|
||||
uint32_t data_size = 0;
|
||||
|
||||
int FormatChunkFound = 0;
|
||||
int DataChunkFound = 0;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("wav",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if ((uint32_t)read_32bitBE(0,streamFile)!=0x52494646) /* "RIFF" */
|
||||
goto fail;
|
||||
/* check for WAVE form */
|
||||
if ((uint32_t)read_32bitBE(8,streamFile)!=0x57415645) /* "WAVE" */
|
||||
goto fail;
|
||||
|
||||
riff_size = read_32bitLE(4,streamFile);
|
||||
file_size = get_streamfile_size(streamFile);
|
||||
|
||||
/* check for tructated RIFF */
|
||||
if (file_size < riff_size+8) goto fail;
|
||||
|
||||
/* read through chunks to verify format and find metadata */
|
||||
{
|
||||
off_t current_chunk = 0xc; /* start with first chunk */
|
||||
|
||||
while (current_chunk < file_size) {
|
||||
uint32_t chunk_type = read_32bitBE(current_chunk,streamFile);
|
||||
off_t chunk_size = read_32bitLE(current_chunk+4,streamFile);
|
||||
|
||||
if (current_chunk+8+chunk_size > file_size) goto fail;
|
||||
|
||||
switch(chunk_type) {
|
||||
case 0x666d7420: /* "fmt " */
|
||||
/* only one per file */
|
||||
if (FormatChunkFound) goto fail;
|
||||
FormatChunkFound = 1;
|
||||
|
||||
sample_rate = read_32bitLE(current_chunk+0x0c,streamFile);
|
||||
channel_count = read_16bitLE(current_chunk+0x0a,streamFile);
|
||||
|
||||
switch (read_16bitLE(current_chunk+0x8,streamFile)) {
|
||||
case 1: /* PCM */
|
||||
switch (read_16bitLE(current_chunk+0x16,streamFile)) {
|
||||
case 16:
|
||||
coding_type = coding_PCM16LE;
|
||||
interleave = 2;
|
||||
break;
|
||||
case 8:
|
||||
coding_type = coding_PCM8;
|
||||
interleave = 1;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case 0x64617461: /* data */
|
||||
/* at most one per file */
|
||||
if (DataChunkFound) goto fail;
|
||||
DataChunkFound = 1;
|
||||
|
||||
start_offset = current_chunk + 8;
|
||||
data_size = chunk_size;
|
||||
break;
|
||||
default:
|
||||
/* ignorance is bliss */
|
||||
break;
|
||||
}
|
||||
|
||||
current_chunk += 8+chunk_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (!FormatChunkFound || !DataChunkFound) goto fail;
|
||||
|
||||
switch (coding_type) {
|
||||
case coding_PCM16LE:
|
||||
sample_count = data_size/2/channel_count;
|
||||
break;
|
||||
case coding_PCM8:
|
||||
sample_count = data_size/channel_count;
|
||||
break;
|
||||
}
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
printf("channel_count = %d, loop_flag = %d\n",channel_count,loop_flag);
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->num_samples = sample_count;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
vgmstream->coding_type = coding_type;
|
||||
if (channel_count > 1)
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
else
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
|
||||
vgmstream->meta_type = meta_RIFF_WAVE;
|
||||
|
||||
/* open the file, set up each channel */
|
||||
{
|
||||
int i;
|
||||
|
||||
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,
|
||||
STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!vgmstream->ch[0].streamfile) goto fail;
|
||||
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile;
|
||||
vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset =
|
||||
start_offset+i*interleave;
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -69,6 +69,8 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_ivb,
|
||||
init_vgmstream_amts,
|
||||
init_vgmstream_svs,
|
||||
init_vgmstream_riff,
|
||||
init_vgmstream_pos,
|
||||
};
|
||||
|
||||
#define INIT_VGMSTREAM_FCNS (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0]))
|
||||
@ -1106,6 +1108,12 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
||||
case meta_PS2_SVS:
|
||||
snprintf(temp,TEMPSIZE,"Square SVS header");
|
||||
break;
|
||||
case meta_RIFF_WAVE:
|
||||
snprintf(temp,TEMPSIZE,"RIFF WAVE header");
|
||||
break;
|
||||
case meta_RIFF_WAVE_POS:
|
||||
snprintf(temp,TEMPSIZE,"RIFF WAVE header and .pos for looping");
|
||||
break;
|
||||
default:
|
||||
snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET");
|
||||
}
|
||||
|
@ -180,6 +180,8 @@ typedef enum {
|
||||
#ifdef VGM_USE_MPEG
|
||||
meta_AHX, /* CRI AHX header (same structure as ADX) */
|
||||
#endif
|
||||
meta_RIFF_WAVE, /* RIFF, for WAVs */
|
||||
meta_RIFF_WAVE_POS, /* .wav + .pos for looping */
|
||||
} meta_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -67,6 +67,7 @@ gchar *vgmstream_exts [] = {
|
||||
"ivb",
|
||||
"amts",
|
||||
"svs",
|
||||
"pos",
|
||||
/* terminator */
|
||||
NULL
|
||||
};
|
||||
|
@ -125,6 +125,7 @@ char * extension_list[] = {
|
||||
"ivb\0IVB Audio File (*.IVB)\0",
|
||||
"amts\0AMTS Audio File (*.AMTS)\0",
|
||||
"svs\0SVS Audio File (*.SVS)\0",
|
||||
"pos\0POS Audio File (*.POS)\0",
|
||||
};
|
||||
|
||||
void about(HWND hwndParent) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user