ref: a2c587e7d7a8b72a7ef9afcd119d8cfb20076b54
dir: /wav.c/
#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;
loopsamples = 0;
info->loopofs = -1;
for(; sz >= 8;){
p += 4; sz -= 4;
n = le32(p); sz -= 4;
if(n > sz || n <= 0)
break;
if(n < 4)
goto skip;
if(memcmp(p-8, "fmt ", 4) == 0){
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 < 1 || (info->width % 8) != 0){
werrstr("invalid width: %d", info->width);
return -1;
}
info->width /= 8;
}else 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){
if(info->width < 1){
werrstr("cue chunk before fmt");
return -1;
}
p += 5*4; sz -= 5*4; n -= 5*4; /* Name+Position+Chunk+ChunkStart+BlockStart */
loopsamples = info->loopofs + le32(p); sz -= 4; n -= 4;
if(loopsamples > info->samples) /* eg "nehahra/sounds/vondur/fan1.wav" */
loopsamples = info->samples;
}
}
}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;
}
}
skip:
n = (n + 1) & ~1;
p += n; sz -= n;
}
if(info->width < 1 || info->channels < 1 || info->rate < 1){
werrstr("invalid/missing fmt chunk?");
return -1;
}
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;
}