half way though the sfx loader re-write. nothing works :)

This commit is contained in:
Bill Currie 2003-04-11 01:17:48 +00:00
parent e5a23c95dc
commit ccb56eea39
8 changed files with 440 additions and 578 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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, &current_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, &current_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

View File

@ -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 = &ltxt->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);
}