extend the sound api slightly to ease things like cd_file and make cd_file

work as intended :)
This commit is contained in:
Bill Currie 2004-01-21 02:52:12 +00:00
parent 19ef80c555
commit d5a33c9545
7 changed files with 203 additions and 119 deletions

View file

@ -55,6 +55,8 @@ typedef void (*P_S_ExtraUpdate) (void);
typedef void (*P_S_LocalSound) (const char *s); typedef void (*P_S_LocalSound) (const char *s);
typedef void (*P_S_BlockSound) (void); typedef void (*P_S_BlockSound) (void);
typedef void (*P_S_UnblockSound) (void); typedef void (*P_S_UnblockSound) (void);
typedef struct sfx_s *(*P_S_LoadSound) (const char *name);
typedef struct channel_s *(*P_S_AllocChannel) (void);
typedef struct snd_render_funcs_s { typedef struct snd_render_funcs_s {
P_S_AmbientOff pS_AmbientOff; P_S_AmbientOff pS_AmbientOff;
@ -73,6 +75,8 @@ typedef struct snd_render_funcs_s {
P_S_LocalSound pS_LocalSound; P_S_LocalSound pS_LocalSound;
P_S_BlockSound pS_BlockSound; P_S_BlockSound pS_BlockSound;
P_S_UnblockSound pS_UnblockSound; P_S_UnblockSound pS_UnblockSound;
P_S_LoadSound pS_LoadSound;
P_S_AllocChannel pS_AllocChannel;
} snd_render_funcs_t; } snd_render_funcs_t;
typedef struct snd_render_data_s { typedef struct snd_render_data_s {

View file

@ -96,6 +96,8 @@ void S_ClearPrecache (void);
void S_BeginPrecaching (void); void S_BeginPrecaching (void);
void S_EndPrecaching (void); void S_EndPrecaching (void);
sfx_t *S_LoadSound (const char *name);
struct channel_s *S_AllocChannel (void);
// ==================================================================== // ====================================================================
// User-setable variables // User-setable variables

View file

@ -36,28 +36,28 @@
// !!! if this is changed, it must be changed in asm_i386.h too !!! // !!! if this is changed, it must be changed in asm_i386.h too !!!
typedef struct portable_samplepair_s { typedef struct portable_samplepair_s {
int left; int left;
int right; int right;
} portable_samplepair_t; } portable_samplepair_t;
typedef struct wavinfo_s { typedef struct wavinfo_s {
unsigned int rate; unsigned rate;
unsigned int width; unsigned width;
unsigned int channels; unsigned channels;
unsigned int loopstart; unsigned loopstart;
unsigned int samples; unsigned samples;
unsigned int dataofs; // chunk starts this many bytes from file start unsigned dataofs; // chunk starts this many bytes from file start
unsigned int datalen; // chunk bytes unsigned datalen; // chunk bytes
} wavinfo_t; } wavinfo_t;
typedef struct channel_s channel_t; typedef struct channel_s channel_t;
typedef struct sfxbuffer_s sfxbuffer_t; typedef struct sfxbuffer_s sfxbuffer_t;
struct sfxbuffer_s { struct sfxbuffer_s {
unsigned int head; // ring buffer head position in sampels unsigned head; // ring buffer head position in sampels
unsigned int tail; // ring buffer tail position in sampels unsigned tail; // ring buffer tail position in sampels
unsigned int length; // length of buffer in samples unsigned length; // length of buffer in samples
unsigned int pos; // position of tail within full stream unsigned pos; // position of tail within full stream
unsigned int bps; // bytes per sample: 1 2 4 usually unsigned bps; // bytes per sample: 1 2 4 usually
void (*paint) (channel_t *ch, sfxbuffer_t *buffer, int count); void (*paint) (channel_t *ch, sfxbuffer_t *buffer, int count);
void (*advance) (sfxbuffer_t *buffer, unsigned int count); void (*advance) (sfxbuffer_t *buffer, unsigned int count);
void (*setpos) (sfxbuffer_t *buffer, unsigned int pos); void (*setpos) (sfxbuffer_t *buffer, unsigned int pos);
@ -70,9 +70,9 @@ typedef struct sfxstream_s {
void *file; void *file;
wavinfo_t wavinfo; wavinfo_t wavinfo;
int pos; int pos;
void (*resample)(sfxbuffer_t *, byte *, int, void *); void (*resample)(sfxbuffer_t *, byte *, int, void *);
int (*read)(void *file, byte *data, int bytes, wavinfo_t *info); int (*read)(void *file, byte *data, int bytes, wavinfo_t *info);
int (*seek)(void *file, int pos, wavinfo_t *info); int (*seek)(void *file, int pos, wavinfo_t *info);
sfxbuffer_t buffer; sfxbuffer_t buffer;
} sfxstream_t; } sfxstream_t;
@ -85,19 +85,19 @@ typedef struct sfxblock_s {
// !!! if this is changed, it much be changed in asm_i386.h too !!! // !!! if this is changed, it much be changed in asm_i386.h too !!!
struct channel_s { struct channel_s {
sfx_t *sfx; // sfx number sfx_t *sfx; // sfx number
int leftvol; // 0-255 volume int leftvol; // 0-255 volume
int rightvol; // 0-255 volume int rightvol; // 0-255 volume
unsigned int end; // end time in global paintsamples unsigned end; // end time in global paintsamples
unsigned int pos; // sample position in sfx unsigned pos; // sample position in sfx
unsigned int looping; // where to loop, -1 = no looping unsigned looping; // where to loop, -1 = no looping
int entnum; // to allow overriding a specific sound int entnum; // to allow overriding a specific sound
int entchannel; // int entchannel; //
vec3_t origin; // origin of sound effect vec3_t origin; // origin of sound effect
vec_t dist_mult; // distance multiplier (attenuation/clipK) vec_t dist_mult; // distance multiplier (attenuation/clipK)
int master_vol; // 0-255 master volume int master_vol; // 0-255 master volume
int phase; // phase shift between l-r in samples int phase; // phase shift between l-r in samples
int oldphase; // phase shift between l-r in samples int oldphase; // phase shift between l-r in samples
}; };
void SND_PaintChannels(unsigned int endtime); void SND_PaintChannels(unsigned int endtime);

View file

@ -75,6 +75,8 @@ static qboolean mus_enabled = false;
static cvar_t *bgmvolume; static cvar_t *bgmvolume;
static channel_t *cd_channel;
static sfx_t cd_sfx;
/* added by Andrew, for cd_ogg */ /* added by Andrew, for cd_ogg */
static cvar_t *mus_ogglist; // contain the filename of the ogglist. static cvar_t *mus_ogglist; // contain the filename of the ogglist.
@ -174,6 +176,7 @@ I_OGGMus_Play (int track, qboolean looping)
{ {
plitem_t *trackmap = NULL; plitem_t *trackmap = NULL;
dstring_t *trackstring = dstring_new (); dstring_t *trackstring = dstring_new ();
wavinfo_t *info;
Sys_Printf ("Entering I_OGGMus_Play\n"); Sys_Printf ("Entering I_OGGMus_Play\n");
/* alrighty. grab the list, map track to filename. grab filename from data /* alrighty. grab the list, map track to filename. grab filename from data
@ -192,7 +195,27 @@ I_OGGMus_Play (int track, qboolean looping)
} }
Sys_Printf ("Playing: %s.\n", (char *) trackmap->data); Sys_Printf ("Playing: %s.\n", (char *) trackmap->data);
S_LocalSound ((char *) trackmap->data); if (cd_channel->sfx) {
cd_channel->sfx->close (cd_channel->sfx);
memset (cd_channel, 0, sizeof (*cd_channel));
}
if (cd_sfx.name)
free ((char *) cd_sfx.name);
cd_sfx.name = strdup ((char *) trackmap->data);
SND_Load (&cd_sfx);
if (cd_sfx.wavinfo)
info = cd_sfx.wavinfo (&cd_sfx);
if (info)
info->loopstart = 0;
cd_channel->sfx = cd_sfx.open (&cd_sfx);
if (cd_channel->sfx) {
int vol = bgmvolume->value * 255;
cd_channel->master_vol = vol;
cd_channel->leftvol = cd_channel->rightvol = cd_channel->master_vol;
}
free (trackstring); free (trackstring);
playing = true; playing = true;
} }
@ -411,12 +434,21 @@ static void
Mus_VolChange (cvar_t *bgmvolume) Mus_VolChange (cvar_t *bgmvolume)
{ {
Sys_Printf ("Entering Mus_VolChange\n"); Sys_Printf ("Entering Mus_VolChange\n");
if (cd_channel->sfx) {
int vol = bgmvolume->value * 255;
cd_channel->master_vol = vol;
cd_channel->leftvol = cd_channel->rightvol = cd_channel->master_vol;
}
} }
static void static void
I_OGGMus_Init (void) I_OGGMus_Init (void)
{ {
Sys_Printf ("Entering I_OGGMus_Init\n"); Sys_Printf ("Entering I_OGGMus_Init\n");
cd_channel = S_AllocChannel ();
/* check list file cvar, open list file, create map, close file. */ /* check list file cvar, open list file, create map, close file. */
mus_ogglist = Cvar_Get ("mus_ogglist", "tracklist.cfg", CVAR_NONE, mus_ogglist = Cvar_Get ("mus_ogglist", "tracklist.cfg", CVAR_NONE,

View file

@ -50,6 +50,7 @@ static __attribute__ ((unused)) const char rcsid[] =
#include "QF/sys.h" #include "QF/sys.h"
#include "QF/sound.h" #include "QF/sound.h"
#include "QF/plugin.h" #include "QF/plugin.h"
#include "QF/va.h"
#include "snd_render.h" #include "snd_render.h"
@ -65,6 +66,11 @@ cvar_t *snd_interp;
channel_t channels[MAX_CHANNELS]; channel_t channels[MAX_CHANNELS];
int total_channels; int total_channels;
static channel_t *ambient_channels[NUM_AMBIENTS];
static channel_t *dynamic_channels[MAX_DYNAMIC_CHANNELS];
static channel_t *static_channels[MAX_CHANNELS];
static int num_statics;
static qboolean snd_initialized = false; static qboolean snd_initialized = false;
static int snd_blocked = 0; static int snd_blocked = 0;
static qboolean snd_ambient = 1; static qboolean snd_ambient = 1;
@ -170,17 +176,11 @@ s_startup (void)
// Load a sound =============================================================== // Load a sound ===============================================================
static sfx_t * static sfx_t *
s_findname (const char *name) s_load_sound (const char *name)
{ {
int i; int i;
sfx_t *sfx; sfx_t *sfx;
if (!name)
Sys_Error ("S_FindName: NULL");
if (strlen (name) >= MAX_QPATH)
Sys_Error ("Sound name too long: %s", name);
// see if already loaded // see if already loaded
for (i = 0; i < num_sfx; i++) for (i = 0; i < num_sfx; i++)
if (known_sfx[i].name && !strcmp (known_sfx[i].name, name)) { if (known_sfx[i].name && !strcmp (known_sfx[i].name, name)) {
@ -209,7 +209,11 @@ s_touch_sound (const char *name)
if (!sound_started) if (!sound_started)
return; return;
sfx = s_findname (name); if (!name)
Sys_Error ("s_touch_sound: NULL");
name = va ("sound/%s", name);
sfx = s_load_sound (name);
sfx->touch (sfx); sfx->touch (sfx);
} }
@ -221,7 +225,11 @@ s_precache_sound (const char *name)
if (!sound_started || nosound->int_val) if (!sound_started || nosound->int_val)
return NULL; return NULL;
sfx = s_findname (name); if (!name)
Sys_Error ("s_precache_sound: NULL");
name = va ("sound/%s", name);
sfx = s_load_sound (name);
// cache it in // cache it in
if (precache->int_val) { if (precache->int_val) {
@ -233,46 +241,54 @@ s_precache_sound (const char *name)
//============================================================================= //=============================================================================
static channel_t *
s_alloc_channel (void)
{
if (total_channels < MAX_CHANNELS)
return &channels[total_channels++];
return 0;
}
static channel_t * static channel_t *
s_pick_channel (int entnum, int entchannel) s_pick_channel (int entnum, int entchannel)
{ {
int ch_idx, first_to_die; int ch_idx;
unsigned life_left; unsigned life_left;
channel_t *ch, *first_to_die;
// Check for replacement sound, or find the best one to replace // Check for replacement sound, or find the best one to replace
first_to_die = -1; first_to_die = 0;
life_left = 0x7fffffff; life_left = 0x7fffffff;
for (ch_idx = NUM_AMBIENTS; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS; for (ch_idx = 0; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++) {
ch_idx++) { ch = dynamic_channels[ch_idx];
if (entchannel != 0 // channel 0 never overrides if (entchannel != 0 // channel 0 never overrides
&& channels[ch_idx].entnum == entnum && ch->entnum == entnum
&& (channels[ch_idx].entchannel == entchannel || && (ch->entchannel == entchannel || entchannel == -1)) {
entchannel == -1)) {
// always override sound from same entity // always override sound from same entity
first_to_die = ch_idx; first_to_die = ch;
break; break;
} }
// don't let monster sounds override player sounds // don't let monster sounds override player sounds
if (channels[ch_idx].entnum == *render_data.viewentity if (ch->entnum == *render_data.viewentity
&& entnum != *render_data.viewentity && entnum != *render_data.viewentity
&& channels[ch_idx].sfx) && ch->sfx)
continue; continue;
if (paintedtime + life_left > channels[ch_idx].end) { if (paintedtime + life_left > ch->end) {
life_left = channels[ch_idx].end - paintedtime; life_left = ch->end - paintedtime;
first_to_die = ch_idx; first_to_die = ch;
} }
} }
if (first_to_die == -1) if (!first_to_die)
return NULL; return NULL;
if (channels[first_to_die].sfx) { if (first_to_die->sfx) {
channels[first_to_die].sfx->close (channels[first_to_die].sfx); first_to_die->sfx->close (first_to_die->sfx);
channels[first_to_die].sfx = NULL; first_to_die->sfx = NULL;
} }
return &channels[first_to_die]; return first_to_die;
} }
static void static void
@ -376,9 +392,8 @@ s_start_sound (int entnum, int entchannel, sfx_t *sfx, const vec3_t origin,
// if an identical sound has also been started this frame, offset the pos // 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 // a bit to keep it from just making the first one louder
check = &channels[NUM_AMBIENTS]; for (ch_idx = 0; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++) {
for (ch_idx = NUM_AMBIENTS; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS; check = dynamic_channels[ch_idx];
ch_idx++, check++) {
if (check == target_chan) if (check == target_chan)
continue; continue;
if (check->sfx == sfx && !check->pos) { if (check->sfx == sfx && !check->pos) {
@ -396,17 +411,18 @@ static void
s_stop_sound (int entnum, int entchannel) s_stop_sound (int entnum, int entchannel)
{ {
int i; int i;
channel_t *ch;
if (!sound_started) if (!sound_started)
return; return;
for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++) { for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++) {
if (channels[i].entnum == entnum ch = dynamic_channels[i];
&& channels[i].entchannel == entchannel) { if (ch->entnum == entnum && ch->entchannel == entchannel) {
channels[i].end = 0; ch->end = 0;
if (channels[i].sfx) if (ch->sfx)
channels[i].sfx->close (channels[i].sfx); ch->sfx->close (ch->sfx);
channels[i].sfx = NULL; ch->sfx = NULL;
return; return;
} }
} }
@ -439,7 +455,7 @@ s_stop_all_sounds (qboolean clear)
if (!sound_started) if (!sound_started)
return; return;
total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics num_statics = 0;
for (i = 0; i < MAX_CHANNELS; i++) for (i = 0; i < MAX_CHANNELS; i++)
if (channels[i].sfx) { if (channels[i].sfx) {
@ -468,13 +484,14 @@ s_static_sound (sfx_t *sfx, const vec3_t origin, float vol,
if (!sound_started || !sfx) if (!sound_started || !sfx)
return; return;
if (total_channels == MAX_CHANNELS) { if (!static_channels[num_statics]) {
Sys_Printf ("total_channels == MAX_CHANNELS\n"); if (!(static_channels[num_statics] = s_alloc_channel ())) {
return; Sys_Printf ("ran out of channels\n");
return;
}
} }
ss = &channels[total_channels]; ss = static_channels[num_statics];
total_channels++;
if (!sfx->retain (sfx)) if (!sfx->retain (sfx))
return; return;
@ -497,6 +514,7 @@ s_static_sound (sfx_t *sfx, const vec3_t origin, float vol,
s_spatialize (ss); s_spatialize (ss);
ss->oldphase = ss->phase; ss->oldphase = ss->phase;
num_statics++;
} }
//============================================================================= //=============================================================================
@ -520,16 +538,17 @@ s_updateAmbientSounds (void)
if (!l || !ambient_level->value) { if (!l || !ambient_level->value) {
for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS; for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS;
ambient_channel++) { ambient_channel++) {
if (channels[ambient_channel].sfx) chan = ambient_channels[ambient_channel];
channels[ambient_channel].sfx->close (channels[ambient_channel].sfx); if (chan->sfx)
channels[ambient_channel].sfx = NULL; chan->sfx->close (chan->sfx);
chan->sfx = NULL;
} }
return; return;
} }
for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS; for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS;
ambient_channel++) { ambient_channel++) {
chan = &channels[ambient_channel]; chan = ambient_channels[ambient_channel];
if (!ambient_sfx[ambient_channel]) { if (!ambient_sfx[ambient_channel]) {
chan->sfx = 0; chan->sfx = 0;
continue; continue;
@ -611,6 +630,18 @@ s_update_ (void)
snd_output_funcs->pS_O_Submit (); snd_output_funcs->pS_O_Submit ();
} }
static inline int
s_update_channel (channel_t *ch)
{
if (!ch->sfx)
return 0;
ch->oldphase = ch->phase; // prepare to lerp from prev to next phase
s_spatialize (ch); // respatialize channel
if (!ch->leftvol && !ch->rightvol)
return 0;
return 1;
}
/* /*
s_update s_update
@ -637,43 +668,39 @@ s_update (const vec3_t origin, const vec3_t forward, const vec3_t right,
combine = NULL; combine = NULL;
// update spatialization for static and dynamic sounds // update spatialization for static and dynamic sounds
ch = channels + NUM_AMBIENTS; for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++)
for (i = NUM_AMBIENTS; i < total_channels; i++, ch++) { s_update_channel (dynamic_channels[i]);
if (!ch->sfx)
continue; for (i = 0; i < num_statics; i++) {
ch->oldphase = ch->phase; // prepare to lerp from prev to next ch = static_channels[i];
// phase if (!s_update_channel (ch))
s_spatialize (ch); // respatialize channel
if (!ch->leftvol && !ch->rightvol)
continue; continue;
// try to combine static sounds with a previous channel of the same // try to combine static sounds with a previous channel of the same
// sound effect so we don't mix five torches every frame // sound effect so we don't mix five torches every frame
if (i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS) { // see if it can just use the last one
// see if it can just use the last one if (combine && combine->sfx == ch->sfx) {
if (combine && combine->sfx == ch->sfx) { combine->leftvol += ch->leftvol;
combine->rightvol += ch->rightvol;
ch->leftvol = ch->rightvol = 0;
continue;
}
// search for one
for (j = 0; j < i; j++) {
combine = static_channels[j];
if (combine->sfx == ch->sfx)
break;
}
if (j == i) {
combine = NULL;
} else {
if (combine != ch) {
combine->leftvol += ch->leftvol; combine->leftvol += ch->leftvol;
combine->rightvol += ch->rightvol; combine->rightvol += ch->rightvol;
ch->leftvol = ch->rightvol = 0; ch->leftvol = ch->rightvol = 0;
continue;
}
// search for one
combine = channels + MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;
for (j = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; j < i; j++,
combine++)
if (combine->sfx == ch->sfx)
break;
if (j == total_channels) {
combine = NULL;
} else {
if (combine != ch) {
combine->leftvol += ch->leftvol;
combine->rightvol += ch->rightvol;
ch->leftvol = ch->rightvol = 0;
}
continue;
} }
continue;
} }
} }
@ -857,6 +884,13 @@ s_unblock_sound (void)
static void static void
s_init (void) s_init (void)
{ {
int i;
for (i = 0; i < NUM_AMBIENTS; i++)
ambient_channels[i] = s_alloc_channel ();
for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++)
dynamic_channels[i] = s_alloc_channel ();
snd_output_funcs = render_data.output->functions->snd_output; snd_output_funcs = render_data.output->functions->snd_output;
Sys_Printf ("\nSound Initialization\n"); Sys_Printf ("\nSound Initialization\n");
@ -997,6 +1031,8 @@ static snd_render_funcs_t plugin_info_render_funcs = {
s_local_sound, s_local_sound,
s_block_sound, s_block_sound,
s_unblock_sound, s_unblock_sound,
s_load_sound,
s_alloc_channel,
}; };
static plugin_funcs_t plugin_info_funcs = { static plugin_funcs_t plugin_info_funcs = {

View file

@ -291,7 +291,6 @@ SND_StreamAdvance (sfxbuffer_t *buffer, unsigned int count)
void void
SND_Load (sfx_t *sfx) SND_Load (sfx_t *sfx)
{ {
dstring_t *name = dstring_new ();
dstring_t *foundname = dstring_new (); dstring_t *foundname = dstring_new ();
char *realname; char *realname;
char buf[4]; char buf[4];
@ -302,22 +301,17 @@ SND_Load (sfx_t *sfx)
sfx->close = snd_noop; sfx->close = snd_noop;
sfx->open = snd_open; sfx->open = snd_open;
dsprintf (name, "sound/%s", sfx->name); _QFS_FOpenFile (sfx->name, &file, foundname, 1);
_QFS_FOpenFile (name->str, &file, foundname, 1);
if (!file) { if (!file) {
Sys_Printf ("Couldn't load %s\n", name->str); Sys_Printf ("Couldn't load %s\n", sfx->name);
dstring_delete (name);
dstring_delete (foundname); dstring_delete (foundname);
return; return;
} }
if (!strequal (foundname->str, name->str)) { if (!strequal (foundname->str, sfx->name)) {
realname = foundname->str; realname = foundname->str;
dstring_delete (name);
free (foundname); free (foundname);
} else { } else {
realname = name->str; realname = (char *) sfx->name; // won't free if realname == sfx->name
free (name);
dstring_delete (foundname);
} }
Qread (file, buf, 4); Qread (file, buf, 4);
Qseek (file, 0, SEEK_SET); Qseek (file, 0, SEEK_SET);
@ -341,7 +335,8 @@ SND_Load (sfx_t *sfx)
return; return;
} }
Qclose (file); Qclose (file);
free (realname); if (realname != sfx->name)
free (realname);
} }
sfxbuffer_t * sfxbuffer_t *

View file

@ -179,8 +179,7 @@ S_PrecacheSound (const char *sample)
{ {
if (snd_render_funcs) if (snd_render_funcs)
return snd_render_funcs->pS_PrecacheSound (sample); return snd_render_funcs->pS_PrecacheSound (sample);
else return NULL;
return NULL;
} }
void void
@ -246,3 +245,19 @@ S_UnblockSound (void)
if (snd_render_funcs) if (snd_render_funcs)
snd_render_funcs->pS_UnblockSound (); snd_render_funcs->pS_UnblockSound ();
} }
sfx_t *
S_LoadSound (const char *name)
{
if (snd_render_funcs)
return snd_render_funcs->pS_LoadSound (name);
return 0;
}
struct channel_s *
S_AllocChannel (void)
{
if (snd_render_funcs)
return snd_render_funcs->pS_AllocChannel ();
return 0;
}