ref: bb5d36fa55021e81d20e8cd1309c6a163b4fe498
parent: 76563314d19e01997f1a03bf81c14ccdf6d86300
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Sat Dec 23 13:36:20 EST 2023
move GetWavinfo to its own file
--- a/Makefile
+++ b/Makefile
@@ -92,6 +92,7 @@
unix/snd_sdl.o\
unix/vid.o\
view.o\
+ wav.o\
world.o\
zone.o\
--- a/dat.h
+++ b/dat.h
@@ -12,11 +12,22 @@
};
typedef struct Sfx Sfx;
+typedef struct wavinfo_t wavinfo_t;
struct Sfx {
char s[Npath];
int map;
mem_user_t cu;
+};
+
+struct wavinfo_t
+{
+ int rate;
+ int width;
+ int channels;
+ int loopofs;
+ int samples;
+ int dataofs;
};
extern char *game;
--- a/fns.h
+++ b/fns.h
@@ -64,3 +64,5 @@
void sndwrite(uchar *buf, long sz);
void sndclose(void);
int sndopen(void);
+
+int wavinfo(byte *in, int len, wavinfo_t *info);
--- a/mkfile
+++ b/mkfile
@@ -85,6 +85,7 @@
sv_user.$O\
vid.$O\
view.$O\
+ wav.$O\
world.$O\
zone.$O\
--- a/snd.c
+++ b/snd.c
@@ -51,16 +51,6 @@
byte data[1]; // variable sized
} sfxcache_t;
-typedef struct
-{
- int rate;
- int width;
- int channels;
- int loopofs;
- int samples;
- int dataofs;
-} wavinfo_t;
-
static vec3_t listener_origin;
static vec3_t listener_forward;
static vec3_t listener_right;
@@ -127,161 +117,6 @@
}
}
-static short
-GetLittleShort(void)
-{
- short val;
-
- val = *data_p;
- val = val + (*(data_p+1)<<8);
- data_p += 2;
- return val;
-}
-
-static int
-GetLittleLong(void)
-{
- int val;
-
- val = *data_p;
- val = val + (*(data_p+1)<<8);
- val = val + (*(data_p+2)<<16);
- val = val + (*(data_p+3)<<24);
- data_p += 4;
- return val;
-}
-
-static void
-FindNextChunk(char *name)
-{
- int iff_chunk_len;
-
- while (1)
- {
- data_p=last_chunk;
-
- if (data_p >= iff_end)
- { // didn't find the chunk
- data_p = nil;
- return;
- }
-
- data_p += 4;
- iff_chunk_len = GetLittleLong();
- if (iff_chunk_len < 0)
- {
- data_p = nil;
- return;
- }
-// if (iff_chunk_len > 1024*1024)
-// fatal ("FindNextChunk: %d length is past the 1 meg sanity limit", iff_chunk_len);
- data_p -= 8;
- last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
- if(strncmp((char *)data_p, name, 4) == 0)
- return;
- }
-}
-
-static void
-FindChunk(char *name)
-{
- last_chunk = iff_data;
- FindNextChunk (name);
-}
-
-static wavinfo_t
-GetWavinfo(char *name, byte *wav, vlong wavlength)
-{
- wavinfo_t info;
- int i;
- int format;
- int samples;
-
- memset(&info, 0, sizeof info);
-
- if (!wav)
- return info;
-
- iff_data = wav;
- iff_end = wav + wavlength;
-
-// find "RIFF" chunk
- FindChunk("RIFF");
- if(!(data_p && strncmp((char *)data_p+8, "WAVE", 4) == 0))
- {
- Con_Printf("Missing RIFF/WAVE chunks\n");
- return info;
- }
-
-// get "fmt " chunk
- iff_data = data_p + 12;
-
- FindChunk("fmt ");
- if (!data_p)
- {
- Con_Printf("Missing fmt chunk\n");
- return info;
- }
- data_p += 8;
- format = GetLittleShort();
- if (format != 1)
- {
- Con_Printf("Microsoft PCM format only\n");
- return info;
- }
-
- info.channels = GetLittleShort();
- info.rate = GetLittleLong();
- data_p += 4+2;
- info.width = GetLittleShort() / 8;
-
-// get cue chunk
- FindChunk("cue ");
- if (data_p)
- {
- data_p += 32;
- info.loopofs = GetLittleLong();
-
- // if the next chunk is a LIST chunk, look for a cue length marker
- FindNextChunk ("LIST");
- if (data_p)
- {
- if(strncmp((char *)data_p+28, "mark", 4) == 0)
- { // this is not a proper parse, but it works with cooledit...
- data_p += 24;
- i = GetLittleLong (); // samples in loop
- info.samples = info.loopofs + i;
-// Con_Printf("looped length: %d\n", i);
- }
- }
- }
- else
- info.loopofs = -1;
-
-// find data chunk
- FindChunk("data");
- if (!data_p)
- {
- Con_Printf("Missing data chunk\n");
- return info;
- }
-
- data_p += 4;
- samples = GetLittleLong () / info.width;
-
- if (info.samples)
- {
- if (samples < info.samples)
- fatal ("Sound %s has a bad loop length", name);
- }
- else
- info.samples = samples;
-
- info.dataofs = data_p - wav;
-
- return info;
-}
-
static sfxcache_t *
loadsfx(Sfx *sfx)
{
@@ -298,7 +133,10 @@
Con_DPrintf("loadsfx: %r\n");
return nil;
}
- info = GetWavinfo(sfx->s, u, len);
+ if(wavinfo(u, len, &info) != 0){
+ Con_Printf("loadsfx: %s: %s\n", sfx->s, lerr());
+ return nil;
+ }
if(info.channels != 1){
Con_DPrintf("loadsfx: non mono wave %s\n", sfx->s);
return nil;
--- /dev/null
+++ b/wav.c
@@ -1,0 +1,92 @@
+#include "quakedef.h"
+
+int
+wavinfo(byte *in, int len, wavinfo_t *info)
+{
+ int i, n, sz, fmt, loopsamples;
+ byte *p;
+
+ memset(info, 0, sizeof(*info));
+
+ p = in;
+ if(len < 36 || memcmp(p, "RIFF", 4) != 0){
+ werrstr("not a RIFF");
+ return -1;
+ }
+ p += 4; len -= 4;
+ sz = le32(p); len -= 4;
+ if(sz < 36 || sz > len){
+ werrstr("trucated? sz=%d len=%d", sz, len);
+ return -1;
+ }
+ if(memcmp(p, "WAVE", 4) != 0){
+ werrstr("not a WAVE");
+ return -1;
+ }
+ p += 4; sz -= 4;
+ if(memcmp(p, "fmt ", 4) != 0){
+ werrstr("no \"fmt \" subchunk");
+ return -1;
+ }
+ p += 4; sz -= 4;
+ n = le32(p); sz -= 4;
+
+ fmt = le16(p); sz -= 2; n -= 2;
+ if(fmt != 1){
+ werrstr("not Microsoft PCM format: %d", fmt);
+ return -1;
+ }
+ info->channels = le16(p); sz -= 2; n -= 2;
+ info->rate = le32(p); sz -= 4; n -= 4;
+ p += 4+2; sz -= 4+2; n -= 4+2; /* skip ByteRate + BlockAlign */
+ info->width = le16(p); sz -= 2; n -= 2;
+ if((info->width % 8) != 0){
+ werrstr("invalid width: %d", info->width);
+ return -1;
+ }
+ info->width /= 8;
+ info->loopofs = -1;
+ loopsamples = 0;
+ p += n; sz -= n;
+
+ for(; sz >= 8;){
+ p += 4; sz -= 4;
+ n = le32(p); sz -= 4;
+ if(n > sz || n <= 0)
+ break;
+ if(n >= 4){
+ if(memcmp(p-8, "cue ", 4) == 0){
+ i = le32(p); sz -= 4; n -= 4; /* CuePoints - usually two of those */
+ if(i >= 1 && n >= i*6*4){
+ p += 5*4; sz -= 5*4; n -= 5*4; /* Name+Position+Chunk+ChunkStart+BlockStart */
+ info->loopofs = le32(p); sz -= 4; n -= 4;
+ /* FIXME(sigrid): check if this is needed and whether it works at all */
+ if(i > 1){
+ p += 5*4; sz -= 5*4; n -= 5*4; /* Name+Position+Chunk+ChunkStart+BlockStart */
+ loopsamples = info->loopofs + le32(p); sz -= 4; n -= 4;
+ }
+ }
+ }else if(memcmp(p-8, "data", 4) == 0 && info->dataofs == 0){
+ info->samples = n / info->width;
+ info->dataofs = p - in;
+ }else if(memcmp(p-8, "LIST", 4) == 0 && info->loopofs >= 0 && loopsamples == 0){
+ p += 4; sz -= 4; n -= 4; /* skip "adtl" */
+ if(n >= 20 && memcmp(p, "ltxt", 4) == 0 && memcmp(p+16, "mark", 4) == 0){
+ p += 12; sz -= 12; n -= 12;
+ loopsamples = info->loopofs + le32(p); sz -= 4; n -= 4;
+ }
+ }
+ }
+ n = (n + 1) & ~1;
+ p += n; sz -= n;
+ }
+
+ if(loopsamples > info->samples || info->loopofs > info->samples){
+ werrstr("invalid loop: (%d,%d) > %d", info->loopofs, loopsamples, info->samples);
+ return -1;
+ }
+ if(loopsamples > 0)
+ info->samples = loopsamples;
+
+ return 0;
+}