diff --git a/readme.txt b/readme.txt
index 68e89af9..d2a59ef0 100644
--- a/readme.txt
+++ b/readme.txt
@@ -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
diff --git a/src/Makefile b/src/Makefile
index d1ef4933..11f085c5 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -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)
diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj
index 682bc7f5..6b0c03d7 100644
--- a/src/libvgmstream.vcproj
+++ b/src/libvgmstream.vcproj
@@ -366,6 +366,14 @@
RelativePath=".\meta\svs.c"
>
+
+
+
+
+#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;
+}
diff --git a/src/meta/riff.c b/src/meta/riff.c
new file mode 100644
index 00000000..a719a58f
--- /dev/null
+++ b/src/meta/riff.c
@@ -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;ich[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;
+}
diff --git a/src/vgmstream.c b/src/vgmstream.c
index 10165576..be6d1324 100644
--- a/src/vgmstream.c
+++ b/src/vgmstream.c
@@ -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");
}
diff --git a/src/vgmstream.h b/src/vgmstream.h
index 325048ff..7e4381d1 100644
--- a/src/vgmstream.h
+++ b/src/vgmstream.h
@@ -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 {
diff --git a/unix/data.c b/unix/data.c
index 0342fab2..a2ce1cca 100644
--- a/unix/data.c
+++ b/unix/data.c
@@ -67,6 +67,7 @@ gchar *vgmstream_exts [] = {
"ivb",
"amts",
"svs",
+ "pos",
/* terminator */
NULL
};
diff --git a/winamp/in_vgmstream.c b/winamp/in_vgmstream.c
index 462cd53c..6284d497 100644
--- a/winamp/in_vgmstream.c
+++ b/winamp/in_vgmstream.c
@@ -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) {