mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 22:31:05 +00:00
[sound] Clean up the public API
sfx_t is now private, and cd_file no longer accesses channel_t's internals. This is necessary for hiding the code needed to make mixing and channel management *properly* lock-free (I've been getting away with murder thanks to x86's strong memory model and just plain luck with gcc).
This commit is contained in:
parent
0ebb0717b0
commit
1f16f875f6
6 changed files with 152 additions and 38 deletions
|
@ -44,7 +44,12 @@ typedef struct snd_render_funcs_s {
|
|||
void (*stop_sound) (int entnum, int entchannel);
|
||||
|
||||
struct channel_s *(*alloc_channel) (void);
|
||||
void (*channel_stop) (struct channel_s *chan);
|
||||
void (*channel_free) (struct channel_s *chan);
|
||||
int (*channel_set_sfx) (struct channel_s *chan, struct sfx_s *sfx);
|
||||
void (*channel_set_paused) (struct channel_s *chan, int paused);
|
||||
void (*channel_set_looping) (struct channel_s *chan, int looping);
|
||||
enum chan_state_e (*channel_get_state) (struct channel_s *chan);
|
||||
void (*channel_set_volume) (struct channel_s *chan, float volume);
|
||||
|
||||
struct sfx_s *(*precache_sound) (const char *sample);
|
||||
struct sfx_s *(*load_sound) (const char *name);
|
||||
|
|
|
@ -42,6 +42,15 @@ struct transform_s;
|
|||
*/
|
||||
///@{
|
||||
typedef struct sfx_s sfx_t;
|
||||
typedef struct channel_s channel_t;
|
||||
|
||||
typedef enum chan_state_e {
|
||||
chan_invalid, //!< Channel is in an invalid state and must not be used
|
||||
chan_pending, //!< Channel is waiting to be initialized
|
||||
chan_done, //!< Channel is done and should be freed
|
||||
chan_paused, //!< Channel is paused but can be resumed at any time
|
||||
chan_playing, //!< Channel is currently playing
|
||||
} chan_state;
|
||||
///@}
|
||||
|
||||
/** \defgroup sound_init Initialization functions
|
||||
|
@ -138,12 +147,24 @@ sfx_t *S_LoadSound (const char *name);
|
|||
|
||||
/** Allocate a sound channel that can be used for playing sounds.
|
||||
*/
|
||||
struct channel_s *S_AllocChannel (void);
|
||||
channel_t *S_AllocChannel (void);
|
||||
|
||||
/** Stop and safely free a channel.
|
||||
\param chan channel to stop
|
||||
*/
|
||||
void S_ChannelStop (struct channel_s *chan);
|
||||
void S_ChannelFree (channel_t *chan);
|
||||
|
||||
int S_ChannelSetSfx (channel_t *chan, sfx_t *sfx);
|
||||
void S_ChannelSetPaused (channel_t *chan, int paused);
|
||||
void S_ChannelSetLooping (channel_t *chan, int looping);
|
||||
chan_state S_ChannelGetState (channel_t *chan);
|
||||
|
||||
/** Set a channel's volume.
|
||||
\param chan The channel for which the volume will be set.
|
||||
\param volume The overall playback volume of the channel: set to 0 for
|
||||
silence, 1 for full volume.
|
||||
*/
|
||||
void S_ChannelSetVolume (channel_t *chan, float volume);
|
||||
|
||||
/** Start a sound local to the client view.
|
||||
\param s name of sound to play
|
||||
|
|
|
@ -48,7 +48,6 @@ struct transform_s;
|
|||
typedef struct portable_samplepair_s portable_samplepair_t;
|
||||
typedef struct snd_s snd_t;
|
||||
typedef struct wavinfo_s wavinfo_t;
|
||||
typedef struct channel_s channel_t;
|
||||
typedef struct sfxbuffer_s sfxbuffer_t;
|
||||
typedef struct sfxblock_s sfxblock_t;
|
||||
typedef struct sfxstream_s sfxstream_t;
|
||||
|
@ -224,7 +223,7 @@ struct sfxblock_s {
|
|||
/** Representation of a sound being played.
|
||||
*/
|
||||
struct channel_s {
|
||||
struct channel_s *next; //!< next channel in "free" list
|
||||
channel_t *next; //!< next channel in "free" list
|
||||
sfx_t *sfx; //!< sound played by this channel
|
||||
int leftvol; //!< 0-255 volume
|
||||
int rightvol; //!< 0-255 volume
|
||||
|
@ -250,7 +249,7 @@ struct channel_s {
|
|||
can be reused at any time.
|
||||
*/
|
||||
//@{
|
||||
int stop;
|
||||
int stop;
|
||||
int done;
|
||||
//@}
|
||||
};
|
||||
|
@ -342,7 +341,7 @@ extern int snd_total_channels; //!< number of active channels
|
|||
/** Allocate a sound channel that can be used for playing sounds.
|
||||
\param snd sound system state
|
||||
*/
|
||||
struct channel_s *SND_AllocChannel (snd_t *snd);
|
||||
channel_t *SND_AllocChannel (snd_t *snd);
|
||||
|
||||
/** Stop a channel from playing.
|
||||
\param snd sound system state
|
||||
|
|
|
@ -65,7 +65,6 @@
|
|||
#include "QF/plugin/cd.h"
|
||||
|
||||
#include "compat.h"
|
||||
#include "snd_internal.h"
|
||||
|
||||
/* Generic plugin structures */
|
||||
static general_data_t plugin_info_general_data;
|
||||
|
@ -107,11 +106,8 @@ static cvar_t mus_ogglist_cvar = {
|
|||
static void
|
||||
set_volume (void)
|
||||
{
|
||||
if (cd_channel && cd_channel->sfx) {
|
||||
int vol = bgmvolume * 255;
|
||||
|
||||
cd_channel->master_vol = vol;
|
||||
cd_channel->leftvol = cd_channel->rightvol = cd_channel->master_vol;
|
||||
if (cd_channel) {
|
||||
S_ChannelSetVolume (cd_channel, bgmvolume);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,7 +132,7 @@ I_OGGMus_Stop (void)
|
|||
wasPlaying = false;
|
||||
|
||||
if (cd_channel) {
|
||||
S_ChannelStop (cd_channel);
|
||||
S_ChannelFree (cd_channel);
|
||||
cd_channel = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -235,8 +231,7 @@ static void
|
|||
I_OGGMus_PlayNext (int looping)
|
||||
{
|
||||
const char *track;
|
||||
sfx_t *cd_sfx, *sfx;
|
||||
wavinfo_t *info = 0;
|
||||
sfx_t *sfx;
|
||||
|
||||
if (!play_list)
|
||||
return;
|
||||
|
@ -252,29 +247,21 @@ I_OGGMus_PlayNext (int looping)
|
|||
}
|
||||
|
||||
if (cd_channel) {
|
||||
S_ChannelStop (cd_channel);
|
||||
S_ChannelFree (cd_channel);
|
||||
cd_channel = 0;
|
||||
}
|
||||
|
||||
if (!(cd_channel = S_AllocChannel ()))
|
||||
return;
|
||||
|
||||
if (!(cd_sfx = S_LoadSound (track)) || !(sfx = cd_sfx->open (cd_sfx))) {
|
||||
S_ChannelStop (cd_channel);
|
||||
if (!(sfx = S_LoadSound (track)) || !S_ChannelSetSfx (cd_channel, sfx)) {
|
||||
S_ChannelFree (cd_channel);
|
||||
cd_channel = 0;
|
||||
return;
|
||||
}
|
||||
Sys_Printf ("Playing: %s.\n", track);
|
||||
if (sfx->wavinfo)
|
||||
info = sfx->wavinfo (sfx);
|
||||
if (info) {
|
||||
if (looping == true)
|
||||
info->loopstart = 0;
|
||||
else
|
||||
info->loopstart = -1;
|
||||
}
|
||||
cd_channel->sfx = sfx;
|
||||
S_ChannelSetLooping (cd_channel, looping ? 1 : -1);
|
||||
set_volume ();
|
||||
Sys_Printf ("Playing: %s.\n", track);
|
||||
|
||||
playing = true;
|
||||
}
|
||||
|
@ -286,7 +273,7 @@ I_OGGMus_Pause (void)
|
|||
return;
|
||||
|
||||
if (cd_channel)
|
||||
cd_channel->pause = 1;
|
||||
S_ChannelSetPaused (cd_channel, 1);
|
||||
|
||||
wasPlaying = playing;
|
||||
playing = false;
|
||||
|
@ -299,7 +286,7 @@ I_OGGMus_Resume (void)
|
|||
return;
|
||||
|
||||
set_volume ();
|
||||
cd_channel->pause = 0;
|
||||
S_ChannelSetPaused (cd_channel, 0);
|
||||
wasPlaying = false;
|
||||
playing = true;
|
||||
}
|
||||
|
@ -446,7 +433,7 @@ I_OGG_f (void)
|
|||
static void
|
||||
I_OGGMus_Update (void)
|
||||
{
|
||||
if (!cd_channel || !cd_channel->done)
|
||||
if (!cd_channel || S_ChannelGetState (cd_channel) > chan_done)
|
||||
return;
|
||||
// will get here only when multi-tracked
|
||||
I_OGGMus_Stop ();
|
||||
|
|
|
@ -465,13 +465,67 @@ s_load_sound (const char *name)
|
|||
}
|
||||
|
||||
static void
|
||||
s_channel_stop (channel_t *chan)
|
||||
s_channel_free (channel_t *chan)
|
||||
{
|
||||
if (!sound_started)
|
||||
return;
|
||||
SND_ChannelStop (&snd, chan);
|
||||
}
|
||||
|
||||
static int
|
||||
s_channel_set_sfx (channel_t *chan, sfx_t *sfx)
|
||||
{
|
||||
sfx_t *s = sfx->open (sfx);
|
||||
if (!s) {
|
||||
return 0;
|
||||
}
|
||||
chan->sfx = s;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
s_channel_set_paused (channel_t *chan, int paused)
|
||||
{
|
||||
chan->pause = paused != 0;
|
||||
}
|
||||
|
||||
static void
|
||||
s_channel_set_looping (channel_t *chan, int looping)
|
||||
{
|
||||
// FIXME implement
|
||||
}
|
||||
|
||||
static chan_state
|
||||
s_channel_get_state (channel_t *chan)
|
||||
{
|
||||
// stop means the channel has been "freed" and is waiting for the mixer
|
||||
// thread to be done with it, thus putting the channel in an invalid state
|
||||
// from the user's point of view. ie, don't touch (user should set channel
|
||||
// pointer to null).
|
||||
if (!chan->stop) {
|
||||
if (chan->done) {
|
||||
// The mixer has finished mixing the channel (come to the end).
|
||||
return chan_done;
|
||||
}
|
||||
if (!chan->sfx) {
|
||||
// channel requires initialization
|
||||
return chan_pending;
|
||||
}
|
||||
if (chan->pause) {
|
||||
return chan_paused;
|
||||
}
|
||||
return chan_playing;
|
||||
}
|
||||
return chan_invalid;
|
||||
}
|
||||
|
||||
static void
|
||||
s_channel_set_volume (channel_t *chan, float volume)
|
||||
{
|
||||
chan->master_vol = volume * 256; //FIXME
|
||||
chan->leftvol = chan->rightvol = chan->master_vol;
|
||||
}
|
||||
|
||||
static void
|
||||
s_local_sound (const char *sound)
|
||||
{
|
||||
|
@ -506,7 +560,12 @@ static snd_render_funcs_t plugin_info_render_funcs = {
|
|||
.stop_sound = s_stop_sound,
|
||||
|
||||
.alloc_channel = s_alloc_channel,
|
||||
.channel_stop = s_channel_stop,
|
||||
.channel_free = s_channel_free,
|
||||
.channel_set_sfx = s_channel_set_sfx,
|
||||
.channel_set_paused = s_channel_set_paused,
|
||||
.channel_set_looping = s_channel_set_looping,
|
||||
.channel_get_state = s_channel_get_state,
|
||||
.channel_set_volume = s_channel_set_volume,
|
||||
|
||||
.precache_sound = s_precache_sound,
|
||||
.load_sound = s_load_sound,
|
||||
|
|
|
@ -229,7 +229,7 @@ S_LoadSound (const char *name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
VISIBLE struct channel_s *
|
||||
VISIBLE channel_t *
|
||||
S_AllocChannel (void)
|
||||
{
|
||||
if (snd_render_funcs)
|
||||
|
@ -238,8 +238,51 @@ S_AllocChannel (void)
|
|||
}
|
||||
|
||||
VISIBLE void
|
||||
S_ChannelStop (struct channel_s *chan)
|
||||
S_ChannelFree (channel_t *chan)
|
||||
{
|
||||
if (snd_render_funcs)
|
||||
snd_render_funcs->channel_stop (chan);
|
||||
if (snd_render_funcs) {
|
||||
snd_render_funcs->channel_free (chan);
|
||||
}
|
||||
}
|
||||
|
||||
VISIBLE int
|
||||
S_ChannelSetSfx (channel_t *chan, sfx_t *sfx)
|
||||
{
|
||||
if (snd_render_funcs) {
|
||||
return snd_render_funcs->channel_set_sfx (chan, sfx);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
VISIBLE void
|
||||
S_ChannelSetPaused (channel_t *chan, int paused)
|
||||
{
|
||||
if (snd_render_funcs) {
|
||||
snd_render_funcs->channel_set_paused (chan, paused);
|
||||
}
|
||||
}
|
||||
|
||||
VISIBLE void
|
||||
S_ChannelSetLooping (channel_t *chan, int looping)
|
||||
{
|
||||
if (snd_render_funcs) {
|
||||
snd_render_funcs->channel_set_looping (chan, looping);
|
||||
}
|
||||
}
|
||||
|
||||
VISIBLE chan_state
|
||||
S_ChannelGetState (channel_t *chan)
|
||||
{
|
||||
if (snd_render_funcs) {
|
||||
return snd_render_funcs->channel_get_state (chan);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
VISIBLE void
|
||||
S_ChannelSetVolume (channel_t *chan, float volume)
|
||||
{
|
||||
if (snd_render_funcs) {
|
||||
snd_render_funcs->channel_set_volume (chan, volume);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue