mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-17 22:50:51 +00:00
half way though the sfx loader re-write. nothing works :)
This commit is contained in:
parent
e5a23c95dc
commit
ccb56eea39
8 changed files with 440 additions and 578 deletions
|
@ -31,11 +31,9 @@
|
|||
#define _SOUND_H
|
||||
|
||||
#include "QF/mathlib.h"
|
||||
#include "QF/quakeio.h"
|
||||
#include "QF/zone.h"
|
||||
|
||||
#define AMBIENT_WATER 0
|
||||
#define AMBIENT_SKY 1
|
||||
#define AMBIENT_SKY 1
|
||||
#define AMBIENT_SLIME 2
|
||||
#define AMBIENT_LAVA 3
|
||||
#define NUM_AMBIENTS 4 // automatic ambient sounds
|
||||
|
@ -43,11 +41,23 @@
|
|||
#define DEFAULT_SOUND_PACKET_VOLUME 255
|
||||
#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
|
||||
|
||||
typedef struct sfx_s
|
||||
typedef struct sfx_s sfx_t;
|
||||
struct sfx_s
|
||||
{
|
||||
char name[MAX_QPATH];
|
||||
cache_user_t cache;
|
||||
} sfx_t;
|
||||
const char *name;
|
||||
|
||||
int length;
|
||||
int loopstart;
|
||||
int speed;
|
||||
int width;
|
||||
int channels;
|
||||
|
||||
void *data;
|
||||
|
||||
struct sfxbuffer_s *(*touch) (sfx_t *sfx);
|
||||
struct sfxbuffer_s *(*retain) (sfx_t *sfx);
|
||||
void (*release) (sfx_t *sfx);
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -117,6 +127,7 @@ extern struct cvar_s *snd_loadas8bit;
|
|||
extern struct cvar_s *bgmvolume;
|
||||
extern struct cvar_s *volume;
|
||||
|
||||
extern struct cvar_s *snd_mixahead;
|
||||
extern struct cvar_s *snd_device;
|
||||
extern struct cvar_s *snd_rate;
|
||||
extern struct cvar_s *snd_bits;
|
||||
|
|
|
@ -32,25 +32,41 @@
|
|||
#ifndef __snd_render_h
|
||||
#define __snd_render_h
|
||||
|
||||
#include "QF/zone.h"
|
||||
|
||||
// !!! if this is changed, it must be changed in asm_i386.h too !!!
|
||||
typedef struct portable_samplepair_s {
|
||||
int left;
|
||||
int right;
|
||||
} portable_samplepair_t;
|
||||
|
||||
// !!! if this is changed, it much be changed in asm_i386.h too !!!
|
||||
typedef struct sfxcache_s {
|
||||
int length;
|
||||
int loopstart;
|
||||
int speed;
|
||||
int width;
|
||||
int stereo;
|
||||
int bytes;
|
||||
byte data[4]; // variable sized
|
||||
} sfxcache_t;
|
||||
typedef struct channel_s channel_t;
|
||||
typedef struct sfxbuffer_s sfxbuffer_t;
|
||||
struct sfxbuffer_s {
|
||||
int head; // ring buffer head position in sampels
|
||||
int tail; // ring buffer tail position in sampels
|
||||
int length; // length of buffer in samples
|
||||
int pos; // position of tail within full stream
|
||||
void (*paint) (channel_t *ch, sfxbuffer_t *buffer, int count);
|
||||
void (*advance) (sfxbuffer_t *buffer, int count);
|
||||
byte data[4];
|
||||
};
|
||||
|
||||
typedef struct sfxstream_s {
|
||||
sfx_t *sfx;
|
||||
void *file;
|
||||
sfxbuffer_t buffer;
|
||||
} sfxstream_t;
|
||||
|
||||
typedef struct sfxblock_s {
|
||||
sfx_t *sfx;
|
||||
const char *file;
|
||||
int bytes;
|
||||
cache_user_t cache;
|
||||
} sfxblock_t;
|
||||
|
||||
// !!! if this is changed, it much be changed in asm_i386.h too !!!
|
||||
typedef struct channel_s {
|
||||
struct channel_s {
|
||||
sfx_t *sfx; // sfx number
|
||||
int leftvol; // 0-255 volume
|
||||
int rightvol; // 0-255 volume
|
||||
|
@ -64,7 +80,7 @@ typedef struct channel_s {
|
|||
int master_vol; // 0-255 master volume
|
||||
int phase; // phase shift between l-r in samples
|
||||
int oldphase; // phase shift between l-r in samples
|
||||
} channel_t;
|
||||
};
|
||||
|
||||
typedef struct wavinfo_s {
|
||||
int rate;
|
||||
|
@ -99,9 +115,9 @@ void SND_LocalSound (const char *s);
|
|||
void SND_BlockSound (void);
|
||||
void SND_UnblockSound (void);
|
||||
|
||||
void SND_ResampleSfx (sfxcache_t *sc, byte * data);
|
||||
sfxcache_t *SND_GetCache (long samples, int rate, int inwidth, int channels,
|
||||
sfx_t *sfx, cache_allocator_t allocator);
|
||||
void SND_ResampleSfx (sfx_t *sfx, sfxbuffer_t *sc, byte *data);
|
||||
sfxbuffer_t *SND_GetCache (long samples, int rate, int inwidth, int channels,
|
||||
sfxblock_t *block, cache_allocator_t allocator);
|
||||
|
||||
void SND_InitScaletable (void);
|
||||
// picks a channel based on priorities, empty slots, number of channels
|
||||
|
@ -109,15 +125,21 @@ channel_t *SND_PickChannel(int entnum, int entchannel);
|
|||
// spatializes a channel
|
||||
void SND_Spatialize(channel_t *ch);
|
||||
|
||||
void SND_Load (sfx_t *sfx);
|
||||
void SND_CallbackLoad (void *object, cache_allocator_t allocator);
|
||||
sfxcache_t *SND_LoadOgg (QFile *file, sfx_t *sfx, cache_allocator_t allocator);
|
||||
wavinfo_t SND_GetWavinfo (const char *name, byte * wav, int wavlength);
|
||||
void SND_LoadOgg (QFile *file, sfx_t *sfx, char *realname);
|
||||
void SND_LoadWav (QFile *file, sfx_t *sfx, char *realname);
|
||||
|
||||
sfxbuffer_t *SND_CacheRetain (sfx_t *sfx);
|
||||
void SND_CacheRelease (sfx_t *sfx);
|
||||
sfxbuffer_t *SND_StreamRetain (sfx_t *sfx);
|
||||
void SND_StreamRelease (sfx_t *sfx);
|
||||
|
||||
void SND_WriteLinearBlastStereo16 (void);
|
||||
void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count);
|
||||
void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count);
|
||||
void SND_PaintChannelStereo8 (channel_t *ch, sfxcache_t *sc, int count);
|
||||
void SND_PaintChannelStereo16 (channel_t *ch, sfxcache_t *sc, int count);
|
||||
void SND_PaintChannelFrom8 (channel_t *ch, sfxbuffer_t *sc, int count);
|
||||
void SND_PaintChannelFrom16 (channel_t *ch, sfxbuffer_t *sc, int count);
|
||||
void SND_PaintChannelStereo8 (channel_t *ch, sfxbuffer_t *sc, int count);
|
||||
void SND_PaintChannelStereo16 (channel_t *ch, sfxbuffer_t *sc, int count);
|
||||
|
||||
wavinfo_t GetWavinfo (const char *name, byte *wav, int wavlength);
|
||||
|
||||
|
|
|
@ -10,25 +10,14 @@ EXEEXT=
|
|||
plugin_PROGRAMS= @SND_REND_TARGETS@
|
||||
EXTRA_PROGRAMS= snd_render_default.la
|
||||
|
||||
if ASM_ARCH
|
||||
asm= libasm.la
|
||||
else
|
||||
asm=
|
||||
endif
|
||||
|
||||
noinst_LTLIBRARIES= $(asm)
|
||||
noinst_PROGRAMS= @SND_REND_STATIC@
|
||||
|
||||
libasm_la_SOURCES= snd_mixa.S
|
||||
|
||||
snd_render_default_la_LDFLAGS= $(plugin_ldflags)
|
||||
snd_render_default_la_SOURCES= snd_dma.c snd_mem.c snd_mix.c vorbis.c
|
||||
snd_render_default_la_SOURCES= snd_dma.c snd_mem.c snd_mix.c vorbis.c wav.c
|
||||
if ASM_ARCH
|
||||
snd_render_default_la_LDADD= $(asm) $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(OGG_LIBS)
|
||||
snd_render_default_la_DEPENDENCIES= $(asm)
|
||||
snd_render_default_la_LDADD= $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(OGG_LIBS)
|
||||
snd_render_default_la_DEPENDENCIES=
|
||||
else
|
||||
snd_render_default_la_LDADD= $(VORBISFILE_LIBS) $(VORBIS_LIBS) $(OGG_LIBS)
|
||||
snd_render_default_la_DEPENDENCIES=
|
||||
endif
|
||||
|
||||
EXTRA_DIST= $(libasm_la_SOURCES)
|
||||
|
|
|
@ -176,7 +176,7 @@ SND_FindName (const char *name)
|
|||
|
||||
// see if already loaded
|
||||
for (i = 0; i < num_sfx; i++)
|
||||
if (!strcmp (known_sfx[i].name, name)) {
|
||||
if (known_sfx[i].name && !strcmp (known_sfx[i].name, name)) {
|
||||
return &known_sfx[i];
|
||||
}
|
||||
|
||||
|
@ -184,8 +184,10 @@ SND_FindName (const char *name)
|
|||
Sys_Error ("S_FindName: out of sfx_t");
|
||||
|
||||
sfx = &known_sfx[i];
|
||||
strcpy (sfx->name, name);
|
||||
Cache_Add (&sfx->cache, sfx, SND_CallbackLoad);
|
||||
if (sfx->name)
|
||||
free ((char *) sfx->name);
|
||||
sfx->name = strdup (name);
|
||||
SND_Load (sfx);
|
||||
|
||||
num_sfx++;
|
||||
|
||||
|
@ -201,7 +203,7 @@ SND_TouchSound (const char *name)
|
|||
return;
|
||||
|
||||
sfx = SND_FindName (name);
|
||||
Cache_Check (&sfx->cache);
|
||||
sfx->touch (sfx);
|
||||
}
|
||||
|
||||
sfx_t *
|
||||
|
@ -215,10 +217,10 @@ SND_PrecacheSound (const char *name)
|
|||
sfx = SND_FindName (name);
|
||||
|
||||
// cache it in
|
||||
if (precache->int_val)
|
||||
if (Cache_TryGet (&sfx->cache))
|
||||
Cache_Release (&sfx->cache);
|
||||
|
||||
if (precache->int_val) {
|
||||
if (sfx->retain (sfx))
|
||||
sfx->release (sfx);
|
||||
}
|
||||
return sfx;
|
||||
}
|
||||
|
||||
|
@ -316,7 +318,6 @@ SND_StartSound (int entnum, int entchannel, sfx_t *sfx, const vec3_t origin,
|
|||
{
|
||||
int ch_idx, skip, vol;
|
||||
channel_t *target_chan, *check;
|
||||
sfxcache_t *sc;
|
||||
|
||||
if (!sound_started)
|
||||
return;
|
||||
|
@ -347,16 +348,15 @@ SND_StartSound (int entnum, int entchannel, sfx_t *sfx, const vec3_t origin,
|
|||
return; // not audible at all
|
||||
|
||||
// new channel
|
||||
sc = Cache_TryGet (&sfx->cache);
|
||||
if (!sc) {
|
||||
if (!sfx->retain (sfx)) {
|
||||
target_chan->sfx = NULL;
|
||||
return; // couldn't load the sound's data
|
||||
return; // couldn't load the sound's data
|
||||
}
|
||||
|
||||
target_chan->sfx = sfx;
|
||||
target_chan->pos = 0.0;
|
||||
target_chan->end = paintedtime + sc->length;
|
||||
Cache_Release (&sfx->cache);
|
||||
target_chan->end = paintedtime + sfx->length;
|
||||
sfx->release (sfx);
|
||||
|
||||
// if an identical sound has also been started this frame, offset the pos
|
||||
// a bit to keep it from just making the first one louder
|
||||
|
@ -444,7 +444,6 @@ SND_StaticSound (sfx_t *sfx, const vec3_t origin, float vol,
|
|||
float attenuation)
|
||||
{
|
||||
channel_t *ss;
|
||||
sfxcache_t *sc;
|
||||
|
||||
if (!sound_started || !sfx)
|
||||
return;
|
||||
|
@ -457,13 +456,12 @@ SND_StaticSound (sfx_t *sfx, const vec3_t origin, float vol,
|
|||
ss = &channels[total_channels];
|
||||
total_channels++;
|
||||
|
||||
sc = Cache_TryGet (&sfx->cache);
|
||||
if (!sc)
|
||||
if (!sfx->retain (sfx))
|
||||
return;
|
||||
|
||||
if (sc->loopstart == -1) {
|
||||
if (sfx->loopstart == -1) {
|
||||
Sys_Printf ("Sound %s not looped\n", sfx->name);
|
||||
Cache_Release (&sfx->cache);
|
||||
sfx->release (sfx);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -471,8 +469,8 @@ SND_StaticSound (sfx_t *sfx, const vec3_t origin, float vol,
|
|||
VectorCopy (origin, ss->origin);
|
||||
ss->master_vol = vol;
|
||||
ss->dist_mult = (attenuation / 64) / sound_nominal_clip_dist;
|
||||
ss->end = paintedtime + sc->length;
|
||||
Cache_Release (&sfx->cache);
|
||||
ss->end = paintedtime + sfx->length;
|
||||
sfx->release (sfx);
|
||||
|
||||
SND_Spatialize (ss);
|
||||
ss->oldphase = ss->phase;
|
||||
|
@ -736,9 +734,8 @@ SND_PlayVol (void)
|
|||
static void
|
||||
SND_SoundList (void)
|
||||
{
|
||||
int load, size, total, i;
|
||||
int load, total, i;
|
||||
sfx_t *sfx;
|
||||
sfxcache_t *sc;
|
||||
|
||||
if (Cmd_Argc() >= 2 && Cmd_Argv (1)[0])
|
||||
load = 1;
|
||||
|
@ -747,23 +744,17 @@ SND_SoundList (void)
|
|||
|
||||
total = 0;
|
||||
for (sfx = known_sfx, i = 0; i < num_sfx; i++, sfx++) {
|
||||
if (load)
|
||||
sc = Cache_TryGet (&sfx->cache);
|
||||
else
|
||||
sc = Cache_Check (&sfx->cache);
|
||||
|
||||
if (!sc)
|
||||
continue;
|
||||
size = sc->length * sc->width * (sc->stereo + 1);
|
||||
total += size;
|
||||
if (sc->loopstart >= 0)
|
||||
Sys_Printf ("L");
|
||||
else
|
||||
Sys_Printf (" ");
|
||||
Sys_Printf ("(%2db) %6i : %s\n", sc->width * 8, size, sfx->name);
|
||||
if (load) {
|
||||
if (!sfx->retain (sfx))
|
||||
continue;
|
||||
} else {
|
||||
if (!sfx->touch (sfx))
|
||||
continue;
|
||||
}
|
||||
total += sfx->length;
|
||||
|
||||
if (load)
|
||||
Cache_Release (&sfx->cache);
|
||||
sfx->release (sfx);
|
||||
}
|
||||
Sys_Printf ("Total resident: %i\n", total);
|
||||
}
|
||||
|
|
|
@ -45,44 +45,121 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include "QF/qendian.h"
|
||||
#include "QF/quakefs.h"
|
||||
|
||||
#include "compat.h"
|
||||
#include "snd_render.h"
|
||||
|
||||
int cache_full_cycle;
|
||||
static sfxbuffer_t *
|
||||
snd_fail (sfx_t *sfx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
sfxcache_t *
|
||||
static void
|
||||
snd_noop (sfx_t *sfx)
|
||||
{
|
||||
}
|
||||
|
||||
sfxbuffer_t *
|
||||
SND_CacheRetain (sfx_t *sfx)
|
||||
{
|
||||
return Cache_TryGet (&((sfxblock_t *) sfx)->cache);
|
||||
}
|
||||
|
||||
void
|
||||
SND_CacheRelease (sfx_t *sfx)
|
||||
{
|
||||
Cache_Release (&((sfxblock_t *) sfx->data)->cache);
|
||||
}
|
||||
|
||||
sfxbuffer_t *
|
||||
SND_StreamRetain (sfx_t *sfx)
|
||||
{
|
||||
return &((sfxstream_t *) sfx->data)->buffer;
|
||||
}
|
||||
|
||||
void
|
||||
SND_StreamRelease (sfx_t *sfx)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SND_Load (sfx_t *sfx)
|
||||
{
|
||||
dstring_t *name = dstring_new ();
|
||||
dstring_t *foundname = dstring_new ();
|
||||
char *realname;
|
||||
char buf[4];
|
||||
QFile *file;
|
||||
|
||||
sfx->touch = sfx->retain = snd_fail;
|
||||
sfx->release = snd_noop;
|
||||
|
||||
dsprintf (name, "sound/%s", sfx->name);
|
||||
_QFS_FOpenFile (name->str, &file, foundname, 1);
|
||||
if (!file) {
|
||||
Sys_Printf ("Couldn't load %s\n", name->str);
|
||||
dstring_delete (name);
|
||||
dstring_delete (foundname);
|
||||
return;
|
||||
}
|
||||
if (!strequal (foundname->str, name->str)) {
|
||||
realname = foundname->str;
|
||||
dstring_delete (name);
|
||||
free (foundname);
|
||||
} else {
|
||||
realname = name->str;
|
||||
free (name);
|
||||
dstring_delete (foundname);
|
||||
}
|
||||
Qread (file, buf, 4);
|
||||
Qseek (file, 0, SEEK_SET);
|
||||
if (strnequal ("OggS", buf, 4)) {
|
||||
free (name);
|
||||
SND_LoadOgg (file, sfx, realname);
|
||||
return;
|
||||
}
|
||||
if (strnequal ("RIFF", buf, 4)) {
|
||||
free (name);
|
||||
SND_LoadWav (file, sfx, realname);
|
||||
return;
|
||||
}
|
||||
free (realname);
|
||||
}
|
||||
|
||||
sfxbuffer_t *
|
||||
SND_GetCache (long samples, int rate, int inwidth, int channels,
|
||||
sfx_t *sfx, cache_allocator_t allocator)
|
||||
sfxblock_t *block, cache_allocator_t allocator)
|
||||
{
|
||||
int size;
|
||||
int width;
|
||||
float stepscale;
|
||||
sfxcache_t *sc;
|
||||
sfxbuffer_t *sc;
|
||||
sfx_t *sfx = block->sfx;
|
||||
|
||||
width = snd_loadas8bit->int_val ? 1 : 2;
|
||||
stepscale = (float) rate / shm->speed; // usually 0.5, 1, or 2
|
||||
size = samples / stepscale;
|
||||
size *= width * channels;
|
||||
sc = allocator (&sfx->cache, size + sizeof (sfxcache_t), sfx->name);
|
||||
sc = allocator (&block->cache, sizeof (sfxbuffer_t) + size, sfx->name);
|
||||
if (!sc)
|
||||
return 0;
|
||||
sc->length = samples;
|
||||
sc->speed = rate;
|
||||
sc->width = inwidth;
|
||||
sc->stereo = channels;
|
||||
sc->bytes = size;
|
||||
memcpy (sc->data + size, "\xde\xad\xbe\xef", 4);
|
||||
sfx->length = samples;
|
||||
sfx->speed = rate;
|
||||
sfx->width = inwidth;
|
||||
sfx->channels = channels;
|
||||
block->bytes = size;
|
||||
return sc;
|
||||
}
|
||||
|
||||
void
|
||||
SND_ResampleSfx (sfxcache_t *sc, byte * data)
|
||||
SND_ResampleSfx (sfx_t *sfx, sfxbuffer_t *sc, byte *data)
|
||||
{
|
||||
unsigned char *ib, *ob;
|
||||
int fracstep, outcount, sample, samplefrac, srcsample, i;
|
||||
float stepscale;
|
||||
short *is, *os;
|
||||
int inwidth = sc->width;
|
||||
int inrate = sc->speed;
|
||||
int inwidth = sfx->width;
|
||||
int inrate = sfx->speed;
|
||||
|
||||
is = (short *) data;
|
||||
os = (short *) sc->data;
|
||||
|
@ -91,30 +168,30 @@ SND_ResampleSfx (sfxcache_t *sc, byte * data)
|
|||
|
||||
stepscale = (float) inrate / shm->speed; // usually 0.5, 1, or 2
|
||||
|
||||
outcount = sc->length / stepscale;
|
||||
outcount = sfx->length / stepscale;
|
||||
|
||||
sc->speed = shm->speed;
|
||||
sfx->speed = shm->speed;
|
||||
if (snd_loadas8bit->int_val)
|
||||
sc->width = 1;
|
||||
sfx->width = 1;
|
||||
else
|
||||
sc->width = 2;
|
||||
sc->stereo = 0;
|
||||
sfx->width = 2;
|
||||
sfx->channels = 1;
|
||||
|
||||
// resample / decimate to the current source rate
|
||||
if (stepscale == 1) {
|
||||
if (inwidth == 1 && sc->width == 1) {
|
||||
if (inwidth == 1 && sfx->width == 1) {
|
||||
for (i = 0; i < outcount; i++) {
|
||||
*ob++ = *ib++ - 128;
|
||||
}
|
||||
} else if (inwidth == 1 && sc->width == 2) {
|
||||
} else if (inwidth == 1 && sfx->width == 2) {
|
||||
for (i = 0; i < outcount; i++) {
|
||||
*os++ = (*ib++ - 128) << 8;
|
||||
}
|
||||
} else if (inwidth == 2 && sc->width == 1) {
|
||||
} else if (inwidth == 2 && sfx->width == 1) {
|
||||
for (i = 0; i < outcount; i++) {
|
||||
*ob++ = LittleShort (*is++) >> 8;
|
||||
}
|
||||
} else if (inwidth == 2 && sc->width == 2) {
|
||||
} else if (inwidth == 2 && sfx->width == 2) {
|
||||
for (i = 0; i < outcount; i++) {
|
||||
*os++ = LittleShort (*is++);
|
||||
}
|
||||
|
@ -125,29 +202,29 @@ SND_ResampleSfx (sfxcache_t *sc, byte * data)
|
|||
int j;
|
||||
int points = 1 / stepscale;
|
||||
|
||||
for (i = 0; i < sc->length; i++) {
|
||||
for (i = 0; i < sfx->length; i++) {
|
||||
int s1, s2;
|
||||
|
||||
if (inwidth == 2) {
|
||||
s2 = s1 = LittleShort (is[0]);
|
||||
if (i < sc->length - 1)
|
||||
if (i < sfx->length - 1)
|
||||
s2 = LittleShort (is[1]);
|
||||
is++;
|
||||
} else {
|
||||
s2 = s1 = (ib[0] - 128) << 8;
|
||||
if (i < sc->length - 1)
|
||||
if (i < sfx->length - 1)
|
||||
s2 = (ib[1] - 128) << 8;
|
||||
ib++;
|
||||
}
|
||||
for (j = 0; j < points; j++) {
|
||||
sample = s1 + (s2 - s1) * ((float) j) / points;
|
||||
if (sc->width == 2) {
|
||||
if (sfx->width == 2) {
|
||||
os[j] = sample;
|
||||
} else {
|
||||
ob[j] = sample >> 8;
|
||||
}
|
||||
}
|
||||
if (sc->width == 2) {
|
||||
if (sfx->width == 2) {
|
||||
os += points;
|
||||
} else {
|
||||
ob += points;
|
||||
|
@ -164,7 +241,7 @@ SND_ResampleSfx (sfxcache_t *sc, byte * data)
|
|||
else
|
||||
sample =
|
||||
(int) ((unsigned char) (data[srcsample]) - 128) << 8;
|
||||
if (sc->width == 2)
|
||||
if (sfx->width == 2)
|
||||
((short *) sc->data)[i] = sample;
|
||||
else
|
||||
((signed char *) sc->data)[i] = sample >> 8;
|
||||
|
@ -172,241 +249,7 @@ SND_ResampleSfx (sfxcache_t *sc, byte * data)
|
|||
}
|
||||
}
|
||||
|
||||
sc->length = outcount;
|
||||
if (sc->loopstart != -1)
|
||||
sc->loopstart = sc->loopstart / stepscale;
|
||||
if (memcmp (sc->data + sc->bytes, "\xde\xad\xbe\xef", 4))
|
||||
Sys_Error ("SND_ResampleSfx screwed the pooch: %02x%02x%02x%02x",
|
||||
sc->data[sc->bytes + 0], sc->data[sc->bytes + 1],
|
||||
sc->data[sc->bytes + 2], sc->data[sc->bytes + 3]);
|
||||
}
|
||||
|
||||
static sfxcache_t *
|
||||
SND_LoadSound (sfx_t *sfx, cache_allocator_t allocator)
|
||||
{
|
||||
char namebuffer[256];
|
||||
dstring_t *foundname = dstring_new ();
|
||||
byte *data;
|
||||
wavinfo_t info;
|
||||
int len;
|
||||
float stepscale;
|
||||
sfxcache_t *sc;
|
||||
byte stackbuf[1 * 1024]; // avoid dirtying the cache heap
|
||||
QFile *file;
|
||||
|
||||
// load it in
|
||||
strcpy (namebuffer, "sound/");
|
||||
strncat (namebuffer, sfx->name, sizeof (namebuffer) - strlen (namebuffer));
|
||||
_QFS_FOpenFile (namebuffer, &file, foundname, 1);
|
||||
if (!file) {
|
||||
dstring_delete (foundname);
|
||||
Sys_Printf ("Couldn't load %s\n", namebuffer);
|
||||
return 0;
|
||||
}
|
||||
if (strcmp (".ogg", QFS_FileExtension (foundname->str)) == 0) {
|
||||
dstring_delete (foundname);
|
||||
return SND_LoadOgg (file, sfx, allocator);
|
||||
}
|
||||
dstring_delete (foundname);
|
||||
Qclose (file); //FIXME this is a dumb way to do this
|
||||
data = QFS_LoadStackFile (namebuffer, stackbuf, sizeof (stackbuf));
|
||||
|
||||
if (!data) {
|
||||
Sys_Printf ("Couldn't load %s\n", namebuffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info = SND_GetWavinfo (sfx->name, data, qfs_filesize);
|
||||
if (info.channels != 1) {
|
||||
Sys_Printf ("%s is a stereo sample\n", sfx->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stepscale = (float) info.rate / shm->speed;
|
||||
len = info.samples / stepscale;
|
||||
|
||||
if (snd_loadas8bit->int_val) {
|
||||
len = len * info.channels;
|
||||
} else {
|
||||
len = len * 2 * info.channels;
|
||||
}
|
||||
|
||||
sc = SND_GetCache (info.samples, info.rate, info.width, info.channels,
|
||||
sfx, allocator);
|
||||
if (!sc)
|
||||
return NULL;
|
||||
|
||||
sc->loopstart = info.loopstart;
|
||||
|
||||
SND_ResampleSfx (sc, data + info.dataofs);
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
void
|
||||
SND_CallbackLoad (void *object, cache_allocator_t allocator)
|
||||
{
|
||||
SND_LoadSound (object, allocator);
|
||||
}
|
||||
|
||||
/* WAV loading */
|
||||
|
||||
byte *data_p;
|
||||
byte *iff_end;
|
||||
byte *last_chunk;
|
||||
byte *iff_data;
|
||||
int iff_chunk_len;
|
||||
|
||||
static short
|
||||
SND_GetLittleShort (void)
|
||||
{
|
||||
short val = 0;
|
||||
|
||||
val = *data_p;
|
||||
val = val + (*(data_p + 1) << 8);
|
||||
data_p += 2;
|
||||
return val;
|
||||
}
|
||||
|
||||
static int
|
||||
SND_GetLittleLong (void)
|
||||
{
|
||||
int val = 0;
|
||||
|
||||
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
|
||||
SND_FindNexctChunk (const char *name)
|
||||
{
|
||||
while (1) {
|
||||
data_p = last_chunk;
|
||||
|
||||
if (data_p >= iff_end) { // didn't find the chunk
|
||||
data_p = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
data_p += 4;
|
||||
iff_chunk_len = SND_GetLittleLong ();
|
||||
if (iff_chunk_len < 0) {
|
||||
data_p = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
data_p -= 8;
|
||||
last_chunk = data_p + 8 + ((iff_chunk_len + 1) & ~1);
|
||||
if (!strncmp (data_p, name, 4))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
SND_FindChunk (const char *name)
|
||||
{
|
||||
last_chunk = iff_data;
|
||||
SND_FindNexctChunk (name);
|
||||
}
|
||||
/*
|
||||
static void
|
||||
SND_DumpChunks (void)
|
||||
{
|
||||
char str[5];
|
||||
|
||||
str[4] = 0;
|
||||
data_p = iff_data;
|
||||
do {
|
||||
memcpy (str, data_p, 4);
|
||||
data_p += 4;
|
||||
iff_chunk_len = SND_GetLittleLong ();
|
||||
Sys_Printf ("0x%lx : %s (%d)\n", (long) (data_p - 4), str,
|
||||
iff_chunk_len);
|
||||
data_p += (iff_chunk_len + 1) & ~1;
|
||||
} while (data_p < iff_end);
|
||||
}
|
||||
*/
|
||||
wavinfo_t
|
||||
SND_GetWavinfo (const char *name, byte * wav, int wavlength)
|
||||
{
|
||||
int format, samples, i;
|
||||
wavinfo_t info;
|
||||
|
||||
memset (&info, 0, sizeof (info));
|
||||
|
||||
if (!wav)
|
||||
return info;
|
||||
|
||||
iff_data = wav;
|
||||
iff_end = wav + wavlength;
|
||||
|
||||
// find "RIFF" chunk
|
||||
SND_FindChunk ("RIFF");
|
||||
if (!(data_p && !strncmp (data_p + 8, "WAVE", 4))) {
|
||||
Sys_Printf ("Missing RIFF/WAVE chunks\n");
|
||||
return info;
|
||||
}
|
||||
// get "fmt " chunk
|
||||
iff_data = data_p + 12;
|
||||
// SND_DumpChunks ();
|
||||
|
||||
SND_FindChunk ("fmt ");
|
||||
if (!data_p) {
|
||||
Sys_Printf ("Missing fmt chunk\n");
|
||||
return info;
|
||||
}
|
||||
data_p += 8;
|
||||
format = SND_GetLittleShort ();
|
||||
if (format != 1) {
|
||||
Sys_Printf ("Microsoft PCM format only\n");
|
||||
return info;
|
||||
}
|
||||
|
||||
info.channels = SND_GetLittleShort ();
|
||||
info.rate = SND_GetLittleLong ();
|
||||
data_p += 4 + 2;
|
||||
info.width = SND_GetLittleShort () / 8;
|
||||
|
||||
// get cue chunk
|
||||
SND_FindChunk ("cue ");
|
||||
if (data_p) {
|
||||
data_p += 32;
|
||||
info.loopstart = SND_GetLittleLong ();
|
||||
|
||||
// if the next chunk is a LIST chunk, look for a cue length marker
|
||||
SND_FindNexctChunk ("LIST");
|
||||
if (data_p) {
|
||||
if (!strncmp (data_p + 28, "mark", 4)) {
|
||||
// this is not a proper parse, but it works with cooledit...
|
||||
data_p += 24;
|
||||
i = SND_GetLittleLong (); // samples in loop
|
||||
info.samples = info.loopstart + i;
|
||||
}
|
||||
}
|
||||
} else
|
||||
info.loopstart = -1;
|
||||
|
||||
// find data chunk
|
||||
SND_FindChunk ("data");
|
||||
if (!data_p) {
|
||||
Sys_Printf ("Missing data chunk\n");
|
||||
return info;
|
||||
}
|
||||
|
||||
data_p += 4;
|
||||
samples = SND_GetLittleLong () / info.width;
|
||||
|
||||
if (info.samples) {
|
||||
if (samples < info.samples)
|
||||
Sys_Error ("Sound %s has a bad loop length", name);
|
||||
} else
|
||||
info.samples = samples;
|
||||
|
||||
info.dataofs = data_p - wav;
|
||||
|
||||
return info;
|
||||
sfx->length = outcount;
|
||||
if (sfx->loopstart != -1)
|
||||
sfx->loopstart = sfx->loopstart / stepscale;
|
||||
}
|
||||
|
|
|
@ -55,7 +55,6 @@ int snd_scaletable[32][256];
|
|||
int *snd_p, snd_linear_count, snd_vol;
|
||||
short *snd_out;
|
||||
|
||||
#ifndef USE_INTEL_ASM
|
||||
void
|
||||
SND_WriteLinearBlastStereo16 (void)
|
||||
{
|
||||
|
@ -79,7 +78,6 @@ SND_WriteLinearBlastStereo16 (void)
|
|||
snd_out[i + 1] = val;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
SND_TransferStereo16 (int endtime)
|
||||
|
@ -172,7 +170,7 @@ SND_PaintChannels (int endtime)
|
|||
{
|
||||
int end, ltime, count, i;
|
||||
channel_t *ch;
|
||||
sfxcache_t *sc;
|
||||
sfxbuffer_t *sc;
|
||||
|
||||
while (paintedtime < endtime) {
|
||||
// if paintbuffer is smaller than DMA buffer
|
||||
|
@ -192,7 +190,7 @@ SND_PaintChannels (int endtime)
|
|||
continue;
|
||||
if (!ch->leftvol && !ch->rightvol)
|
||||
continue;
|
||||
sc = Cache_TryGet (&ch->sfx->cache);
|
||||
sc = ch->sfx->retain (ch->sfx);
|
||||
if (!sc)
|
||||
continue;
|
||||
|
||||
|
@ -205,20 +203,17 @@ SND_PaintChannels (int endtime)
|
|||
count = end - ltime;
|
||||
|
||||
if (count > 0) {
|
||||
if (sc->width == 1)
|
||||
SND_PaintChannelFrom8 (ch, sc, count);
|
||||
else
|
||||
SND_PaintChannelFrom16 (ch, sc, count);
|
||||
sc->paint (ch, sc, count);
|
||||
|
||||
ltime += count;
|
||||
}
|
||||
// if at end of loop, restart
|
||||
if (ltime >= ch->end) {
|
||||
if (sc->loopstart >= 0) {
|
||||
ch->pos = sc->loopstart;
|
||||
ch->end = ltime + sc->length - ch->pos;
|
||||
if (ch->sfx->loopstart >= 0) {
|
||||
ch->pos = ch->sfx->loopstart;
|
||||
ch->end = ltime + ch->sfx->length - ch->pos;
|
||||
} else { // channel just stopped
|
||||
Cache_Release (&ch->sfx->cache);
|
||||
ch->sfx->release (ch->sfx);
|
||||
ch->sfx = NULL;
|
||||
break;
|
||||
}
|
||||
|
@ -226,7 +221,7 @@ SND_PaintChannels (int endtime)
|
|||
}
|
||||
|
||||
if (ch->sfx)
|
||||
Cache_Release (&ch->sfx->cache);
|
||||
ch->sfx->release (ch->sfx);
|
||||
}
|
||||
|
||||
// transfer out according to DMA format
|
||||
|
@ -251,9 +246,8 @@ SND_InitScaletable (void)
|
|||
snd_scaletable[i][j] = ((signed char) j) * i * 8;
|
||||
}
|
||||
|
||||
#ifndef USE_INTEL_ASM
|
||||
void
|
||||
SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
|
||||
SND_PaintChannelFrom8 (channel_t *ch, sfxbuffer_t *sc, int count)
|
||||
{
|
||||
unsigned char *sfx;
|
||||
int data, i;
|
||||
|
@ -276,10 +270,9 @@ SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
|
|||
|
||||
ch->pos += count;
|
||||
}
|
||||
#endif // !USE_INTEL_ASM
|
||||
|
||||
void
|
||||
SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
|
||||
SND_PaintChannelFrom16 (channel_t *ch, sfxbuffer_t *sc, int count)
|
||||
{
|
||||
int leftvol, rightvol;
|
||||
unsigned int left_phase, right_phase; // Never allowed < 0 anyway
|
||||
|
@ -374,7 +367,7 @@ SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
|
|||
}
|
||||
|
||||
void
|
||||
SND_PaintChannelStereo8 (channel_t *ch, sfxcache_t *sc, int count)
|
||||
SND_PaintChannelStereo8 (channel_t *ch, sfxbuffer_t *sc, int count)
|
||||
{
|
||||
byte *samp;
|
||||
portable_samplepair_t *pair;
|
||||
|
@ -398,7 +391,7 @@ SND_PaintChannelStereo8 (channel_t *ch, sfxcache_t *sc, int count)
|
|||
}
|
||||
|
||||
void
|
||||
SND_PaintChannelStereo16 (channel_t *ch, sfxcache_t *sc, int count)
|
||||
SND_PaintChannelStereo16 (channel_t *ch, sfxbuffer_t *sc, int count)
|
||||
{
|
||||
short *samp;
|
||||
portable_samplepair_t *pair;
|
||||
|
|
|
@ -47,7 +47,7 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include <vorbis/vorbisfile.h>
|
||||
|
||||
#include "QF/cvar.h"
|
||||
#include "QF/quakeio.h"
|
||||
#include "QF/quakefs.h"
|
||||
#include "QF/sound.h"
|
||||
#include "QF/sys.h"
|
||||
|
||||
|
@ -85,73 +85,185 @@ static ov_callbacks callbacks = {
|
|||
tell_func,
|
||||
};
|
||||
|
||||
sfxcache_t *
|
||||
SND_LoadOgg (QFile *file, sfx_t *sfx, cache_allocator_t allocator)
|
||||
static void
|
||||
get_info (OggVorbis_File *vf, sfx_t *sfx)
|
||||
{
|
||||
OggVorbis_File vf;
|
||||
vorbis_info *vi;
|
||||
long samples, size;
|
||||
byte *data, *d;
|
||||
int current_section;
|
||||
int sample_start = -1, sample_count = 0;
|
||||
sfxcache_t *sc = 0;
|
||||
char **ptr;
|
||||
|
||||
if (ov_open_callbacks (file, &vf, 0, 0, callbacks) < 0) {
|
||||
Sys_Printf ("Input does not appear to be an Ogg bitstream.\n");
|
||||
Qclose (file);
|
||||
return 0;
|
||||
}
|
||||
vi = ov_info (&vf, -1);
|
||||
samples = ov_pcm_total (&vf, -1);
|
||||
vi = ov_info (vf, -1);
|
||||
sfx->length = ov_pcm_total (vf, -1);
|
||||
sfx->channels = vi->channels;
|
||||
sfx->speed = vi->rate;
|
||||
|
||||
for (ptr = ov_comment (&vf, -1)->user_comments; *ptr; ptr++) {
|
||||
for (ptr = ov_comment (vf, -1)->user_comments; *ptr; ptr++) {
|
||||
Sys_DPrintf ("%s\n", *ptr);
|
||||
if (strncmp ("CUEPOINT=", *ptr, 9) == 0) {
|
||||
sscanf (*ptr + 9, "%d %d", &sample_start, &sample_count);
|
||||
} else {
|
||||
sample_count = samples;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sample_start != -1)
|
||||
samples = sample_start + sample_count;
|
||||
size = samples * vi->channels * 2;
|
||||
|
||||
if (developer->int_val) {
|
||||
Sys_Printf ("\nBitstream is %d channel, %ldHz\n",
|
||||
vi->channels, vi->rate);
|
||||
Sys_Printf ("\nDecoded length: %ld samples (%ld bytes)\n",
|
||||
samples, size);
|
||||
Sys_Printf ("Encoded by: %s\n\n", ov_comment (&vf, -1)->vendor);
|
||||
Sys_Printf ("\nBitstream is %d channel, %dHz\n",
|
||||
sfx->channels, sfx->speed);
|
||||
Sys_Printf ("\nDecoded length: %d samples (%d bytes)\n",
|
||||
sfx->length, sfx->length * sfx->channels * 2);
|
||||
Sys_Printf ("Encoded by: %s\n\n", ov_comment (vf, -1)->vendor);
|
||||
}
|
||||
data = malloc (size);
|
||||
if (!data)
|
||||
goto bail;
|
||||
sc = SND_GetCache (samples, vi->rate, 2, vi->channels, sfx, allocator);
|
||||
if (!sc)
|
||||
goto bail;
|
||||
d = data;
|
||||
while (size) {
|
||||
int res = ov_read (&vf, d, size, 0, 2, 1, ¤t_section);
|
||||
|
||||
if (sample_start != -1)
|
||||
sfx->length = sample_start + sample_count;
|
||||
sfx->loopstart = sample_start;
|
||||
}
|
||||
|
||||
static int
|
||||
read_ogg (OggVorbis_File *vf, byte *buf, int len)
|
||||
{
|
||||
int count = 0;
|
||||
int current_section;
|
||||
|
||||
while (len) {
|
||||
int res = ov_read (vf, buf, len, 0, 2, 1, ¤t_section);
|
||||
if (res > 0) {
|
||||
size -= res;
|
||||
d += res;
|
||||
count += res;
|
||||
len -= res;
|
||||
buf += res;
|
||||
} else if (res < 0) {
|
||||
Sys_Printf ("vorbis error %d\n", res);
|
||||
goto bail;
|
||||
return -1;
|
||||
} else {
|
||||
Sys_Printf ("unexpected eof\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
sc->loopstart = sample_start;
|
||||
SND_ResampleSfx (sc, data);
|
||||
return count;
|
||||
}
|
||||
|
||||
static sfxbuffer_t *
|
||||
load_ogg (OggVorbis_File *vf, sfxblock_t *block, cache_allocator_t allocator)
|
||||
{
|
||||
long size;
|
||||
byte *data;
|
||||
sfxbuffer_t *sc = 0;
|
||||
sfx_t *sfx = block->sfx;
|
||||
int channels;
|
||||
|
||||
|
||||
get_info (vf, sfx);
|
||||
|
||||
channels = sfx->channels;
|
||||
|
||||
size = sfx->length * channels * 2;
|
||||
|
||||
data = malloc (size);
|
||||
if (!data)
|
||||
goto bail;
|
||||
sc = SND_GetCache (sfx->length, sfx->speed, 2, channels, block, allocator);
|
||||
if (!sc)
|
||||
goto bail;
|
||||
if (read_ogg (vf, data, size) < 0)
|
||||
goto bail;
|
||||
SND_ResampleSfx (sfx, sc, data);
|
||||
bail:
|
||||
if (data)
|
||||
free (data);
|
||||
ov_clear (&vf);
|
||||
ov_clear (vf);
|
||||
return sc;
|
||||
}
|
||||
|
||||
static void
|
||||
ogg_callback_load (void *object, cache_allocator_t allocator)
|
||||
{
|
||||
QFile *file;
|
||||
OggVorbis_File vf;
|
||||
|
||||
sfxblock_t *block = (sfxblock_t *) object;
|
||||
|
||||
QFS_FOpenFile (block->file, &file);
|
||||
if (!file)
|
||||
return; //FIXME Sys_Error?
|
||||
|
||||
if (ov_open_callbacks (file, &vf, 0, 0, callbacks) < 0) {
|
||||
Sys_Printf ("Input does not appear to be an Ogg bitstream.\n");
|
||||
Qclose (file);
|
||||
return; //FIXME Sys_Error?
|
||||
}
|
||||
load_ogg (&vf, block, allocator);
|
||||
}
|
||||
|
||||
static void
|
||||
vorbis_advance (sfxbuffer_t *buffer, int count)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
stream_ogg (sfx_t *sfx, OggVorbis_File *vf)
|
||||
{
|
||||
sfxstream_t *stream;
|
||||
int length, bytes;
|
||||
void (*paint) (channel_t *ch, sfxbuffer_t *buffer, int count);
|
||||
|
||||
|
||||
get_info (vf, sfx);
|
||||
|
||||
switch (sfx->channels) {
|
||||
case 1:
|
||||
paint = SND_PaintChannelFrom16;
|
||||
break;
|
||||
case 2:
|
||||
paint = SND_PaintChannelStereo16;
|
||||
break;
|
||||
default:
|
||||
Sys_Printf ("%s: unsupported channel count: %d\n",
|
||||
sfx->name, sfx->channels);
|
||||
return;
|
||||
}
|
||||
|
||||
length = shm->speed * snd_mixahead->value * 3;
|
||||
bytes = sfx->channels * 2 * length;
|
||||
|
||||
stream = calloc (1, sizeof (sfxstream_t) + bytes);
|
||||
|
||||
stream->file = malloc (sizeof (OggVorbis_File));
|
||||
memcpy (stream->file, vf, sizeof (OggVorbis_File));
|
||||
|
||||
stream->buffer.length = length;
|
||||
stream->buffer.paint = paint;
|
||||
stream->buffer.advance = vorbis_advance;
|
||||
|
||||
sfx->data = stream;
|
||||
}
|
||||
|
||||
void
|
||||
SND_LoadOgg (QFile *file, sfx_t *sfx, char *realname)
|
||||
{
|
||||
OggVorbis_File vf;
|
||||
|
||||
if (ov_open_callbacks (file, &vf, 0, 0, callbacks) < 0) {
|
||||
Sys_Printf ("Input does not appear to be an Ogg bitstream.\n");
|
||||
Qclose (file);
|
||||
free (realname);
|
||||
return;
|
||||
}
|
||||
if (ov_pcm_total (&vf, -1) < 3 * shm->speed) {
|
||||
sfxblock_t *block = calloc (1, sizeof (sfxblock_t));
|
||||
ov_clear (&vf);
|
||||
sfx->data = block;
|
||||
sfx->retain = SND_CacheRetain;
|
||||
sfx->release = SND_CacheRelease;
|
||||
block->sfx = sfx;
|
||||
block->file = realname;
|
||||
Cache_Add (&block->cache, block, ogg_callback_load);
|
||||
} else {
|
||||
sfx->retain = SND_StreamRetain;
|
||||
sfx->release = SND_StreamRelease;
|
||||
free (realname);
|
||||
stream_ogg (sfx, &vf);
|
||||
}
|
||||
}
|
||||
|
||||
#else//HAVE_VORBIS
|
||||
|
||||
#include "QF/sound.h"
|
||||
|
@ -160,11 +272,12 @@ SND_LoadOgg (QFile *file, sfx_t *sfx, cache_allocator_t allocator)
|
|||
|
||||
#include "snd_render.h"
|
||||
|
||||
sfxcache_t *
|
||||
SND_LoadOgg (QFile *file, sfx_t *sfx, cache_allocator_t allocator)
|
||||
void
|
||||
SND_LoadOgg (QFile *file, sfx_t *sfx, char *realname)
|
||||
{
|
||||
Sys_Printf ("Ogg/Vorbis support not available, sorry.\n");
|
||||
Qclose (file);
|
||||
return 0;
|
||||
free (realname);
|
||||
return;
|
||||
}
|
||||
#endif//HAVE_VORBIS
|
||||
|
|
|
@ -43,184 +43,84 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include "QF/sys.h"
|
||||
#include "QF/qendian.h"
|
||||
#include "QF/quakefs.h"
|
||||
#include "QF/riff.h"
|
||||
|
||||
#include "snd_render.h"
|
||||
|
||||
static byte *data_p;
|
||||
static byte *iff_end;
|
||||
static byte *last_chunk;
|
||||
static byte *iff_data;
|
||||
static int iff_chunk_len;
|
||||
|
||||
static short
|
||||
SND_GetLittleShort (void)
|
||||
{
|
||||
short val = 0;
|
||||
|
||||
val = *data_p;
|
||||
val = val + (*(data_p + 1) << 8);
|
||||
data_p += 2;
|
||||
return val;
|
||||
}
|
||||
|
||||
static int
|
||||
SND_GetLittleLong (void)
|
||||
{
|
||||
int val = 0;
|
||||
|
||||
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
|
||||
SND_FindNexctChunk (const char *name)
|
||||
{
|
||||
while (1) {
|
||||
data_p = last_chunk;
|
||||
|
||||
if (data_p >= iff_end) { // didn't find the chunk
|
||||
data_p = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
data_p += 4;
|
||||
iff_chunk_len = SND_GetLittleLong ();
|
||||
if (iff_chunk_len < 0) {
|
||||
data_p = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
data_p -= 8;
|
||||
last_chunk = data_p + 8 + ((iff_chunk_len + 1) & ~1);
|
||||
if (!strncmp (data_p, name, 4))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
SND_FindChunk (const char *name)
|
||||
{
|
||||
last_chunk = iff_data;
|
||||
SND_FindNexctChunk (name);
|
||||
}
|
||||
|
||||
static wavinfo_t
|
||||
SND_GetWavinfo (const char *name, byte * wav, int wavlength)
|
||||
{
|
||||
int format, samples, i;
|
||||
wavinfo_t info;
|
||||
|
||||
memset (&info, 0, sizeof (info));
|
||||
|
||||
if (!wav)
|
||||
return info;
|
||||
|
||||
iff_data = wav;
|
||||
iff_end = wav + wavlength;
|
||||
|
||||
// find "RIFF" chunk
|
||||
SND_FindChunk ("RIFF");
|
||||
if (!(data_p && !strncmp (data_p + 8, "WAVE", 4))) {
|
||||
Sys_Printf ("Missing RIFF/WAVE chunks\n");
|
||||
return info;
|
||||
}
|
||||
// get "fmt " chunk
|
||||
iff_data = data_p + 12;
|
||||
// SND_DumpChunks ();
|
||||
|
||||
SND_FindChunk ("fmt ");
|
||||
if (!data_p) {
|
||||
Sys_Printf ("Missing fmt chunk\n");
|
||||
return info;
|
||||
}
|
||||
data_p += 8;
|
||||
format = SND_GetLittleShort ();
|
||||
if (format != 1) {
|
||||
Sys_Printf ("Microsoft PCM format only\n");
|
||||
return info;
|
||||
}
|
||||
|
||||
info.channels = SND_GetLittleShort ();
|
||||
info.rate = SND_GetLittleLong ();
|
||||
data_p += 4 + 2;
|
||||
info.width = SND_GetLittleShort () / 8;
|
||||
|
||||
// get cue chunk
|
||||
SND_FindChunk ("cue ");
|
||||
if (data_p) {
|
||||
data_p += 32;
|
||||
info.loopstart = SND_GetLittleLong ();
|
||||
|
||||
// if the next chunk is a LIST chunk, look for a cue length marker
|
||||
SND_FindNexctChunk ("LIST");
|
||||
if (data_p) {
|
||||
if (!strncmp (data_p + 28, "mark", 4)) {
|
||||
// this is not a proper parse, but it works with cooledit...
|
||||
data_p += 24;
|
||||
i = SND_GetLittleLong (); // samples in loop
|
||||
info.samples = info.loopstart + i;
|
||||
}
|
||||
}
|
||||
} else
|
||||
info.loopstart = -1;
|
||||
|
||||
// find data chunk
|
||||
SND_FindChunk ("data");
|
||||
if (!data_p) {
|
||||
Sys_Printf ("Missing data chunk\n");
|
||||
return info;
|
||||
}
|
||||
|
||||
data_p += 4;
|
||||
samples = SND_GetLittleLong () / info.width;
|
||||
|
||||
if (info.samples) {
|
||||
if (samples < info.samples)
|
||||
Sys_Error ("Sound %s has a bad loop length", name);
|
||||
} else
|
||||
info.samples = samples;
|
||||
|
||||
info.dataofs = data_p - wav;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void
|
||||
SND_LoadWav (QFile *file)
|
||||
SND_LoadWav (QFile *file, sfx_t *sfx, char *realname)
|
||||
{
|
||||
int size;
|
||||
riff_t *riff;
|
||||
riff_d_chunk_t **ck;
|
||||
|
||||
size = Qfilelen (file);
|
||||
data = Hunk_TempAlloc (size);
|
||||
Qread (file, data, size);
|
||||
riff_format_t *fmt;
|
||||
riff_d_format_t *dfmt = 0;
|
||||
|
||||
info = SND_GetWavinfo (sfx->name, data, qfs_filesize);
|
||||
if (info.channels != 1) {
|
||||
Sys_Printf ("%s is a stereo sample\n", sfx->name);
|
||||
return NULL;
|
||||
riff_data_t *data = 0;
|
||||
|
||||
riff_cue_t *cue;
|
||||
riff_d_cue_t *dcue;
|
||||
riff_d_cue_point_t *cp = 0;
|
||||
|
||||
riff_list_t *list;
|
||||
riff_d_chunk_t **lck;
|
||||
|
||||
riff_ltxt_t *ltxt;
|
||||
riff_d_ltxt_t *dltxt = 0;
|
||||
|
||||
int loop_start = -1, sample_count = -1;
|
||||
|
||||
if (!(riff = riff_read (file))) {
|
||||
Sys_Printf ("bad riff file\n");
|
||||
return;
|
||||
}
|
||||
|
||||
stepscale = (float) info.rate / shm->speed;
|
||||
len = info.samples / stepscale;
|
||||
|
||||
if (snd_loadas8bit->int_val) {
|
||||
len = len * info.channels;
|
||||
} else {
|
||||
len = len * 2 * info.channels;
|
||||
for (ck = riff->chunks; *ck; ck++) {
|
||||
RIFF_SWITCH ((*ck)->name) {
|
||||
case RIFF_CASE ('f','m','t',' '):
|
||||
fmt = (riff_format_t *) *ck;
|
||||
dfmt = (riff_d_format_t *) fmt->fdata;
|
||||
break;
|
||||
case RIFF_CASE ('d','a','t','a'):
|
||||
data = (riff_data_t *) *ck;
|
||||
break;
|
||||
case RIFF_CASE ('c','u','e',' '):
|
||||
cue = (riff_cue_t *) *ck;
|
||||
dcue = cue->cue;
|
||||
if (dcue->count)
|
||||
cp = &dcue->cue_points[dcue->count - 1];
|
||||
break;
|
||||
case RIFF_CASE ('L','I','S','T'):
|
||||
list = (riff_list_t *) *ck;
|
||||
RIFF_SWITCH (list->name) {
|
||||
case RIFF_CASE ('a','d','t','l'):
|
||||
for (lck = list->chunks; *lck; lck++) {
|
||||
RIFF_SWITCH ((*lck)->name) {
|
||||
case RIFF_CASE ('l','t','x','t'):
|
||||
ltxt = (riff_ltxt_t *) *ck;
|
||||
dltxt = <xt->ltxt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sc = SND_GetCache (info.samples, info.rate, info.width, info.channels,
|
||||
sfx, allocator);
|
||||
if (!sc)
|
||||
return NULL;
|
||||
|
||||
sfx->loopstart = info.loopstart;
|
||||
|
||||
SND_ResampleSfx (sc, data + info.dataofs);
|
||||
|
||||
return sc;
|
||||
if (!dfmt) {
|
||||
Sys_Printf ("missing format chunk\n");
|
||||
goto bail;
|
||||
}
|
||||
if (!data) {
|
||||
Sys_Printf ("missing data chunk\n");
|
||||
goto bail;
|
||||
}
|
||||
if (dltxt)
|
||||
sample_count = dltxt->len;
|
||||
if (cp)
|
||||
loop_start = cp->sample_offset;
|
||||
bail:
|
||||
Qclose (file);
|
||||
riff_free (riff);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue