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_BlockSound) (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 {
P_S_AmbientOff pS_AmbientOff;
@ -73,6 +75,8 @@ typedef struct snd_render_funcs_s {
P_S_LocalSound pS_LocalSound;
P_S_BlockSound pS_BlockSound;
P_S_UnblockSound pS_UnblockSound;
P_S_LoadSound pS_LoadSound;
P_S_AllocChannel pS_AllocChannel;
} snd_render_funcs_t;
typedef struct snd_render_data_s {

View file

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

View file

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

View file

@ -75,6 +75,8 @@ static qboolean mus_enabled = false;
static cvar_t *bgmvolume;
static channel_t *cd_channel;
static sfx_t cd_sfx;
/* added by Andrew, for cd_ogg */
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;
dstring_t *trackstring = dstring_new ();
wavinfo_t *info;
Sys_Printf ("Entering I_OGGMus_Play\n");
/* 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);
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);
playing = true;
}
@ -411,12 +434,21 @@ static void
Mus_VolChange (cvar_t *bgmvolume)
{
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
I_OGGMus_Init (void)
{
Sys_Printf ("Entering I_OGGMus_Init\n");
cd_channel = S_AllocChannel ();
/* check list file cvar, open list file, create map, close file. */
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/sound.h"
#include "QF/plugin.h"
#include "QF/va.h"
#include "snd_render.h"
@ -65,6 +66,11 @@ cvar_t *snd_interp;
channel_t channels[MAX_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 int snd_blocked = 0;
static qboolean snd_ambient = 1;
@ -170,17 +176,11 @@ s_startup (void)
// Load a sound ===============================================================
static sfx_t *
s_findname (const char *name)
s_load_sound (const char *name)
{
int i;
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
for (i = 0; i < num_sfx; i++)
if (known_sfx[i].name && !strcmp (known_sfx[i].name, name)) {
@ -209,7 +209,11 @@ s_touch_sound (const char *name)
if (!sound_started)
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);
}
@ -221,7 +225,11 @@ s_precache_sound (const char *name)
if (!sound_started || nosound->int_val)
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
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 *
s_pick_channel (int entnum, int entchannel)
{
int ch_idx, first_to_die;
int ch_idx;
unsigned life_left;
channel_t *ch, *first_to_die;
// Check for replacement sound, or find the best one to replace
first_to_die = -1;
first_to_die = 0;
life_left = 0x7fffffff;
for (ch_idx = NUM_AMBIENTS; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS;
ch_idx++) {
for (ch_idx = 0; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++) {
ch = dynamic_channels[ch_idx];
if (entchannel != 0 // channel 0 never overrides
&& channels[ch_idx].entnum == entnum
&& (channels[ch_idx].entchannel == entchannel ||
entchannel == -1)) {
&& ch->entnum == entnum
&& (ch->entchannel == entchannel || entchannel == -1)) {
// always override sound from same entity
first_to_die = ch_idx;
first_to_die = ch;
break;
}
// 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
&& channels[ch_idx].sfx)
&& ch->sfx)
continue;
if (paintedtime + life_left > channels[ch_idx].end) {
life_left = channels[ch_idx].end - paintedtime;
first_to_die = ch_idx;
if (paintedtime + life_left > ch->end) {
life_left = ch->end - paintedtime;
first_to_die = ch;
}
}
if (first_to_die == -1)
if (!first_to_die)
return NULL;
if (channels[first_to_die].sfx) {
channels[first_to_die].sfx->close (channels[first_to_die].sfx);
channels[first_to_die].sfx = NULL;
if (first_to_die->sfx) {
first_to_die->sfx->close (first_to_die->sfx);
first_to_die->sfx = NULL;
}
return &channels[first_to_die];
return first_to_die;
}
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
// a bit to keep it from just making the first one louder
check = &channels[NUM_AMBIENTS];
for (ch_idx = NUM_AMBIENTS; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS;
ch_idx++, check++) {
for (ch_idx = 0; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++) {
check = dynamic_channels[ch_idx];
if (check == target_chan)
continue;
if (check->sfx == sfx && !check->pos) {
@ -396,17 +411,18 @@ static void
s_stop_sound (int entnum, int entchannel)
{
int i;
channel_t *ch;
if (!sound_started)
return;
for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++) {
if (channels[i].entnum == entnum
&& channels[i].entchannel == entchannel) {
channels[i].end = 0;
if (channels[i].sfx)
channels[i].sfx->close (channels[i].sfx);
channels[i].sfx = NULL;
ch = dynamic_channels[i];
if (ch->entnum == entnum && ch->entchannel == entchannel) {
ch->end = 0;
if (ch->sfx)
ch->sfx->close (ch->sfx);
ch->sfx = NULL;
return;
}
}
@ -439,7 +455,7 @@ s_stop_all_sounds (qboolean clear)
if (!sound_started)
return;
total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics
num_statics = 0;
for (i = 0; i < MAX_CHANNELS; i++)
if (channels[i].sfx) {
@ -468,13 +484,14 @@ s_static_sound (sfx_t *sfx, const vec3_t origin, float vol,
if (!sound_started || !sfx)
return;
if (total_channels == MAX_CHANNELS) {
Sys_Printf ("total_channels == MAX_CHANNELS\n");
return;
if (!static_channels[num_statics]) {
if (!(static_channels[num_statics] = s_alloc_channel ())) {
Sys_Printf ("ran out of channels\n");
return;
}
}
ss = &channels[total_channels];
total_channels++;
ss = static_channels[num_statics];
if (!sfx->retain (sfx))
return;
@ -497,6 +514,7 @@ s_static_sound (sfx_t *sfx, const vec3_t origin, float vol,
s_spatialize (ss);
ss->oldphase = ss->phase;
num_statics++;
}
//=============================================================================
@ -520,16 +538,17 @@ s_updateAmbientSounds (void)
if (!l || !ambient_level->value) {
for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS;
ambient_channel++) {
if (channels[ambient_channel].sfx)
channels[ambient_channel].sfx->close (channels[ambient_channel].sfx);
channels[ambient_channel].sfx = NULL;
chan = ambient_channels[ambient_channel];
if (chan->sfx)
chan->sfx->close (chan->sfx);
chan->sfx = NULL;
}
return;
}
for (ambient_channel = 0; ambient_channel < NUM_AMBIENTS;
ambient_channel++) {
chan = &channels[ambient_channel];
chan = ambient_channels[ambient_channel];
if (!ambient_sfx[ambient_channel]) {
chan->sfx = 0;
continue;
@ -611,6 +630,18 @@ s_update_ (void)
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
@ -637,43 +668,39 @@ s_update (const vec3_t origin, const vec3_t forward, const vec3_t right,
combine = NULL;
// update spatialization for static and dynamic sounds
ch = channels + NUM_AMBIENTS;
for (i = NUM_AMBIENTS; i < total_channels; i++, ch++) {
if (!ch->sfx)
continue;
ch->oldphase = ch->phase; // prepare to lerp from prev to next
// phase
s_spatialize (ch); // respatialize channel
if (!ch->leftvol && !ch->rightvol)
for (i = 0; i < MAX_DYNAMIC_CHANNELS; i++)
s_update_channel (dynamic_channels[i]);
for (i = 0; i < num_statics; i++) {
ch = static_channels[i];
if (!s_update_channel (ch))
continue;
// try to combine static sounds with a previous channel of the same
// 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
if (combine && combine->sfx == ch->sfx) {
// see if it can just use the last one
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->rightvol += ch->rightvol;
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
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;
Sys_Printf ("\nSound Initialization\n");
@ -997,6 +1031,8 @@ static snd_render_funcs_t plugin_info_render_funcs = {
s_local_sound,
s_block_sound,
s_unblock_sound,
s_load_sound,
s_alloc_channel,
};
static plugin_funcs_t plugin_info_funcs = {

View file

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

View file

@ -179,8 +179,7 @@ S_PrecacheSound (const char *sample)
{
if (snd_render_funcs)
return snd_render_funcs->pS_PrecacheSound (sample);
else
return NULL;
return NULL;
}
void
@ -246,3 +245,19 @@ S_UnblockSound (void)
if (snd_render_funcs)
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;
}