[audio] Rework alsa to use a pull model

This brings the alsa driver in line with the jack render (progress
towards #16), but breaks most of the other drivers (for now: one step at
a time). The idea is that once the pull model is working for at least
one other target, the jack renderer can become just another target like
it should have been in the first place (but I needed to get the pull
model working first, then forgot about it).

Correct state checking is not done yet, but testsound does produce what
seems to be fairly good sound when it starts up correctly (part of the
state checking (or lack thereof), I imagine).
This commit is contained in:
Bill Currie 2021-06-24 00:04:02 +09:00
parent c9319966ce
commit fc907e232f
13 changed files with 506 additions and 331 deletions

View file

@ -30,23 +30,15 @@
#include <QF/plugin.h> #include <QF/plugin.h>
#include <QF/qtypes.h> #include <QF/qtypes.h>
/* struct snd_s;
All sound plugins must export these functions
*/
typedef volatile struct dma_s *(*P_S_O_Init) (void);
typedef void (*P_S_O_Shutdown) (void);
typedef int (*P_S_O_GetDMAPos) (void);
typedef void (*P_S_O_Submit) (void);
typedef void (*P_S_O_BlockSound) (void);
typedef void (*P_S_O_UnblockSound) (void);
typedef struct snd_output_funcs_s { typedef struct snd_output_funcs_s {
P_S_O_Init pS_O_Init; int (*init) (struct snd_s *snd);
P_S_O_Shutdown pS_O_Shutdown; void (*shutdown) (struct snd_s *snd);
P_S_O_GetDMAPos pS_O_GetDMAPos; int (*get_dma_pos) (struct snd_s *snd);
P_S_O_Submit pS_O_Submit; void (*submit) (struct snd_s *snd);
P_S_O_BlockSound pS_O_BlockSound; void (*block_sound) (struct snd_s *snd);
P_S_O_UnblockSound pS_O_UnblockSound; void (*unblock_sound) (struct snd_s *snd);
} snd_output_funcs_t; } snd_output_funcs_t;
typedef struct snd_output_data_s { typedef struct snd_output_data_s {

View file

@ -41,6 +41,7 @@
typedef struct sfx_s sfx_t; typedef struct sfx_s sfx_t;
struct sfx_s struct sfx_s
{ {
struct snd_s *snd; //!< ownding snd_t instance
const char *name; const char *name;
sfx_t *owner; sfx_t *owner;

View file

@ -67,6 +67,11 @@ QF_ALSA_NEED (int, snd_pcm_sw_params_set_stop_threshold, (snd_pcm_t *pcm, snd_pc
QF_ALSA_NEED (size_t, snd_pcm_sw_params_sizeof, (void)) QF_ALSA_NEED (size_t, snd_pcm_sw_params_sizeof, (void))
QF_ALSA_NEED (const char *, snd_strerror, (int errnum)) QF_ALSA_NEED (const char *, snd_strerror, (int errnum))
QF_ALSA_NEED (int, snd_async_add_pcm_handler, (snd_async_handler_t **handler, snd_pcm_t *pcm, snd_async_callback_t callback, void *private_data))
QF_ALSA_NEED (snd_pcm_t *, snd_async_handler_get_pcm, (snd_async_handler_t *handler))
QF_ALSA_NEED (void *, snd_async_handler_get_callback_private, (snd_async_handler_t *handler))
QF_ALSA_NEED (int, snd_async_del_handler, (snd_async_handler_t *handler))
#ifdef UNDEF_QF_ALSA_NEED #ifdef UNDEF_QF_ALSA_NEED
#undef QF_ALSA_NEED #undef QF_ALSA_NEED
#undef UNDEF_QF_ALSA_NEED #undef UNDEF_QF_ALSA_NEED

View file

@ -45,7 +45,7 @@
#include "QF/zone.h" #include "QF/zone.h"
typedef struct portable_samplepair_s portable_samplepair_t; typedef struct portable_samplepair_s portable_samplepair_t;
typedef struct dma_s dma_t; typedef struct snd_s snd_t;
typedef struct wavinfo_s wavinfo_t; typedef struct wavinfo_s 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;
@ -70,7 +70,7 @@ struct portable_samplepair_s {
/** communication structure between output drivers and renderer /** communication structure between output drivers and renderer
*/ */
struct dma_s { struct snd_s {
int speed; //!< sample rate int speed; //!< sample rate
int samplebits; //!< bits per sample int samplebits; //!< bits per sample
int channels; //!< number of output channels int channels; //!< number of output channels
@ -84,7 +84,8 @@ struct dma_s {
\param count The number of sample to transfer. \param count The number of sample to transfer.
\param volume The gain for the samples. \param volume The gain for the samples.
*/ */
void (*xfer) (portable_samplepair_t *paintbuffer, int count, void (*xfer) (struct snd_s *snd,
portable_samplepair_t *paintbuffer, int count,
float volume); float volume);
/** Optional data for the xfer function. /** Optional data for the xfer function.
*/ */
@ -229,8 +230,6 @@ extern struct cvar_s *snd_volume;
extern struct cvar_s *snd_interp; extern struct cvar_s *snd_interp;
extern struct cvar_s *snd_stereo_phase_separation; extern struct cvar_s *snd_stereo_phase_separation;
extern volatile dma_t *snd_shm;
extern snd_render_data_t snd_render_data; extern snd_render_data_t snd_render_data;
#define PAINTBUFFER_SIZE 512 #define PAINTBUFFER_SIZE 512
extern portable_samplepair_t snd_paintbuffer[PAINTBUFFER_SIZE * 2]; extern portable_samplepair_t snd_paintbuffer[PAINTBUFFER_SIZE * 2];
@ -279,16 +278,16 @@ void SND_SFX_StreamClose (sfx_t *sfx);
/** Pre-load a sound into the cache. /** Pre-load a sound into the cache.
\param sample name of sound to precache \param sample name of sound to precache
*/ */
sfx_t *SND_PrecacheSound (const char *sample); sfx_t *SND_PrecacheSound (snd_t *snd, const char *sample);
/** Pre-load a sound. /** Pre-load a sound.
\param name name of sound to load \param name name of sound to load
*/ */
sfx_t *SND_LoadSound (const char *name); sfx_t *SND_LoadSound (snd_t *snd, const char *name);
/** Initialize the sfx sub-subsystem /** Initialize the sfx sub-subsystem
*/ */
void SND_SFX_Init (void); void SND_SFX_Init (snd_t *snd);
///@} ///@}
@ -312,29 +311,29 @@ extern int snd_total_channels; //!< number of active channels
/** Allocate a sound channel that can be used for playing sounds. /** Allocate a sound channel that can be used for playing sounds.
*/ */
struct channel_s *SND_AllocChannel (void); struct channel_s *SND_AllocChannel (snd_t *snd);
/** Stop a channel from playing. /** Stop a channel from playing.
\param chan the channel to stop \param chan the channel to stop
*/ */
void SND_ChannelStop (channel_t *chan); void SND_ChannelStop (snd_t *snd, channel_t *chan);
/** Scan channels looking for stopped channels. /** Scan channels looking for stopped channels.
\param wait if true, wait for the channels to be done. if false, force the \param wait if true, wait for the channels to be done. if false, force the
channels to be done. true is for threaded, false for channels to be done. true is for threaded, false for
non-threaded. non-threaded.
*/ */
void SND_ScanChannels (int wait); void SND_ScanChannels (snd_t *snd, int wait);
/** Disable ambient sounds. /** Disable ambient sounds.
\todo not used, remove? \todo not used, remove?
*/ */
void SND_AmbientOff (void); void SND_AmbientOff (snd_t *snd);
/** Enable ambient sounds. /** Enable ambient sounds.
\todo not used, remove? \todo not used, remove?
*/ */
void SND_AmbientOn (void); void SND_AmbientOn (snd_t *snd);
/** Update the sound engine with the client's position and orientation and /** Update the sound engine with the client's position and orientation and
render some sound. render some sound.
@ -345,17 +344,17 @@ void SND_AmbientOn (void);
\param ambient_sound_level Pointer to 4 bytes indicating the levels at \param ambient_sound_level Pointer to 4 bytes indicating the levels at
which to play the ambient sounds. which to play the ambient sounds.
*/ */
void SND_SetListener (const vec3_t origin, const vec3_t v_forward, void SND_SetListener (snd_t *snd, const vec3_t origin, const vec3_t v_forward,
const vec3_t v_right, const vec3_t v_up, const vec3_t v_right, const vec3_t v_up,
const byte *ambient_sound_level); const byte *ambient_sound_level);
/** Stop all sounds from playing. /** Stop all sounds from playing.
*/ */
void SND_StopAllSounds(void); void SND_StopAllSounds (snd_t *snd);
/** Initialize the channels sub-subsystem /** Initialize the channels sub-subsystem
*/ */
void SND_Channels_Init (void); void SND_Channels_Init (snd_t *snd);
/** Start a sound playing. /** Start a sound playing.
\param entnum index of entity the sound is associated with. \param entnum index of entity the sound is associated with.
@ -370,8 +369,8 @@ void SND_Channels_Init (void);
\param fvol absolute volume of the sound \param fvol absolute volume of the sound
\param attenuation rate of volume dropoff vs distance \param attenuation rate of volume dropoff vs distance
*/ */
void SND_StartSound (int entnum, int entchannel, sfx_t *sfx, const vec3_t origin, void SND_StartSound (snd_t *snd, int entnum, int entchannel, sfx_t *sfx,
float fvol, float attenuation); const vec3_t origin, float fvol, float attenuation);
/** Create a sound generated by the world. /** Create a sound generated by the world.
\param sfx sound to play \param sfx sound to play
@ -379,18 +378,18 @@ void SND_StartSound (int entnum, int entchannel, sfx_t *sfx, const vec3_t origin
\param vol absolute volume of the sound \param vol absolute volume of the sound
\param attenuation rate of volume dropoff vs distance \param attenuation rate of volume dropoff vs distance
*/ */
void SND_StaticSound (sfx_t *sfx, const vec3_t origin, float vol, void SND_StaticSound (snd_t *snd, sfx_t *sfx, const vec3_t origin, float vol,
float attenuation); float attenuation);
/** Stop an entity's sound. /** Stop an entity's sound.
\param entnum index of entity the sound is associated with. \param entnum index of entity the sound is associated with.
\param entchannel channel to silence \param entchannel channel to silence
*/ */
void SND_StopSound (int entnum, int entchannel); void SND_StopSound (snd_t *snd, int entnum, int entchannel);
/** Start a sound local to the client view. /** Start a sound local to the client view.
\param s name of sound to play \param s name of sound to play
*/ */
void SND_LocalSound (const char *s); void SND_LocalSound (snd_t *snd, const char *s);
///@} ///@}
@ -405,11 +404,11 @@ extern unsigned snd_paintedtime;
/** Mix all active channels into the output buffer. /** Mix all active channels into the output buffer.
\param endtime sample time until when to mix \param endtime sample time until when to mix
*/ */
void SND_PaintChannels(unsigned int endtime); void SND_PaintChannels(snd_t *snd, unsigned int endtime);
/** Initialize the scale table for painting of 8 bit samples. /** Initialize the scale table for painting of 8 bit samples.
*/ */
void SND_InitScaletable (void); void SND_InitScaletable (snd_t *snd);
/** Set the paint function of the sfxbuffer /** Set the paint function of the sfxbuffer
\param sc sfxbuffer to set. \param sc sfxbuffer to set.
@ -447,8 +446,8 @@ void SND_Resample (sfxbuffer_t *sc, float *data, int length);
\param channels number of channels per frame \param channels number of channels per frame
\param width bytes per channel \param width bytes per channel
*/ */
void SND_Convert (byte *idata, float *fdata, int frames, int channels, void SND_Convert (byte *idata, float *fdata, int frames,
int width); int channels, int width);
///@} ///@}
@ -492,7 +491,7 @@ int SND_LoadWav (QFile *file, sfx_t *sfx, char *realname);
\param realname path of sound file should it need to be re-opened \param realname path of sound file should it need to be re-opened
\return 0 if ok, -1 on error \return 0 if ok, -1 on error
*/ */
int SND_LoadMidi (QFile *file, sfx_t *sfx, char *realname); int SND_LoadMidi (snd_t *snd, QFile *file, sfx_t *sfx, char *realname);
///@} ///@}
/** \defgroup sound_render_cache_stream Cache/Stream Functions. /** \defgroup sound_render_cache_stream Cache/Stream Functions.

View file

@ -85,7 +85,7 @@ unlink_channel (channel_t **_ch)
} }
channel_t * channel_t *
SND_AllocChannel (void) SND_AllocChannel (snd_t *snd)
{ {
channel_t **free = &free_channels; channel_t **free = &free_channels;
channel_t *chan; channel_t *chan;
@ -124,7 +124,7 @@ SND_AllocChannel (void)
} }
void void
SND_ChannelStop (channel_t *chan) SND_ChannelStop (snd_t *snd, channel_t *chan)
{ {
/* if chan->next is set, then this channel may have already been freed. /* if chan->next is set, then this channel may have already been freed.
a rather serious bug as it will create a loop in the free list a rather serious bug as it will create a loop in the free list
@ -137,13 +137,13 @@ SND_ChannelStop (channel_t *chan)
} }
void void
SND_ScanChannels (int wait) SND_ScanChannels (snd_t *snd, int wait)
{ {
int i; int i;
channel_t *ch; channel_t *ch;
int count = 0; int count = 0;
if (!snd_shm || !snd_shm->speed) if (!snd || !snd->speed)
return; return;
if (wait) { if (wait) {
@ -184,23 +184,23 @@ SND_ScanChannels (int wait)
} }
void void
SND_StopAllSounds (void) SND_StopAllSounds (snd_t *snd)
{ {
int i; int i;
snd_num_statics = 0; snd_num_statics = 0;
while (dynamic_channels) while (dynamic_channels)
SND_ChannelStop (unlink_channel (&dynamic_channels)); SND_ChannelStop (snd, unlink_channel (&dynamic_channels));
while (looped_dynamic_channels) while (looped_dynamic_channels)
SND_ChannelStop (unlink_channel (&looped_dynamic_channels)); SND_ChannelStop (snd, unlink_channel (&looped_dynamic_channels));
for (i = 0; i < NUM_AMBIENTS; i++) { for (i = 0; i < NUM_AMBIENTS; i++) {
if (ambient_channels[i]) if (ambient_channels[i])
SND_ChannelStop (ambient_channels[i]); SND_ChannelStop (snd, ambient_channels[i]);
ambient_channels[i] = 0; ambient_channels[i] = 0;
} }
for (i = 0; i < MAX_STATIC_CHANNELS; i++) { for (i = 0; i < MAX_STATIC_CHANNELS; i++) {
if (static_channels[i]) if (static_channels[i])
SND_ChannelStop (static_channels[i]); SND_ChannelStop (snd, static_channels[i]);
static_channels[i] = 0; static_channels[i] = 0;
} }
if (0) { if (0) {
@ -217,8 +217,9 @@ SND_StopAllSounds (void)
} }
static void static void
s_play_f (void) s_play_f (void *_snd)
{ {
snd_t *snd = _snd;
dstring_t *name = dstring_new (); dstring_t *name = dstring_new ();
int i; int i;
static int hash = 345; static int hash = 345;
@ -231,16 +232,17 @@ s_play_f (void)
} else { } else {
dsprintf (name, "%s", Cmd_Argv (i)); dsprintf (name, "%s", Cmd_Argv (i));
} }
sfx = SND_PrecacheSound (name->str); sfx = SND_PrecacheSound (snd, name->str);
SND_StartSound (hash++, 0, sfx, listener_origin, 1.0, 1.0); SND_StartSound (snd, hash++, 0, sfx, listener_origin, 1.0, 1.0);
i++; i++;
} }
dstring_delete (name); dstring_delete (name);
} }
static void static void
s_playcenter_f (void) s_playcenter_f (void *_snd)
{ {
snd_t *snd = _snd;
dstring_t *name = dstring_new (); dstring_t *name = dstring_new ();
int i; int i;
sfx_t *sfx; sfx_t *sfx;
@ -255,15 +257,16 @@ s_playcenter_f (void)
} else { } else {
dsprintf (name, "%s", Cmd_Argv (i)); dsprintf (name, "%s", Cmd_Argv (i));
} }
sfx = SND_PrecacheSound (name->str); sfx = SND_PrecacheSound (snd, name->str);
SND_StartSound (viewent, 0, sfx, listener_origin, 1.0, 1.0); SND_StartSound (snd, viewent, 0, sfx, listener_origin, 1.0, 1.0);
} }
dstring_delete (name); dstring_delete (name);
} }
static void static void
s_playvol_f (void) s_playvol_f (void *_snd)
{ {
snd_t *snd = _snd;
dstring_t *name = dstring_new (); dstring_t *name = dstring_new ();
float vol; float vol;
int i; int i;
@ -277,9 +280,9 @@ s_playvol_f (void)
} else { } else {
dsprintf (name, "%s", Cmd_Argv (i)); dsprintf (name, "%s", Cmd_Argv (i));
} }
sfx = SND_PrecacheSound (name->str); sfx = SND_PrecacheSound (snd, name->str);
vol = atof (Cmd_Argv (i + 1)); vol = atof (Cmd_Argv (i + 1));
SND_StartSound (hash++, 0, sfx, listener_origin, vol, 1.0); SND_StartSound (snd, hash++, 0, sfx, listener_origin, vol, 1.0);
i += 2; i += 2;
} }
dstring_delete (name); dstring_delete (name);
@ -291,14 +294,15 @@ s_channels_gamedir (int phase)
//FIXME for some reason, a gamedir change causes semi-random //FIXME for some reason, a gamedir change causes semi-random
//"already released" cache errors. fortunatly, servers don't change //"already released" cache errors. fortunatly, servers don't change
//gamedir often, so I'll put this in the too-hard basket for now. //gamedir often, so I'll put this in the too-hard basket for now.
if (phase) { //XXX FIXME set ambient sounds
ambient_sfx[AMBIENT_WATER] = SND_PrecacheSound ("ambience/water1.wav"); //if (phase) {
ambient_sfx[AMBIENT_SKY] = SND_PrecacheSound ("ambience/wind2.wav"); // ambient_sfx[AMBIENT_WATER] = SND_PrecacheSound (snd, "ambience/water1.wav");
} // ambient_sfx[AMBIENT_SKY] = SND_PrecacheSound (snd, "ambience/wind2.wav");
//}
} }
void void
SND_Channels_Init (void) SND_Channels_Init (snd_t *snd)
{ {
int i; int i;
@ -315,12 +319,14 @@ SND_Channels_Init (void)
ambient_level = Cvar_Get ("ambient_level", "0.3", CVAR_NONE, NULL, ambient_level = Cvar_Get ("ambient_level", "0.3", CVAR_NONE, NULL,
"Ambient sounds' volume"); "Ambient sounds' volume");
Cmd_AddCommand ("play", s_play_f, Cmd_AddDataCommand ("play", s_play_f, snd,
"Play selected sound effect (play pathto/sound.wav)"); "Play selected sound effect (play pathto/sound.wav)");
Cmd_AddCommand ("playcenter", s_playcenter_f, Cmd_AddDataCommand ("playcenter", s_playcenter_f, snd,
"Play selected sound effect without 3D spatialization."); "Play selected sound effect without 3D "
Cmd_AddCommand ("playvol", s_playvol_f, "Play selected sound effect at " "spatialization.");
"selected volume (playvol pathto/sound.wav num"); Cmd_AddDataCommand ("playvol", s_playvol_f, snd,
"Play selected sound effect at selected volume "
"(playvol pathto/sound.wav num");
for (i = 0; i < MAX_CHANNELS - 1; i++) for (i = 0; i < MAX_CHANNELS - 1; i++)
snd_channels[i].next = &snd_channels[i + 1]; snd_channels[i].next = &snd_channels[i + 1];
@ -333,14 +339,14 @@ SND_Channels_Init (void)
} }
static channel_t * static channel_t *
s_pick_channel (int entnum, int entchannel, int looped) s_pick_channel (snd_t *snd, int entnum, int entchannel, int looped)
{ {
channel_t *ch, **_ch; channel_t *ch, **_ch;
// check for finished non-looped sounds // check for finished non-looped sounds
for (_ch = &dynamic_channels; *_ch; ) { for (_ch = &dynamic_channels; *_ch; ) {
if (!(*_ch)->sfx || (*_ch)->done) { if (!(*_ch)->sfx || (*_ch)->done) {
SND_ChannelStop (unlink_channel (_ch)); SND_ChannelStop (snd, unlink_channel (_ch));
continue; continue;
} }
_ch = &(*_ch)->next; _ch = &(*_ch)->next;
@ -352,13 +358,13 @@ s_pick_channel (int entnum, int entchannel, int looped)
if (!(*_ch)->sfx || (*_ch)->done if (!(*_ch)->sfx || (*_ch)->done
|| ((*_ch)->entnum == entnum || ((*_ch)->entnum == entnum
&& ((*_ch)->entchannel == entchannel || entchannel == -1))) { && ((*_ch)->entchannel == entchannel || entchannel == -1))) {
SND_ChannelStop (unlink_channel (_ch)); SND_ChannelStop (snd, unlink_channel (_ch));
continue; continue;
} }
_ch = &(*_ch)->next; _ch = &(*_ch)->next;
} }
_ch = looped ? &looped_dynamic_channels : &dynamic_channels; _ch = looped ? &looped_dynamic_channels : &dynamic_channels;
if ((ch = SND_AllocChannel ())) { if ((ch = SND_AllocChannel (snd))) {
ch->next = *_ch; ch->next = *_ch;
*_ch = ch; *_ch = ch;
} }
@ -366,19 +372,19 @@ s_pick_channel (int entnum, int entchannel, int looped)
} }
void void
SND_AmbientOff (void) SND_AmbientOff (snd_t *snd)
{ {
snd_ambient = false; snd_ambient = false;
} }
void void
SND_AmbientOn (void) SND_AmbientOn (snd_t *snd)
{ {
snd_ambient = true; snd_ambient = true;
} }
static void static void
s_updateAmbientSounds (const byte *ambient_sound_level) s_updateAmbientSounds (snd_t *snd, const byte *ambient_sound_level)
{ {
float vol; float vol;
int ambient_channel; int ambient_channel;
@ -410,7 +416,7 @@ s_updateAmbientSounds (const byte *ambient_sound_level)
chan = ambient_channels[ambient_channel]; chan = ambient_channels[ambient_channel];
if (!chan) { if (!chan) {
chan = ambient_channels[ambient_channel] = SND_AllocChannel (); chan = ambient_channels[ambient_channel] = SND_AllocChannel (snd);
if (!chan) if (!chan)
continue; continue;
} }
@ -450,7 +456,7 @@ s_updateAmbientSounds (const byte *ambient_sound_level)
} }
static void static void
s_spatialize (channel_t *ch) s_spatialize (snd_t *snd, channel_t *ch)
{ {
int phase; // in samples int phase; // in samples
vec_t dist, dot, lscale, rscale, scale; vec_t dist, dot, lscale, rscale, scale;
@ -477,14 +483,14 @@ s_spatialize (channel_t *ch)
if (snd_swapchannelside->int_val) if (snd_swapchannelside->int_val)
dot = -dot; dot = -dot;
if (snd_shm->channels == 1) { if (snd->channels == 1) {
rscale = 1.0; rscale = 1.0;
lscale = 1.0; lscale = 1.0;
phase = 0; phase = 0;
} else { } else {
rscale = 1.0 + dot * snd_volumesep->value; rscale = 1.0 + dot * snd_volumesep->value;
lscale = 1.0 - dot * snd_volumesep->value; lscale = 1.0 - dot * snd_volumesep->value;
phase = snd_phasesep->value * 0.001 * snd_shm->speed * dot; phase = snd_phasesep->value * 0.001 * snd->speed * dot;
} }
// add in distance effect // add in distance effect
@ -502,11 +508,11 @@ s_spatialize (channel_t *ch)
} }
static inline int static inline int
s_update_channel (channel_t *ch) s_update_channel (snd_t *snd, channel_t *ch)
{ {
if (!ch->sfx) if (!ch->sfx)
return 0; return 0;
s_spatialize (ch); // respatialize channel s_spatialize (snd, ch);
if (!ch->leftvol && !ch->rightvol) if (!ch->leftvol && !ch->rightvol)
return 0; return 0;
return 1; return 1;
@ -521,8 +527,9 @@ s_combine_channel (channel_t *combine, channel_t *ch)
} }
void void
SND_SetListener (const vec3_t origin, const vec3_t forward, const vec3_t right, SND_SetListener (snd_t *snd, const vec3_t origin, const vec3_t forward,
const vec3_t up, const byte *ambient_sound_level) const vec3_t right, const vec3_t up,
const byte *ambient_sound_level)
{ {
int i, j; int i, j;
channel_t *combine, *ch; channel_t *combine, *ch;
@ -533,19 +540,19 @@ SND_SetListener (const vec3_t origin, const vec3_t forward, const vec3_t right,
VectorCopy (up, listener_up); VectorCopy (up, listener_up);
// update general area ambient sound sources // update general area ambient sound sources
s_updateAmbientSounds (ambient_sound_level); s_updateAmbientSounds (snd, ambient_sound_level);
// update spatialization for dynamic sounds // update spatialization for dynamic sounds
for (ch = dynamic_channels; ch; ch = ch->next) for (ch = dynamic_channels; ch; ch = ch->next)
s_update_channel (ch); s_update_channel (snd, ch);
for (ch = looped_dynamic_channels; ch; ch = ch->next) for (ch = looped_dynamic_channels; ch; ch = ch->next)
s_update_channel (ch); s_update_channel (snd, ch);
// update spatialization for static sounds // update spatialization for static sounds
combine = 0; combine = 0;
for (i = 0; i < snd_num_statics; i++) { for (i = 0; i < snd_num_statics; i++) {
ch = static_channels[i]; ch = static_channels[i];
if (!s_update_channel (ch)) if (!s_update_channel (snd, ch))
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
@ -573,13 +580,13 @@ SND_SetListener (const vec3_t origin, const vec3_t forward, const vec3_t right,
} }
static int static int
snd_check_channels (channel_t *target_chan, const channel_t *check, snd_check_channels (snd_t *snd, channel_t *target_chan, const channel_t *check,
const sfx_t *osfx) const sfx_t *osfx)
{ {
if (!check || check == target_chan) if (!check || check == target_chan)
return 0; return 0;
if (check->sfx->owner == osfx->owner && !check->pos) { if (check->sfx->owner == osfx->owner && !check->pos) {
int skip = rand () % (int) (0.01 * snd_shm->speed); int skip = rand () % (int) (0.01 * snd->speed);
target_chan->pos = -skip; target_chan->pos = -skip;
return 1; return 1;
} }
@ -587,19 +594,19 @@ snd_check_channels (channel_t *target_chan, const channel_t *check,
} }
void void
SND_StartSound (int entnum, int entchannel, sfx_t *sfx, const vec3_t origin, SND_StartSound (snd_t *snd, int entnum, int entchannel, sfx_t *sfx,
float fvol, float attenuation) const vec3_t origin, float fvol, float attenuation)
{ {
int vol; int vol;
int looped; int looped;
channel_t *target_chan, *check; channel_t *target_chan, *check;
sfx_t *osfx; sfx_t *osfx;
if (!sfx || !snd_shm->speed) if (!sfx || !snd->speed)
return; return;
// pick a channel to play on // pick a channel to play on
looped = sfx->loopstart != (unsigned) -1; looped = sfx->loopstart != (unsigned) -1;
target_chan = s_pick_channel (entnum, entchannel, looped); target_chan = s_pick_channel (snd, entnum, entchannel, looped);
if (!target_chan) if (!target_chan)
return; return;
@ -611,11 +618,11 @@ SND_StartSound (int entnum, int entchannel, sfx_t *sfx, const vec3_t origin,
target_chan->master_vol = vol; target_chan->master_vol = vol;
target_chan->entnum = entnum; target_chan->entnum = entnum;
target_chan->entchannel = entchannel; target_chan->entchannel = entchannel;
s_spatialize (target_chan); s_spatialize (snd, target_chan);
// new channel // new channel
if (!(osfx = sfx->open (sfx))) { if (!(osfx = sfx->open (sfx))) {
SND_ChannelStop (unlink_channel (looped ? &looped_dynamic_channels SND_ChannelStop (snd, unlink_channel (looped ? &looped_dynamic_channels
: &dynamic_channels)); : &dynamic_channels));
return; return;
} }
@ -625,13 +632,13 @@ SND_StartSound (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
for (check = dynamic_channels; check; check = check->next) for (check = dynamic_channels; check; check = check->next)
if (snd_check_channels (target_chan, check, osfx)) if (snd_check_channels (snd, target_chan, check, osfx))
break; break;
for (check = looped_dynamic_channels; check; check = check->next) for (check = looped_dynamic_channels; check; check = check->next)
if (snd_check_channels (target_chan, check, osfx)) if (snd_check_channels (snd, target_chan, check, osfx))
break; break;
if (!osfx->retain (osfx)) { if (!osfx->retain (osfx)) {
SND_ChannelStop (unlink_channel (looped ? &looped_dynamic_channels SND_ChannelStop (snd, unlink_channel (looped ? &looped_dynamic_channels
: &dynamic_channels)); : &dynamic_channels));
return; // couldn't load the sound's data return; // couldn't load the sound's data
} }
@ -639,30 +646,30 @@ SND_StartSound (int entnum, int entchannel, sfx_t *sfx, const vec3_t origin,
} }
static int static int
s_check_stop (channel_t **_ch, int entnum, int entchannel) s_check_stop (snd_t *snd, channel_t **_ch, int entnum, int entchannel)
{ {
if ((*_ch)->entnum == entnum && (*_ch)->entchannel == entchannel) { if ((*_ch)->entnum == entnum && (*_ch)->entchannel == entchannel) {
SND_ChannelStop (unlink_channel (_ch)); SND_ChannelStop (snd, unlink_channel (_ch));
return 1; return 1;
} }
return 0; return 0;
} }
void void
SND_StopSound (int entnum, int entchannel) SND_StopSound (snd_t *snd, int entnum, int entchannel)
{ {
channel_t **_ch; channel_t **_ch;
for (_ch = &dynamic_channels; *_ch; ) for (_ch = &dynamic_channels; *_ch; )
if (!s_check_stop (_ch, entnum, entchannel)) if (!s_check_stop (snd, _ch, entnum, entchannel))
_ch = &(*_ch)->next; _ch = &(*_ch)->next;
for (_ch = &looped_dynamic_channels; *_ch; ) for (_ch = &looped_dynamic_channels; *_ch; )
if (!s_check_stop (_ch, entnum, entchannel)) if (!s_check_stop (snd, _ch, entnum, entchannel))
_ch = &(*_ch)->next; _ch = &(*_ch)->next;
} }
void void
SND_StaticSound (sfx_t *sfx, const vec3_t origin, float vol, SND_StaticSound (snd_t *snd, sfx_t *sfx, const vec3_t origin, float vol,
float attenuation) float attenuation)
{ {
channel_t *ss; channel_t *ss;
@ -676,7 +683,7 @@ SND_StaticSound (sfx_t *sfx, const vec3_t origin, float vol,
} }
if (!static_channels[snd_num_statics]) { if (!static_channels[snd_num_statics]) {
if (!(static_channels[snd_num_statics] = SND_AllocChannel ())) { if (!(static_channels[snd_num_statics] = SND_AllocChannel (snd))) {
Sys_Printf ("ran out of channels\n"); Sys_Printf ("ran out of channels\n");
return; return;
} }
@ -692,7 +699,7 @@ SND_StaticSound (sfx_t *sfx, const vec3_t origin, float vol,
ss->dist_mult = (attenuation / 64) / sound_nominal_clip_dist; ss->dist_mult = (attenuation / 64) / sound_nominal_clip_dist;
ss->end = 0; ss->end = 0;
s_spatialize (ss); s_spatialize (snd, ss);
ss->oldphase = ss->phase; ss->oldphase = ss->phase;
if (!osfx->retain (osfx)) if (!osfx->retain (osfx))
@ -702,17 +709,17 @@ SND_StaticSound (sfx_t *sfx, const vec3_t origin, float vol,
} }
void void
SND_LocalSound (const char *sound) SND_LocalSound (snd_t *snd, const char *sound)
{ {
sfx_t *sfx; sfx_t *sfx;
int viewent = 0; int viewent = 0;
sfx = SND_PrecacheSound (sound); sfx = SND_PrecacheSound (snd, sound);
if (!sfx) { if (!sfx) {
Sys_Printf ("S_LocalSound: can't cache %s\n", sound); Sys_Printf ("S_LocalSound: can't cache %s\n", sound);
return; return;
} }
if (snd_render_data.viewentity) if (snd_render_data.viewentity)
viewent = *snd_render_data.viewentity; viewent = *snd_render_data.viewentity;
SND_StartSound (viewent, -1, sfx, vec3_origin, 1, 1); SND_StartSound (snd, viewent, -1, sfx, vec3_origin, 1, 1);
} }

View file

@ -1,5 +1,5 @@
/* /*
snd_dma.c snd_default.c
main control for any streaming sound output device main control for any streaming sound output device
@ -69,23 +69,26 @@ static general_data_t plugin_info_general_data;
static snd_output_funcs_t *snd_output_funcs; static snd_output_funcs_t *snd_output_funcs;
static snd_t snd;
static int snd_shutdown = 0;
static void static void
s_xfer_paint_buffer (portable_samplepair_t *paintbuffer, int count, s_xfer_paint_buffer (snd_t *snd, portable_samplepair_t *paintbuffer, int count,
float volume) float volume)
{ {
int out_idx, out_max, step, val; int out_idx, out_max, step, val;
float *p; float *p;
p = (float *) paintbuffer; p = (float *) paintbuffer;
count *= snd_shm->channels; count *= snd->channels;
out_max = (snd_shm->frames * snd_shm->channels) - 1; out_max = (snd->frames * snd->channels) - 1;
out_idx = snd_paintedtime * snd_shm->channels; out_idx = snd_paintedtime * snd->channels;
while (out_idx > out_max) while (out_idx > out_max)
out_idx -= out_max + 1; out_idx -= out_max + 1;
step = 3 - snd_shm->channels; step = 3 - snd->channels;
if (snd_shm->samplebits == 16) { if (snd->samplebits == 16) {
short *out = (short *) snd_shm->buffer; short *out = (short *) snd->buffer;
while (count--) { while (count--) {
val = (*p * volume) * 0x8000; val = (*p * volume) * 0x8000;
@ -98,8 +101,8 @@ s_xfer_paint_buffer (portable_samplepair_t *paintbuffer, int count,
if (out_idx > out_max) if (out_idx > out_max)
out_idx = 0; out_idx = 0;
} }
} else if (snd_shm->samplebits == 8) { } else if (snd->samplebits == 8) {
unsigned char *out = (unsigned char *) snd_shm->buffer; unsigned char *out = (unsigned char *) snd->buffer;
while (count--) { while (count--) {
val = (*p * volume) * 128; val = (*p * volume) * 128;
@ -116,35 +119,35 @@ s_xfer_paint_buffer (portable_samplepair_t *paintbuffer, int count,
} }
static void static void
s_clear_buffer (void) s_clear_buffer (snd_t *snd)
{ {
int clear, i; int clear, i;
int count; int count;
if (!sound_started || !snd_shm || !snd_shm->buffer) if (!sound_started || !snd || !snd->buffer)
return; return;
if (snd_shm->samplebits == 8) if (snd->samplebits == 8)
clear = 0x80; clear = 0x80;
else else
clear = 0; clear = 0;
count = snd_shm->frames * snd_shm->channels * snd_shm->samplebits / 8; count = snd->frames * snd->channels * snd->samplebits / 8;
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
snd_shm->buffer[i] = clear; snd->buffer[i] = clear;
} }
static void static void
s_stop_all_sounds (void) s_stop_all_sounds (void)
{ {
SND_StopAllSounds (); SND_StopAllSounds (&snd);
SND_ScanChannels (0); SND_ScanChannels (&snd, 0);
s_clear_buffer (); s_clear_buffer (&snd);
} }
//============================================================================= //=============================================================================
static void /*static void
s_get_soundtime (void) s_get_soundtime (void)
{ {
int frames, framepos; int frames, framepos;
@ -196,7 +199,7 @@ s_update_ (void)
SND_PaintChannels (endtime); SND_PaintChannels (endtime);
snd_output_funcs->pS_O_Submit (); snd_output_funcs->pS_O_Submit ();
} }*/
/* /*
s_update s_update
@ -210,27 +213,27 @@ s_update (const vec3_t origin, const vec3_t forward, const vec3_t right,
if (!sound_started || (snd_blocked > 0)) if (!sound_started || (snd_blocked > 0))
return; return;
SND_SetListener (origin, forward, right, up, ambient_sound_level); SND_SetListener (&snd, origin, forward, right, up, ambient_sound_level);
// mix some sound // mix some sound
s_update_ (); //s_update_ ();
SND_ScanChannels (0); //SND_ScanChannels (0);
} }
static void //static void
s_extra_update (void) //s_extra_update (void)
{ //{
if (!sound_started || snd_noextraupdate->int_val) // if (!sound_started || snd_noextraupdate->int_val)
return; // don't pollute timings // return; // don't pollute timings
s_update_ (); // s_update_ ();
} //}
static void static void
s_block_sound (void) s_block_sound (void)
{ {
if (++snd_blocked == 1) { if (++snd_blocked == 1) {
snd_output_funcs->pS_O_BlockSound (); snd_output_funcs->block_sound (&snd);
s_clear_buffer (); s_clear_buffer (&snd);
} }
} }
@ -241,8 +244,8 @@ s_unblock_sound (void)
return; return;
if (!--snd_blocked) { if (!--snd_blocked) {
s_clear_buffer (); s_clear_buffer (&snd);
snd_output_funcs->pS_O_UnblockSound (); snd_output_funcs->unblock_sound (&snd);
} }
} }
@ -251,18 +254,20 @@ s_unblock_sound (void)
static void static void
s_soundinfo_f (void) s_soundinfo_f (void)
{ {
if (!sound_started || !snd_shm) { if (!sound_started) {
Sys_Printf ("sound system not started\n"); Sys_Printf ("sound system not started\n");
return; return;
} }
Sys_Printf ("%5d channels\n", snd_shm->channels); Sys_Printf ("%5d channels\n", snd.channels);
Sys_Printf ("%5d frames\n", snd_shm->frames); Sys_Printf ("%5d frames (%.1fms)\n", snd.frames,
Sys_Printf ("%5d framepos\n", snd_shm->framepos); 1000.0 * snd.frames / snd.speed);
Sys_Printf ("%5d samplebits\n", snd_shm->samplebits); Sys_Printf ("%5d framepos\n", snd.framepos);
Sys_Printf ("%5d submission_chunk\n", snd_shm->submission_chunk); Sys_Printf ("%5d samplebits\n", snd.samplebits);
Sys_Printf ("%5d speed\n", snd_shm->speed); Sys_Printf ("%5d submission_chunk (%.1fms)\n", snd.submission_chunk,
Sys_Printf ("0x%"PRIxPTR" dma buffer\n", (intptr_t) snd_shm->buffer); 1000.0 * snd.submission_chunk / snd.speed);
Sys_Printf ("%5d speed\n", snd.speed);
Sys_Printf ("0x%"PRIxPTR" dma buffer\n", (intptr_t) snd.buffer);
Sys_Printf ("%5d total_channels\n", snd_total_channels); Sys_Printf ("%5d total_channels\n", snd_total_channels);
} }
@ -278,15 +283,13 @@ s_startup (void)
if (!snd_initialized) if (!snd_initialized)
return; return;
snd_shm = snd_output_funcs->pS_O_Init (); if (!snd_output_funcs->init (&snd)) {
if (!snd_shm) {
Sys_Printf ("S_Startup: S_O_Init failed.\n"); Sys_Printf ("S_Startup: S_O_Init failed.\n");
sound_started = 0; sound_started = 0;
return; return;
} }
if (!snd_shm->xfer) if (!snd.xfer)
snd_shm->xfer = s_xfer_paint_buffer; snd.xfer = s_xfer_paint_buffer;
sound_started = 1; sound_started = 1;
} }
@ -337,8 +340,8 @@ s_init (void)
if (sound_started == 0) // sound startup failed? Bail out. if (sound_started == 0) // sound startup failed? Bail out.
return; return;
SND_SFX_Init (); SND_SFX_Init (&snd);
SND_Channels_Init (); SND_Channels_Init (&snd);
s_stop_all_sounds (); s_stop_all_sounds ();
} }
@ -350,10 +353,96 @@ s_shutdown (void)
return; return;
sound_started = 0; sound_started = 0;
snd_shutdown = 1;
snd_output_funcs->pS_O_Shutdown (); snd_output_funcs->shutdown (&snd);
}
snd_shm = 0; static void
s_ambient_off (void)
{
if (!sound_started)
return;
SND_AmbientOff (&snd);
}
static void
s_ambient_on (void)
{
if (!sound_started)
return;
SND_AmbientOn (&snd);
}
static void
s_static_sound (sfx_t *sfx, const vec3_t origin, float vol,
float attenuation)
{
if (!sound_started)
return;
SND_StaticSound (&snd, sfx, origin, vol, attenuation);
}
static void
s_start_sound (int entnum, int entchannel, sfx_t *sfx, const vec3_t origin,
float fvol, float attenuation)
{
if (!sound_started)
return;
if (!snd_shutdown)
SND_StartSound (&snd, entnum, entchannel, sfx, origin, fvol,
attenuation);
}
static void
s_stop_sound (int entnum, int entchannel)
{
if (!sound_started)
return;
SND_StopSound (&snd, entnum, entchannel);
}
static sfx_t *
s_precache_sound (const char *name)
{
if (!sound_started)
return 0;
return SND_PrecacheSound (&snd, name);
}
static sfx_t *
s_load_sound (const char *name)
{
if (!sound_started)
return 0;
return SND_LoadSound (&snd, name);
}
static void
s_channel_stop (channel_t *chan)
{
if (!sound_started)
return;
SND_ChannelStop (&snd, chan);
}
static void
s_local_sound (const char *sound)
{
if (!sound_started)
return;
if (!snd_shutdown)
SND_LocalSound (&snd, sound);
}
static channel_t *
s_alloc_channel (void)
{
if (!sound_started)
return 0;
if (!snd_shutdown)
return SND_AllocChannel (&snd);
return 0;
} }
static general_funcs_t plugin_info_general_funcs = { static general_funcs_t plugin_info_general_funcs = {
@ -362,21 +451,24 @@ static general_funcs_t plugin_info_general_funcs = {
}; };
static snd_render_funcs_t plugin_info_render_funcs = { static snd_render_funcs_t plugin_info_render_funcs = {
.ambient_off = SND_AmbientOff, .ambient_off = s_ambient_off,
.ambient_on = SND_AmbientOn, .ambient_on = s_ambient_on,
.static_sound = SND_StaticSound, .static_sound = s_static_sound,
.start_sound = SND_StartSound, .start_sound = s_start_sound,
.stop_sound = SND_StopSound, .local_sound = s_local_sound,
.precache_sound = SND_PrecacheSound, .stop_sound = s_stop_sound,
.update = s_update,
.alloc_channel = s_alloc_channel,
.channel_stop = s_channel_stop,
.precache_sound = s_precache_sound,
.load_sound = s_load_sound,
.update = s_update,
.stop_all_sounds = s_stop_all_sounds, .stop_all_sounds = s_stop_all_sounds,
.extra_update = s_extra_update, //.extra_update = s_extra_update,
.local_sound = SND_LocalSound, .block_sound = s_block_sound,
.block_sound = s_block_sound, .unblock_sound = s_unblock_sound,
.unblock_sound = s_unblock_sound,
.load_sound = SND_LoadSound,
.alloc_channel = SND_AllocChannel,
.channel_stop = SND_ChannelStop,
}; };
static plugin_funcs_t plugin_info_funcs = { static plugin_funcs_t plugin_info_funcs = {

View file

@ -54,7 +54,7 @@ static int snd_alive = 0;
static double snd_alive_time = 0; static double snd_alive_time = 0;
static jack_client_t *jack_handle; static jack_client_t *jack_handle;
static jack_port_t *jack_out[2]; static jack_port_t *jack_out[2];
static dma_t _snd_shm; static snd_t snd;
static float *output[2]; static float *output[2];
static cvar_t *snd_jack_server; static cvar_t *snd_jack_server;
@ -65,8 +65,8 @@ s_stop_all_sounds (void)
{ {
if (!sound_started) if (!sound_started)
return; return;
SND_StopAllSounds (); SND_StopAllSounds (&snd);
SND_ScanChannels (1); SND_ScanChannels (&snd, 1);
} }
static void static void
@ -76,7 +76,8 @@ s_start_sound (int entnum, int entchannel, sfx_t *sfx, const vec3_t origin,
if (!sound_started) if (!sound_started)
return; return;
if (!snd_shutdown) if (!snd_shutdown)
SND_StartSound (entnum, entchannel, sfx, origin, fvol, attenuation); SND_StartSound (&snd, entnum, entchannel, sfx, origin, fvol,
attenuation);
} }
static void static void
@ -120,7 +121,7 @@ s_update (const vec3_t origin, const vec3_t forward, const vec3_t right,
if (snd_shutdown) if (snd_shutdown)
return; return;
} }
SND_SetListener (origin, forward, right, up, ambient_sound_level); SND_SetListener (&snd, origin, forward, right, up, ambient_sound_level);
} }
static void static void
@ -129,7 +130,7 @@ s_local_sound (const char *sound)
if (!sound_started) if (!sound_started)
return; return;
if (!snd_shutdown) if (!snd_shutdown)
SND_LocalSound (sound); SND_LocalSound (&snd, sound);
} }
static void static void
@ -184,7 +185,7 @@ s_alloc_channel (void)
if (!sound_started) if (!sound_started)
return 0; return 0;
if (!snd_shutdown) if (!snd_shutdown)
return SND_AllocChannel (); return SND_AllocChannel (&snd);
return 0; return 0;
} }
@ -202,7 +203,7 @@ s_ambient_off (void)
{ {
if (!sound_started) if (!sound_started)
return; return;
SND_AmbientOff (); SND_AmbientOff (&snd);
} }
static void static void
@ -210,7 +211,7 @@ s_ambient_on (void)
{ {
if (!sound_started) if (!sound_started)
return; return;
SND_AmbientOn (); SND_AmbientOn (&snd);
} }
static void static void
@ -219,7 +220,7 @@ s_static_sound (sfx_t *sfx, const vec3_t origin, float vol,
{ {
if (!sound_started) if (!sound_started)
return; return;
SND_StaticSound (sfx, origin, vol, attenuation); SND_StaticSound (&snd, sfx, origin, vol, attenuation);
} }
static void static void
@ -227,7 +228,7 @@ s_stop_sound (int entnum, int entchannel)
{ {
if (!sound_started) if (!sound_started)
return; return;
SND_StopSound (entnum, entchannel); SND_StopSound (&snd, entnum, entchannel);
} }
static sfx_t * static sfx_t *
@ -235,7 +236,7 @@ s_precache_sound (const char *name)
{ {
if (!sound_started) if (!sound_started)
return 0; return 0;
return SND_PrecacheSound (name); return SND_PrecacheSound (&snd, name);
} }
static sfx_t * static sfx_t *
@ -243,7 +244,7 @@ s_load_sound (const char *name)
{ {
if (!sound_started) if (!sound_started)
return 0; return 0;
return SND_LoadSound (name); return SND_LoadSound (&snd, name);
} }
static void static void
@ -251,11 +252,12 @@ s_channel_stop (channel_t *chan)
{ {
if (!sound_started) if (!sound_started)
return; return;
SND_ChannelStop (chan); SND_ChannelStop (&snd, chan);
} }
static void static void
snd_jack_xfer (portable_samplepair_t *paintbuffer, int count, float volume) snd_jack_xfer (snd_t *snd, portable_samplepair_t *paintbuffer, int count,
float volume)
{ {
int i; int i;
@ -281,7 +283,7 @@ snd_jack_process (jack_nframes_t nframes, void *arg)
snd_alive = 1; snd_alive = 1;
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
output[i] = (float *) jack_port_get_buffer (jack_out[i], nframes); output[i] = (float *) jack_port_get_buffer (jack_out[i], nframes);
SND_PaintChannels (snd_paintedtime + nframes); SND_PaintChannels (&snd, snd_paintedtime + nframes);
return 0; return 0;
} }
@ -327,17 +329,16 @@ s_jack_connect (void)
jack_out[i] = jack_port_register (jack_handle, va (0, "out_%d", i + 1), jack_out[i] = jack_port_register (jack_handle, va (0, "out_%d", i + 1),
JACK_DEFAULT_AUDIO_TYPE, JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0); JackPortIsOutput, 0);
snd_shm->speed = jack_get_sample_rate (jack_handle); snd.speed = jack_get_sample_rate (jack_handle);
s_jack_activate (); s_jack_activate ();
sound_started = 1; sound_started = 1;
Sys_Printf ("Connected to JACK: %d Sps\n", snd_shm->speed); Sys_Printf ("Connected to JACK: %d Sps\n", snd.speed);
} }
static void static void
s_init (void) s_init (void)
{ {
snd_shm = &_snd_shm; snd.xfer = snd_jack_xfer;
snd_shm->xfer = snd_jack_xfer;
Cmd_AddCommand ("snd_force_unblock", s_snd_force_unblock, Cmd_AddCommand ("snd_force_unblock", s_snd_force_unblock,
"fix permanently blocked sound"); "fix permanently blocked sound");
@ -347,8 +348,8 @@ s_init (void)
snd_jack_server = Cvar_Get ("snd_jack_server", "default", CVAR_ROM, NULL, snd_jack_server = Cvar_Get ("snd_jack_server", "default", CVAR_ROM, NULL,
"The name of the JACK server to connect to"); "The name of the JACK server to connect to");
SND_SFX_Init (); SND_SFX_Init (&snd);
SND_Channels_Init (); SND_Channels_Init (&snd);
s_jack_connect (); s_jack_connect ();
} }

View file

@ -51,7 +51,6 @@
#define SAMPLE_GAP 4 #define SAMPLE_GAP 4
volatile dma_t *snd_shm;
snd_render_data_t snd_render_data = { snd_render_data_t snd_render_data = {
0, 0,
0, 0,
@ -212,7 +211,7 @@ SND_StreamSetPos (sfxbuffer_t *buffer, unsigned int pos)
sfxstream_t *stream = sfx->data.stream; sfxstream_t *stream = sfx->data.stream;
wavinfo_t *info = &stream->wavinfo; wavinfo_t *info = &stream->wavinfo;
stepscale = (float) info->rate / snd_shm->speed; stepscale = (float) info->rate / sfx->snd->speed;
buffer->head = buffer->tail = 0; buffer->head = buffer->tail = 0;
buffer->pos = pos; buffer->pos = pos;
@ -235,7 +234,7 @@ SND_StreamAdvance (sfxbuffer_t *buffer, unsigned int count)
if (!count) if (!count)
return 1; return 1;
stepscale = (float) info->rate / snd_shm->speed; stepscale = (float) info->rate / sfx->snd->speed;
// find out how many samples the buffer currently holds // find out how many samples the buffer currently holds
samples = buffer->head - buffer->tail; samples = buffer->head - buffer->tail;
@ -360,8 +359,9 @@ SND_GetCache (long frames, int rate, int channels,
float stepscale; float stepscale;
sfxbuffer_t *sc; sfxbuffer_t *sc;
sfx_t *sfx = block->sfx; sfx_t *sfx = block->sfx;
snd_t *snd = sfx->snd;
stepscale = (float) rate / snd_shm->speed; stepscale = (float) rate / snd->speed;
len = size = frames / stepscale; len = size = frames / stepscale;
size *= sizeof (float) * channels; size *= sizeof (float) * channels;
sc = allocator (&block->cache, sizeof (sfxbuffer_t) + size, sfx->name); sc = allocator (&block->cache, sizeof (sfxbuffer_t) + size, sfx->name);

View file

@ -104,7 +104,7 @@ snd_paint_channel (channel_t *ch, sfxbuffer_t *sc, int count)
} }
void void
SND_PaintChannels (unsigned endtime) SND_PaintChannels (snd_t *snd, unsigned endtime)
{ {
unsigned end, ltime; unsigned end, ltime;
int i, count; int i, count;
@ -171,8 +171,8 @@ SND_PaintChannels (unsigned endtime)
} }
// transfer out according to DMA format // transfer out according to DMA format
snd_shm->xfer (snd_paintbuffer, end - snd_paintedtime, snd->xfer (snd, snd_paintbuffer, end - snd_paintedtime,
snd_volume->value); snd_volume->value);
memmove (snd_paintbuffer, snd_paintbuffer + end - snd_paintedtime, memmove (snd_paintbuffer, snd_paintbuffer + end - snd_paintedtime,
max_overpaint * sizeof (snd_paintbuffer[0])); max_overpaint * sizeof (snd_paintbuffer[0]));

View file

@ -68,11 +68,12 @@ SND_Resample (sfxbuffer_t *sc, float *data, int length)
int outcount; int outcount;
double stepscale; double stepscale;
wavinfo_t *info = sc->sfx->wavinfo (sc->sfx); wavinfo_t *info = sc->sfx->wavinfo (sc->sfx);
snd_t *snd = sc->sfx->snd;
int inrate = info->rate; int inrate = info->rate;
int outwidth; int outwidth;
SRC_DATA src_data; SRC_DATA src_data;
stepscale = (double) snd_shm->speed / inrate; stepscale = (double) snd->speed / inrate;
outcount = length * stepscale; outcount = length * stepscale;
src_data.data_in = data; src_data.data_in = data;
@ -119,7 +120,7 @@ static int
snd_resample_read (sfxstream_t *stream, float *data, int frames) snd_resample_read (sfxstream_t *stream, float *data, int frames)
{ {
int inrate = stream->wavinfo.rate; int inrate = stream->wavinfo.rate;
double ratio = (double) snd_shm->speed / inrate; double ratio = (double) stream->sfx->snd->speed / inrate;
return src_callback_read (stream->state, ratio, frames, data); return src_callback_read (stream->state, ratio, frames, data);
} }
@ -143,9 +144,10 @@ SND_SetupResampler (sfxbuffer_t *sc, int streamed)
{ {
double stepscale; double stepscale;
wavinfo_t *info = sc->sfx->wavinfo (sc->sfx); wavinfo_t *info = sc->sfx->wavinfo (sc->sfx);
snd_t *snd = sc->sfx->snd;
int inrate = info->rate; int inrate = info->rate;
stepscale = (double) snd_shm->speed / inrate; stepscale = (double) snd->speed / inrate;
sc->sfx->length = info->frames * stepscale; sc->sfx->length = info->frames * stepscale;
if (info->loopstart != (unsigned int)-1) if (info->loopstart != (unsigned int)-1)
@ -159,7 +161,7 @@ SND_SetupResampler (sfxbuffer_t *sc, int streamed)
int err; int err;
sfxstream_t *stream = sc->sfx->data.stream; sfxstream_t *stream = sc->sfx->data.stream;
if (snd_shm->speed == inrate) { if (snd->speed == inrate) {
stream->state = calloc (sizeof (snd_null_state_t), 1); stream->state = calloc (sizeof (snd_null_state_t), 1);
stream->read = snd_read; stream->read = snd_read;
} else { } else {

View file

@ -112,6 +112,7 @@ SND_SFX_StreamOpen (sfx_t *sfx, void *file,
int (*seek)(sfxstream_t *, int), int (*seek)(sfxstream_t *, int),
void (*close) (sfx_t *)) void (*close) (sfx_t *))
{ {
snd_t *snd = sfx->snd;
sfxstream_t *stream = sfx->data.stream; sfxstream_t *stream = sfx->data.stream;
wavinfo_t *info = &stream->wavinfo; wavinfo_t *info = &stream->wavinfo;
int frames; int frames;
@ -119,11 +120,12 @@ SND_SFX_StreamOpen (sfx_t *sfx, void *file,
// if the speed is 0, there is no sound driver (probably failed to connect // if the speed is 0, there is no sound driver (probably failed to connect
// to jackd) // to jackd)
if (!snd_shm->speed) if (!snd->speed)
return 0; return 0;
sfx_t *new_sfx = calloc (1, sizeof (sfx_t)); sfx_t *new_sfx = calloc (1, sizeof (sfx_t));
new_sfx->snd = sfx->snd;
new_sfx->name = sfx->name; new_sfx->name = sfx->name;
new_sfx->owner = sfx; new_sfx->owner = sfx;
new_sfx->wavinfo = SND_CacheWavinfo; new_sfx->wavinfo = SND_CacheWavinfo;
@ -132,7 +134,7 @@ SND_SFX_StreamOpen (sfx_t *sfx, void *file,
new_sfx->getbuffer = SND_StreamGetBuffer; new_sfx->getbuffer = SND_StreamGetBuffer;
new_sfx->close = close; new_sfx->close = close;
frames = snd_shm->speed * 0.3; frames = snd->speed * 0.3;
frames = (frames + 255) & ~255; frames = (frames + 255) & ~255;
size = frames * info->channels * sizeof (float); size = frames * info->channels * sizeof (float);
@ -168,7 +170,7 @@ SND_SFX_StreamClose (sfx_t *sfx)
} }
sfx_t * sfx_t *
SND_LoadSound (const char *name) SND_LoadSound (snd_t *snd, const char *name)
{ {
sfx_t *sfx; sfx_t *sfx;
@ -181,6 +183,7 @@ SND_LoadSound (const char *name)
Sys_Error ("s_load_sound: out of sfx_t"); Sys_Error ("s_load_sound: out of sfx_t");
sfx = &snd_sfx[snd_num_sfx++]; sfx = &snd_sfx[snd_num_sfx++];
sfx->snd = snd;
sfx->name = strdup (name); sfx->name = strdup (name);
sfx->owner = sfx; sfx->owner = sfx;
if (SND_Load (sfx) == -1) { if (SND_Load (sfx) == -1) {
@ -192,14 +195,14 @@ SND_LoadSound (const char *name)
} }
sfx_t * sfx_t *
SND_PrecacheSound (const char *name) SND_PrecacheSound (snd_t *snd, const char *name)
{ {
sfx_t *sfx; sfx_t *sfx;
if (!name) if (!name)
Sys_Error ("SND_PrecacheSound: NULL"); Sys_Error ("SND_PrecacheSound: NULL");
sfx = SND_LoadSound (va (0, "sound/%s", name)); sfx = SND_LoadSound (snd, va (0, "sound/%s", name));
if (sfx && precache->int_val) { if (sfx && precache->int_val) {
if (sfx->retain (sfx)) if (sfx->retain (sfx))
sfx->release (sfx); sfx->release (sfx);
@ -243,7 +246,7 @@ s_soundlist_f (void)
} }
void void
SND_SFX_Init (void) SND_SFX_Init (snd_t *snd)
{ {
snd_sfx_hash = Hash_NewTable (511, snd_sfx_getkey, snd_sfx_free, 0, 0); snd_sfx_hash = Hash_NewTable (511, snd_sfx_getkey, snd_sfx_free, 0, 0);
precache = Cvar_Get ("precache", "1", CVAR_NONE, NULL, precache = Cvar_Get ("precache", "1", CVAR_NONE, NULL,

View file

@ -39,14 +39,20 @@
#include "snd_internal.h" #include "snd_internal.h"
typedef struct {
const snd_pcm_channel_area_t *areas;
snd_pcm_uframes_t offset;
snd_pcm_uframes_t nframes;
} alsa_pkt_t;
static int snd_inited; static int snd_inited;
static int snd_blocked = 0; static int snd_blocked = 0;
static volatile dma_t sn;
static snd_pcm_uframes_t buffer_size; static snd_pcm_uframes_t buffer_size;
static void *alsa_handle; static void *alsa_handle;
static const char *pcmname = NULL; static const char *pcmname = NULL;
static snd_pcm_t *pcm; static snd_pcm_t *pcm;
static snd_async_handler_t *async_haandler;
static plugin_t plugin_info; static plugin_t plugin_info;
static plugin_data_t plugin_info_data; static plugin_data_t plugin_info_data;
@ -101,7 +107,7 @@ SNDDMA_Init_Cvars (void)
"sound sample depth. 0 is system default"); "sound sample depth. 0 is system default");
} }
static int SNDDMA_GetDMAPos (void); static int SNDDMA_GetDMAPos (snd_t *snd);
static __attribute__((const)) snd_pcm_uframes_t static __attribute__((const)) snd_pcm_uframes_t
round_buffer_size (snd_pcm_uframes_t sz) round_buffer_size (snd_pcm_uframes_t sz)
@ -136,25 +142,26 @@ clamp_8 (int val)
} }
static void static void
SNDDMA_ni_xfer (portable_samplepair_t *paintbuffer, int count, float volume) alsa_ni_xfer (snd_t *snd, portable_samplepair_t *paintbuffer, int count,
float volume)
{ {
const snd_pcm_channel_area_t *areas; const snd_pcm_channel_area_t *areas;
int out_idx, out_max; int out_idx, out_max;
float *p; float *p;
areas = sn.xfer_data; areas = snd->xfer_data;
p = (float *) paintbuffer; p = (float *) paintbuffer;
out_max = sn.frames - 1; out_max = snd->frames - 1;
out_idx = *plugin_info_snd_output_data.paintedtime; out_idx = *plugin_info_snd_output_data.paintedtime;
while (out_idx > out_max) while (out_idx > out_max)
out_idx -= out_max + 1; out_idx -= out_max + 1;
if (sn.samplebits == 16) { if (snd->samplebits == 16) {
short *out_0 = (short *) areas[0].addr; short *out_0 = (short *) areas[0].addr;
short *out_1 = (short *) areas[1].addr; short *out_1 = (short *) areas[1].addr;
if (sn.channels == 2) { if (snd->channels == 2) {
while (count--) { while (count--) {
out_0[out_idx] = clamp_16 ((*p++ * volume) * 0x8000); out_0[out_idx] = clamp_16 ((*p++ * volume) * 0x8000);
out_1[out_idx] = clamp_16 ((*p++ * volume) * 0x8000); out_1[out_idx] = clamp_16 ((*p++ * volume) * 0x8000);
@ -169,11 +176,11 @@ SNDDMA_ni_xfer (portable_samplepair_t *paintbuffer, int count, float volume)
out_idx = 0; out_idx = 0;
} }
} }
} else if (sn.samplebits == 8) { } else if (snd->samplebits == 8) {
byte *out_0 = (byte *) areas[0].addr; byte *out_0 = (byte *) areas[0].addr;
byte *out_1 = (byte *) areas[1].addr; byte *out_1 = (byte *) areas[1].addr;
if (sn.channels == 2) { if (snd->channels == 2) {
while (count--) { while (count--) {
out_0[out_idx] = clamp_8 ((*p++ * volume) * 0x80); out_0[out_idx] = clamp_8 ((*p++ * volume) * 0x80);
out_1[out_idx] = clamp_8 ((*p++ * volume) * 0x80); out_1[out_idx] = clamp_8 ((*p++ * volume) * 0x80);
@ -191,8 +198,71 @@ SNDDMA_ni_xfer (portable_samplepair_t *paintbuffer, int count, float volume)
} }
} }
static volatile dma_t * static void
SNDDMA_Init (void) alsa_xfer (snd_t *snd, portable_samplepair_t *paintbuffer, int count,
float volume)
{
int out_idx, out_max, step, val;
float *p;
p = (float *) paintbuffer;
count *= snd->channels;
out_max = (snd->frames * snd->channels) - 1;
out_idx = snd_paintedtime * snd->channels;
while (out_idx > out_max)
out_idx -= out_max + 1;
step = 3 - snd->channels;
if (snd->samplebits == 16) {
short *out = (short *) snd->buffer;
while (count--) {
val = (*p * volume) * 0x8000;
p += step;
if (val > 0x7fff)
val = 0x7fff;
else if (val < -0x8000)
val = -0x8000;
out[out_idx++] = val;
if (out_idx > out_max)
out_idx = 0;
}
} else if (snd->samplebits == 8) {
unsigned char *out = (unsigned char *) snd->buffer;
while (count--) {
val = (*p * volume) * 128;
p += step;
if (val > 0x7f)
val = 0x7f;
else if (val < -0x80)
val = -0x80;
out[out_idx++] = val + 0x80;
if (out_idx > out_max)
out_idx = 0;
}
}
}
static void
alsa_callback (snd_async_handler_t *handler)
{
snd_pcm_t *pcm = qfsnd_async_handler_get_pcm (handler);
snd_t *snd = qfsnd_async_handler_get_callback_private (handler);
alsa_pkt_t packet;
qfsnd_pcm_avail_update (pcm);
qfsnd_pcm_mmap_begin (pcm, &packet.areas, &packet.offset, &packet.nframes);
snd->xfer_data = &packet;
SND_PaintChannels (snd, snd_paintedtime + packet.nframes);
qfsnd_pcm_mmap_commit (pcm, packet.offset, packet.nframes);
}
static int
SNDDMA_Init (snd_t *snd)
{ {
int err; int err;
int bps = -1, stereo = -1; int bps = -1, stereo = -1;
@ -238,6 +308,7 @@ retry_open:
goto error; goto error;
} }
snd->xfer = alsa_xfer;
err = qfsnd_pcm_hw_params_set_access (pcm, hw, err = qfsnd_pcm_hw_params_set_access (pcm, hw,
SND_PCM_ACCESS_MMAP_INTERLEAVED); SND_PCM_ACCESS_MMAP_INTERLEAVED);
if (0 > err) { if (0 > err) {
@ -257,7 +328,7 @@ retry_open:
Sys_Printf ("ALSA: could not set mmap access\n"); Sys_Printf ("ALSA: could not set mmap access\n");
goto error; goto error;
} }
sn.xfer = SNDDMA_ni_xfer; snd->xfer = alsa_ni_xfer;
} }
Sys_Printf ("Using PCM %s.\n", pcmname); Sys_Printf ("Using PCM %s.\n", pcmname);
@ -371,8 +442,6 @@ retry_open:
(int) period_size, qfsnd_strerror (err)); (int) period_size, qfsnd_strerror (err));
goto error; goto error;
} }
int dir;
qfsnd_pcm_hw_params_get_period_size (hw, &period_size, &dir);
err = qfsnd_pcm_hw_params (pcm, hw); err = qfsnd_pcm_hw_params (pcm, hw);
if (0 > err) { if (0 > err) {
Sys_Printf ("ALSA: unable to install hw params: %s\n", Sys_Printf ("ALSA: unable to install hw params: %s\n",
@ -404,21 +473,19 @@ retry_open:
goto error; goto error;
} }
memset ((dma_t *) &sn, 0, sizeof (sn)); snd->channels = stereo + 1;
sn.channels = stereo + 1;
// don't mix less than this in frames: // don't mix less than this in frames:
err = qfsnd_pcm_hw_params_get_period_size (hw, (snd_pcm_uframes_t *) err = qfsnd_pcm_hw_params_get_period_size (hw, &period_size, 0);
(char *)
&sn.submission_chunk, 0);
if (0 > err) { if (0 > err) {
Sys_Printf ("ALSA: unable to get period size. %s\n", Sys_Printf ("ALSA: unable to get period size. %s\n",
qfsnd_strerror (err)); qfsnd_strerror (err));
goto error; goto error;
} }
snd->submission_chunk = period_size;
sn.framepos = 0; snd->framepos = 0;
sn.samplebits = bps; snd->samplebits = bps;
err = qfsnd_pcm_hw_params_get_buffer_size (hw, &buffer_size); err = qfsnd_pcm_hw_params_get_buffer_size (hw, &buffer_size);
if (0 > err) { if (0 > err) {
@ -432,46 +499,58 @@ retry_open:
Sys_Printf ("to have a power of 2 buffer size\n"); Sys_Printf ("to have a power of 2 buffer size\n");
} }
sn.frames = buffer_size; qfsnd_async_add_pcm_handler (&async_haandler, pcm, alsa_callback, snd);
sn.speed = rate;
SNDDMA_GetDMAPos (); //XXX sets sn.buffer snd->frames = buffer_size;
Sys_Printf ("%5d channels %sinterleaved\n", sn.channels, snd->speed = rate;
sn.xfer ? "non-" : ""); SNDDMA_GetDMAPos (snd); //XXX sets snd->buffer
Sys_Printf ("%5d samples (%.1fms)\n", sn.frames, Sys_Printf ("%5d channels %sinterleaved\n", snd->channels,
1000.0 * sn.frames / sn.speed); snd->xfer ? "non-" : "");
Sys_Printf ("%5d samplepos\n", sn.framepos); Sys_Printf ("%5d samples (%.1fms)\n", snd->frames,
Sys_Printf ("%5d samplebits\n", sn.samplebits); 1000.0 * snd->frames / snd->speed);
Sys_Printf ("%5d submission_chunk (%.1fms)\n", sn.submission_chunk, Sys_Printf ("%5d samplepos\n", snd->framepos);
1000.0 * sn.submission_chunk / sn.speed); Sys_Printf ("%5d samplebits\n", snd->samplebits);
Sys_Printf ("%5d speed\n", sn.speed); Sys_Printf ("%5d submission_chunk (%.1fms)\n", snd->submission_chunk,
Sys_Printf ("0x%lx dma buffer\n", (long) sn.buffer); 1000.0 * snd->submission_chunk / snd->speed);
Sys_Printf ("%5d speed\n", snd->speed);
Sys_Printf ("0x%lx dma buffer\n", (long) snd->buffer);
snd_inited = 1; snd_inited = 1;
return &sn;
alsa_pkt_t packet;
qfsnd_pcm_mmap_begin (pcm, &packet.areas, &packet.offset, &packet.nframes);
snd->xfer_data = &packet;
SND_PaintChannels (snd, snd_paintedtime + packet.nframes);
qfsnd_pcm_mmap_commit (pcm, packet.offset, packet.nframes);
qfsnd_pcm_start (pcm);
return 1;
error: error:
qfsnd_pcm_close (pcm); qfsnd_pcm_close (pcm);
return 0; return 0;
} }
static int static int
SNDDMA_GetDMAPos (void) SNDDMA_GetDMAPos (snd_t *snd)
{ {
const snd_pcm_channel_area_t *areas; const snd_pcm_channel_area_t *areas;
snd_pcm_uframes_t offset; snd_pcm_uframes_t offset;
snd_pcm_uframes_t nframes = sn.frames; snd_pcm_uframes_t nframes = snd->frames;
qfsnd_pcm_avail_update (pcm); qfsnd_pcm_avail_update (pcm);
qfsnd_pcm_mmap_begin (pcm, &areas, &offset, &nframes); qfsnd_pcm_mmap_begin (pcm, &areas, &offset, &nframes);
sn.framepos = offset; snd->framepos = offset;
sn.buffer = areas->addr; snd->buffer = areas->addr;
sn.xfer_data = (void *) areas; snd->xfer_data = (void *) areas;
return sn.framepos; return snd->framepos;
} }
static void static void
SNDDMA_shutdown (void) SNDDMA_shutdown (snd_t *snd)
{ {
if (snd_inited) { if (snd_inited) {
qfsnd_async_del_handler (async_haandler);
async_haandler = 0;
qfsnd_pcm_close (pcm); qfsnd_pcm_close (pcm);
snd_inited = 0; snd_inited = 0;
} }
@ -483,7 +562,7 @@ SNDDMA_shutdown (void)
Send sound to device if buffer isn't really the dma buffer Send sound to device if buffer isn't really the dma buffer
*/ */
static void static void
SNDDMA_Submit (void) SNDDMA_Submit (snd_t *snd)
{ {
int state; int state;
int count = (*plugin_info_snd_output_data.paintedtime - int count = (*plugin_info_snd_output_data.paintedtime -
@ -516,14 +595,14 @@ SNDDMA_Submit (void)
} }
static void static void
SNDDMA_BlockSound (void) SNDDMA_BlockSound (snd_t *snd)
{ {
if (snd_inited && ++snd_blocked == 1) if (snd_inited && ++snd_blocked == 1)
qfsnd_pcm_pause (pcm, 1); qfsnd_pcm_pause (pcm, 1);
} }
static void static void
SNDDMA_UnblockSound (void) SNDDMA_UnblockSound (snd_t *snd)
{ {
if (!snd_inited || !snd_blocked) if (!snd_inited || !snd_blocked)
return; return;
@ -554,12 +633,12 @@ PLUGIN_INFO(snd_output, alsa)
plugin_info_general_funcs.init = SNDDMA_Init_Cvars; plugin_info_general_funcs.init = SNDDMA_Init_Cvars;
plugin_info_general_funcs.shutdown = NULL; plugin_info_general_funcs.shutdown = NULL;
plugin_info_snd_output_funcs.pS_O_Init = SNDDMA_Init; plugin_info_snd_output_funcs.init = SNDDMA_Init;
plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_snd_output_funcs.shutdown = SNDDMA_shutdown;
plugin_info_snd_output_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_snd_output_funcs.get_dma_pos = SNDDMA_GetDMAPos;
plugin_info_snd_output_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_snd_output_funcs.submit = SNDDMA_Submit;
plugin_info_snd_output_funcs.pS_O_BlockSound = SNDDMA_BlockSound; plugin_info_snd_output_funcs.block_sound = SNDDMA_BlockSound;
plugin_info_snd_output_funcs.pS_O_UnblockSound = SNDDMA_UnblockSound; plugin_info_snd_output_funcs.unblock_sound = SNDDMA_UnblockSound;
return &plugin_info; return &plugin_info;
} }

View file

@ -78,7 +78,6 @@ static int audio_fd;
static int snd_inited; static int snd_inited;
static int mmaped_io = 0; static int mmaped_io = 0;
static const char *snd_dev = "/dev/dsp"; static const char *snd_dev = "/dev/dsp";
static volatile dma_t sn;
static int tryrates[] = { 44100, 48000, 11025, 22050, 22051, 44100, 8000 }; static int tryrates[] = { 44100, 48000, 11025, 22050, 22051, 44100, 8000 };
@ -112,8 +111,8 @@ SNDDMA_Init_Cvars (void)
"mmaped io"); "mmaped io");
} }
static volatile dma_t * static int
try_open (int rw) try_open (snd_t *snd, int rw)
{ {
int caps, fmt, rc, tmp, i; int caps, fmt, rc, tmp, i;
int retries = 3; int retries = 3;
@ -169,21 +168,21 @@ try_open (int rw)
} }
// set sample bits & speed // set sample bits & speed
sn.samplebits = snd_bits->int_val; snd->samplebits = snd_bits->int_val;
if (sn.samplebits != 16 && sn.samplebits != 8) { if (snd->samplebits != 16 && snd->samplebits != 8) {
ioctl (audio_fd, SNDCTL_DSP_GETFMTS, &fmt); ioctl (audio_fd, SNDCTL_DSP_GETFMTS, &fmt);
if (fmt & AFMT_S16_LE) { // little-endian 16-bit signed if (fmt & AFMT_S16_LE) { // little-endian 16-bit signed
sn.samplebits = 16; snd->samplebits = 16;
} else { } else {
if (fmt & AFMT_U8) { // unsigned 8-bit ulaw if (fmt & AFMT_U8) { // unsigned 8-bit ulaw
sn.samplebits = 8; snd->samplebits = 8;
} }
} }
} }
if (sn.samplebits == 16) { if (snd->samplebits == 16) {
rc = AFMT_S16_LE; rc = AFMT_S16_LE;
rc = ioctl (audio_fd, SNDCTL_DSP_SETFMT, &rc); rc = ioctl (audio_fd, SNDCTL_DSP_SETFMT, &rc);
if (rc < 0) { if (rc < 0) {
@ -192,7 +191,7 @@ try_open (int rw)
close (audio_fd); close (audio_fd);
return 0; return 0;
} }
} else if (sn.samplebits == 8) { } else if (snd->samplebits == 8) {
rc = AFMT_U8; rc = AFMT_U8;
rc = ioctl (audio_fd, SNDCTL_DSP_SETFMT, &rc); rc = ioctl (audio_fd, SNDCTL_DSP_SETFMT, &rc);
if (rc < 0) { if (rc < 0) {
@ -202,39 +201,39 @@ try_open (int rw)
return 0; return 0;
} }
} else { } else {
Sys_Printf ("%d-bit sound not supported. %s", sn.samplebits, Sys_Printf ("%d-bit sound not supported. %s", snd->samplebits,
strerror (errno)); strerror (errno));
close (audio_fd); close (audio_fd);
return 0; return 0;
} }
tmp = sn.channels; tmp = snd->channels;
rc = ioctl (audio_fd, SNDCTL_DSP_CHANNELS, &tmp); rc = ioctl (audio_fd, SNDCTL_DSP_CHANNELS, &tmp);
if (rc < 0) { if (rc < 0) {
Sys_Printf ("Could not set %s to stereo=%d: %s\n", snd_dev, Sys_Printf ("Could not set %s to stereo=%d: %s\n", snd_dev,
sn.channels, strerror (errno)); snd->channels, strerror (errno));
close (audio_fd); close (audio_fd);
return 0; return 0;
} }
if (snd_rate->int_val) { if (snd_rate->int_val) {
sn.speed = snd_rate->int_val; snd->speed = snd_rate->int_val;
} else { } else {
for (i = 0; i < ((int) sizeof (tryrates) / 4); i++) for (i = 0; i < ((int) sizeof (tryrates) / 4); i++)
if (!ioctl (audio_fd, SNDCTL_DSP_SPEED, &tryrates[i])) if (!ioctl (audio_fd, SNDCTL_DSP_SPEED, &tryrates[i]))
break; break;
sn.speed = tryrates[i]; snd->speed = tryrates[i];
} }
if (!snd_stereo->int_val) { if (!snd_stereo->int_val) {
sn.channels = 1; snd->channels = 1;
} else { } else {
sn.channels = 2; snd->channels = 2;
} }
rc = ioctl (audio_fd, SNDCTL_DSP_SPEED, &sn.speed); rc = ioctl (audio_fd, SNDCTL_DSP_SPEED, &snd->speed);
if (rc < 0) { if (rc < 0) {
Sys_Printf ("Could not set %s speed to %d: %s\n", snd_dev, sn.speed, Sys_Printf ("Could not set %s speed to %d: %s\n", snd_dev, snd->speed,
strerror (errno)); strerror (errno));
close (audio_fd); close (audio_fd);
return 0; return 0;
@ -246,25 +245,25 @@ try_open (int rw)
return 0; return 0;
} }
sn.frames = info.fragstotal * info.fragsize; snd->frames = info.fragstotal * info.fragsize;
sn.frames /= sn.channels * sn.samplebits / 8; snd->frames /= snd->channels * snd->samplebits / 8;
sn.submission_chunk = 1; snd->submission_chunk = 1;
if (mmaped_io) { // memory map the dma buffer if (mmaped_io) { // memory map the dma buffer
unsigned long sz = sysconf (_SC_PAGESIZE); unsigned long sz = sysconf (_SC_PAGESIZE);
unsigned long len = info.fragstotal * info.fragsize; unsigned long len = info.fragstotal * info.fragsize;
len = (len + sz - 1) & ~(sz - 1); len = (len + sz - 1) & ~(sz - 1);
sn.buffer = (byte *) mmap (NULL, len, mmmode, mmflags, audio_fd, 0); snd->buffer = (byte *) mmap (NULL, len, mmmode, mmflags, audio_fd, 0);
if (sn.buffer == MAP_FAILED) { if (snd->buffer == MAP_FAILED) {
Sys_MaskPrintf (SYS_snd, "Could not mmap %s: %s\n", snd_dev, Sys_MaskPrintf (SYS_snd, "Could not mmap %s: %s\n", snd_dev,
strerror (errno)); strerror (errno));
close (audio_fd); close (audio_fd);
return 0; return 0;
} }
} else { } else {
sn.buffer = malloc (sn.frames * sn.channels * (sn.samplebits / 8)); snd->buffer = malloc (snd->frames * snd->channels * (snd->samplebits / 8));
if (!sn.buffer) { if (!snd->buffer) {
Sys_Printf ("SNDDMA_Init: memory allocation failure\n"); Sys_Printf ("SNDDMA_Init: memory allocation failure\n");
close (audio_fd); close (audio_fd);
return 0; return 0;
@ -277,7 +276,7 @@ try_open (int rw)
if (rc < 0) { if (rc < 0) {
Sys_Printf ("Could not toggle.: %s\n", strerror (errno)); Sys_Printf ("Could not toggle.: %s\n", strerror (errno));
if (mmaped_io) if (mmaped_io)
munmap (sn.buffer, sn.frames * sn.channels * sn.samplebits / 8); munmap (snd->buffer, snd->frames * snd->channels * snd->samplebits / 8);
close (audio_fd); close (audio_fd);
return 0; return 0;
} }
@ -286,28 +285,25 @@ try_open (int rw)
if (rc < 0) { if (rc < 0) {
Sys_Printf ("Could not toggle.: %s\n", strerror (errno)); Sys_Printf ("Could not toggle.: %s\n", strerror (errno));
if (mmaped_io) if (mmaped_io)
munmap (sn.buffer, sn.frames * sn.channels * sn.samplebits / 8); munmap (snd->buffer, snd->frames * snd->channels * snd->samplebits / 8);
close (audio_fd); close (audio_fd);
return 0; return 0;
} }
sn.framepos = 0; snd->framepos = 0;
snd_inited = 1; snd_inited = 1;
return &sn; return 1;
}
static volatile dma_t *
SNDDMA_Init (void)
{
volatile dma_t *shm;
if ((shm = try_open (0)))
return shm;
return try_open (1);
} }
static int static int
SNDDMA_GetDMAPos (void) SNDDMA_Init (snd_t *snd)
{
return try_open (snd, 0) || try_open (snd, 1);
}
static int
SNDDMA_GetDMAPos (snd_t *snd)
{ {
struct count_info count; struct count_info count;
@ -317,34 +313,32 @@ SNDDMA_GetDMAPos (void)
if (ioctl (audio_fd, SNDCTL_DSP_GETOPTR, &count) == -1) { if (ioctl (audio_fd, SNDCTL_DSP_GETOPTR, &count) == -1) {
Sys_Printf ("Uh, %s dead: %s\n", snd_dev, strerror (errno)); Sys_Printf ("Uh, %s dead: %s\n", snd_dev, strerror (errno));
if (mmaped_io) if (mmaped_io)
munmap (sn.buffer, sn.frames * sn.channels * sn.samplebits / 8); munmap (snd->buffer, snd->frames * snd->channels * snd->samplebits / 8);
close (audio_fd); close (audio_fd);
snd_inited = 0; snd_inited = 0;
return 0; return 0;
} }
// sn.samplepos = (count.bytes / (sn.samplebits / 8)) & (sn.samples-1); snd->framepos = count.ptr / (snd->channels * snd->samplebits / 8);
// fprintf(stderr, "%d \r", count.ptr);
sn.framepos = count.ptr / (sn.channels * sn.samplebits / 8);
return sn.framepos; return snd->framepos;
} }
static void static void
SNDDMA_shutdown (void) SNDDMA_shutdown (snd_t *snd)
{ {
if (snd_inited) { if (snd_inited) {
if (mmaped_io) if (mmaped_io)
munmap (sn.buffer, sn.frames * sn.channels * sn.samplebits / 8); munmap (snd->buffer, snd->frames * snd->channels * snd->samplebits / 8);
close (audio_fd); close (audio_fd);
snd_inited = 0; snd_inited = 0;
} }
} }
static int static int
sample_bytes (int frames) sample_bytes (snd_t *snd, int frames)
{ {
return frames * sn.channels * sn.samplebits / 8; return frames * snd->channels * snd->samplebits / 8;
} }
/* /*
@ -353,7 +347,7 @@ sample_bytes (int frames)
Send sound to device if buffer isn't really the dma buffer Send sound to device if buffer isn't really the dma buffer
*/ */
static void static void
SNDDMA_Submit (void) SNDDMA_Submit (snd_t *snd)
{ {
int frames; int frames;
int len; int len;
@ -362,17 +356,17 @@ SNDDMA_Submit (void)
if (snd_inited && !mmaped_io) { if (snd_inited && !mmaped_io) {
frames = *plugin_info_snd_output_data.paintedtime frames = *plugin_info_snd_output_data.paintedtime
- *plugin_info_snd_output_data.soundtime; - *plugin_info_snd_output_data.soundtime;
offset = frames * sn.channels * sn.samplebits / 8; offset = frames * snd->channels * snd->samplebits / 8;
if (sn.framepos + frames <= sn.frames) { if (snd->framepos + frames <= snd->frames) {
len = sample_bytes (frames); len = sample_bytes (snd, frames);
if (write (audio_fd, sn.buffer + offset, len) != len) if (write (audio_fd, snd->buffer + offset, len) != len)
Sys_Printf ("SNDDMA_Submit(): %s\n", strerror (errno)); Sys_Printf ("SNDDMA_Submit(): %s\n", strerror (errno));
} else { } else {
int len = sample_bytes (sn.frames - sn.framepos); int len = sample_bytes (snd, snd->frames - snd->framepos);
if (write (audio_fd, sn.buffer + offset, len) != len) if (write (audio_fd, snd->buffer + offset, len) != len)
Sys_Printf ("SNDDMA_Submit(): %s\n", strerror (errno)); Sys_Printf ("SNDDMA_Submit(): %s\n", strerror (errno));
if (write (audio_fd, sn.buffer, offset - len) != offset - len) if (write (audio_fd, snd->buffer, offset - len) != offset - len)
Sys_Printf ("SNDDMA_Submit(): %s\n", strerror (errno)); Sys_Printf ("SNDDMA_Submit(): %s\n", strerror (errno));
} }
*plugin_info_snd_output_data.soundtime += frames; *plugin_info_snd_output_data.soundtime += frames;
@ -380,12 +374,12 @@ SNDDMA_Submit (void)
} }
static void static void
SNDDMA_BlockSound (void) SNDDMA_BlockSound (snd_t *snd)
{ {
} }
static void static void
SNDDMA_UnblockSound (void) SNDDMA_UnblockSound (snd_t *snd)
{ {
} }
@ -412,12 +406,12 @@ PLUGIN_INFO(snd_output, oss)
plugin_info_general_funcs.init = SNDDMA_Init_Cvars; plugin_info_general_funcs.init = SNDDMA_Init_Cvars;
plugin_info_general_funcs.shutdown = NULL; plugin_info_general_funcs.shutdown = NULL;
plugin_info_snd_output_funcs.pS_O_Init = SNDDMA_Init; plugin_info_snd_output_funcs.init = SNDDMA_Init;
plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_snd_output_funcs.shutdown = SNDDMA_shutdown;
plugin_info_snd_output_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_snd_output_funcs.get_dma_pos = SNDDMA_GetDMAPos;
plugin_info_snd_output_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_snd_output_funcs.submit = SNDDMA_Submit;
plugin_info_snd_output_funcs.pS_O_BlockSound = SNDDMA_BlockSound; plugin_info_snd_output_funcs.block_sound = SNDDMA_BlockSound;
plugin_info_snd_output_funcs.pS_O_UnblockSound = SNDDMA_UnblockSound; plugin_info_snd_output_funcs.unblock_sound = SNDDMA_UnblockSound;
return &plugin_info; return &plugin_info;
} }