[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/qtypes.h>
/*
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);
struct snd_s;
typedef struct snd_output_funcs_s {
P_S_O_Init pS_O_Init;
P_S_O_Shutdown pS_O_Shutdown;
P_S_O_GetDMAPos pS_O_GetDMAPos;
P_S_O_Submit pS_O_Submit;
P_S_O_BlockSound pS_O_BlockSound;
P_S_O_UnblockSound pS_O_UnblockSound;
int (*init) (struct snd_s *snd);
void (*shutdown) (struct snd_s *snd);
int (*get_dma_pos) (struct snd_s *snd);
void (*submit) (struct snd_s *snd);
void (*block_sound) (struct snd_s *snd);
void (*unblock_sound) (struct snd_s *snd);
} snd_output_funcs_t;
typedef struct snd_output_data_s {

View file

@ -41,6 +41,7 @@
typedef struct sfx_s sfx_t;
struct sfx_s
{
struct snd_s *snd; //!< ownding snd_t instance
const char *name;
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 (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
#undef QF_ALSA_NEED
#undef UNDEF_QF_ALSA_NEED

View file

@ -45,7 +45,7 @@
#include "QF/zone.h"
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 channel_s channel_t;
typedef struct sfxbuffer_s sfxbuffer_t;
@ -70,7 +70,7 @@ struct portable_samplepair_s {
/** communication structure between output drivers and renderer
*/
struct dma_s {
struct snd_s {
int speed; //!< sample rate
int samplebits; //!< bits per sample
int channels; //!< number of output channels
@ -84,7 +84,8 @@ struct dma_s {
\param count The number of sample to transfer.
\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);
/** 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_stereo_phase_separation;
extern volatile dma_t *snd_shm;
extern snd_render_data_t snd_render_data;
#define PAINTBUFFER_SIZE 512
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.
\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.
\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
*/
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.
*/
struct channel_s *SND_AllocChannel (void);
struct channel_s *SND_AllocChannel (snd_t *snd);
/** Stop a channel from playing.
\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.
\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
non-threaded.
*/
void SND_ScanChannels (int wait);
void SND_ScanChannels (snd_t *snd, int wait);
/** Disable ambient sounds.
\todo not used, remove?
*/
void SND_AmbientOff (void);
void SND_AmbientOff (snd_t *snd);
/** Enable ambient sounds.
\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
render some sound.
@ -345,17 +344,17 @@ void SND_AmbientOn (void);
\param ambient_sound_level Pointer to 4 bytes indicating the levels at
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 byte *ambient_sound_level);
/** Stop all sounds from playing.
*/
void SND_StopAllSounds(void);
void SND_StopAllSounds (snd_t *snd);
/** Initialize the channels sub-subsystem
*/
void SND_Channels_Init (void);
void SND_Channels_Init (snd_t *snd);
/** Start a sound playing.
\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 attenuation rate of volume dropoff vs distance
*/
void SND_StartSound (int entnum, int entchannel, sfx_t *sfx, const vec3_t origin,
float fvol, float attenuation);
void SND_StartSound (snd_t *snd, int entnum, int entchannel, sfx_t *sfx,
const vec3_t origin, float fvol, float attenuation);
/** Create a sound generated by the world.
\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 attenuation rate of volume dropoff vs distance
*/
void SND_StaticSound (sfx_t *sfx, const vec3_t origin, float vol,
float attenuation);
void SND_StaticSound (snd_t *snd, sfx_t *sfx, const vec3_t origin, float vol,
float attenuation);
/** Stop an entity's sound.
\param entnum index of entity the sound is associated with.
\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.
\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.
\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.
*/
void SND_InitScaletable (void);
void SND_InitScaletable (snd_t *snd);
/** Set the paint function of the sfxbuffer
\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 width bytes per channel
*/
void SND_Convert (byte *idata, float *fdata, int frames, int channels,
int width);
void SND_Convert (byte *idata, float *fdata, int frames,
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
\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.

View file

@ -85,7 +85,7 @@ unlink_channel (channel_t **_ch)
}
channel_t *
SND_AllocChannel (void)
SND_AllocChannel (snd_t *snd)
{
channel_t **free = &free_channels;
channel_t *chan;
@ -124,7 +124,7 @@ SND_AllocChannel (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.
a rather serious bug as it will create a loop in the free list
@ -137,13 +137,13 @@ SND_ChannelStop (channel_t *chan)
}
void
SND_ScanChannels (int wait)
SND_ScanChannels (snd_t *snd, int wait)
{
int i;
channel_t *ch;
int count = 0;
if (!snd_shm || !snd_shm->speed)
if (!snd || !snd->speed)
return;
if (wait) {
@ -184,23 +184,23 @@ SND_ScanChannels (int wait)
}
void
SND_StopAllSounds (void)
SND_StopAllSounds (snd_t *snd)
{
int i;
snd_num_statics = 0;
while (dynamic_channels)
SND_ChannelStop (unlink_channel (&dynamic_channels));
SND_ChannelStop (snd, unlink_channel (&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++) {
if (ambient_channels[i])
SND_ChannelStop (ambient_channels[i]);
SND_ChannelStop (snd, ambient_channels[i]);
ambient_channels[i] = 0;
}
for (i = 0; i < MAX_STATIC_CHANNELS; i++) {
if (static_channels[i])
SND_ChannelStop (static_channels[i]);
SND_ChannelStop (snd, static_channels[i]);
static_channels[i] = 0;
}
if (0) {
@ -217,8 +217,9 @@ SND_StopAllSounds (void)
}
static void
s_play_f (void)
s_play_f (void *_snd)
{
snd_t *snd = _snd;
dstring_t *name = dstring_new ();
int i;
static int hash = 345;
@ -231,16 +232,17 @@ s_play_f (void)
} else {
dsprintf (name, "%s", Cmd_Argv (i));
}
sfx = SND_PrecacheSound (name->str);
SND_StartSound (hash++, 0, sfx, listener_origin, 1.0, 1.0);
sfx = SND_PrecacheSound (snd, name->str);
SND_StartSound (snd, hash++, 0, sfx, listener_origin, 1.0, 1.0);
i++;
}
dstring_delete (name);
}
static void
s_playcenter_f (void)
s_playcenter_f (void *_snd)
{
snd_t *snd = _snd;
dstring_t *name = dstring_new ();
int i;
sfx_t *sfx;
@ -255,15 +257,16 @@ s_playcenter_f (void)
} else {
dsprintf (name, "%s", Cmd_Argv (i));
}
sfx = SND_PrecacheSound (name->str);
SND_StartSound (viewent, 0, sfx, listener_origin, 1.0, 1.0);
sfx = SND_PrecacheSound (snd, name->str);
SND_StartSound (snd, viewent, 0, sfx, listener_origin, 1.0, 1.0);
}
dstring_delete (name);
}
static void
s_playvol_f (void)
s_playvol_f (void *_snd)
{
snd_t *snd = _snd;
dstring_t *name = dstring_new ();
float vol;
int i;
@ -277,9 +280,9 @@ s_playvol_f (void)
} else {
dsprintf (name, "%s", Cmd_Argv (i));
}
sfx = SND_PrecacheSound (name->str);
sfx = SND_PrecacheSound (snd, name->str);
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;
}
dstring_delete (name);
@ -291,14 +294,15 @@ s_channels_gamedir (int phase)
//FIXME for some reason, a gamedir change causes semi-random
//"already released" cache errors. fortunatly, servers don't change
//gamedir often, so I'll put this in the too-hard basket for now.
if (phase) {
ambient_sfx[AMBIENT_WATER] = SND_PrecacheSound ("ambience/water1.wav");
ambient_sfx[AMBIENT_SKY] = SND_PrecacheSound ("ambience/wind2.wav");
}
//XXX FIXME set ambient sounds
//if (phase) {
// ambient_sfx[AMBIENT_WATER] = SND_PrecacheSound (snd, "ambience/water1.wav");
// ambient_sfx[AMBIENT_SKY] = SND_PrecacheSound (snd, "ambience/wind2.wav");
//}
}
void
SND_Channels_Init (void)
SND_Channels_Init (snd_t *snd)
{
int i;
@ -315,12 +319,14 @@ SND_Channels_Init (void)
ambient_level = Cvar_Get ("ambient_level", "0.3", CVAR_NONE, NULL,
"Ambient sounds' volume");
Cmd_AddCommand ("play", s_play_f,
"Play selected sound effect (play pathto/sound.wav)");
Cmd_AddCommand ("playcenter", s_playcenter_f,
"Play selected sound effect without 3D spatialization.");
Cmd_AddCommand ("playvol", s_playvol_f, "Play selected sound effect at "
"selected volume (playvol pathto/sound.wav num");
Cmd_AddDataCommand ("play", s_play_f, snd,
"Play selected sound effect (play pathto/sound.wav)");
Cmd_AddDataCommand ("playcenter", s_playcenter_f, snd,
"Play selected sound effect without 3D "
"spatialization.");
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++)
snd_channels[i].next = &snd_channels[i + 1];
@ -333,14 +339,14 @@ SND_Channels_Init (void)
}
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;
// check for finished non-looped sounds
for (_ch = &dynamic_channels; *_ch; ) {
if (!(*_ch)->sfx || (*_ch)->done) {
SND_ChannelStop (unlink_channel (_ch));
SND_ChannelStop (snd, unlink_channel (_ch));
continue;
}
_ch = &(*_ch)->next;
@ -352,13 +358,13 @@ s_pick_channel (int entnum, int entchannel, int looped)
if (!(*_ch)->sfx || (*_ch)->done
|| ((*_ch)->entnum == entnum
&& ((*_ch)->entchannel == entchannel || entchannel == -1))) {
SND_ChannelStop (unlink_channel (_ch));
SND_ChannelStop (snd, unlink_channel (_ch));
continue;
}
_ch = &(*_ch)->next;
}
_ch = looped ? &looped_dynamic_channels : &dynamic_channels;
if ((ch = SND_AllocChannel ())) {
if ((ch = SND_AllocChannel (snd))) {
ch->next = *_ch;
*_ch = ch;
}
@ -366,19 +372,19 @@ s_pick_channel (int entnum, int entchannel, int looped)
}
void
SND_AmbientOff (void)
SND_AmbientOff (snd_t *snd)
{
snd_ambient = false;
}
void
SND_AmbientOn (void)
SND_AmbientOn (snd_t *snd)
{
snd_ambient = true;
}
static void
s_updateAmbientSounds (const byte *ambient_sound_level)
s_updateAmbientSounds (snd_t *snd, const byte *ambient_sound_level)
{
float vol;
int ambient_channel;
@ -410,7 +416,7 @@ s_updateAmbientSounds (const byte *ambient_sound_level)
chan = ambient_channels[ambient_channel];
if (!chan) {
chan = ambient_channels[ambient_channel] = SND_AllocChannel ();
chan = ambient_channels[ambient_channel] = SND_AllocChannel (snd);
if (!chan)
continue;
}
@ -450,7 +456,7 @@ s_updateAmbientSounds (const byte *ambient_sound_level)
}
static void
s_spatialize (channel_t *ch)
s_spatialize (snd_t *snd, channel_t *ch)
{
int phase; // in samples
vec_t dist, dot, lscale, rscale, scale;
@ -477,14 +483,14 @@ s_spatialize (channel_t *ch)
if (snd_swapchannelside->int_val)
dot = -dot;
if (snd_shm->channels == 1) {
if (snd->channels == 1) {
rscale = 1.0;
lscale = 1.0;
phase = 0;
} else {
rscale = 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
@ -502,11 +508,11 @@ s_spatialize (channel_t *ch)
}
static inline int
s_update_channel (channel_t *ch)
s_update_channel (snd_t *snd, channel_t *ch)
{
if (!ch->sfx)
return 0;
s_spatialize (ch); // respatialize channel
s_spatialize (snd, ch);
if (!ch->leftvol && !ch->rightvol)
return 0;
return 1;
@ -521,8 +527,9 @@ s_combine_channel (channel_t *combine, channel_t *ch)
}
void
SND_SetListener (const vec3_t origin, const vec3_t forward, const vec3_t right,
const vec3_t up, const byte *ambient_sound_level)
SND_SetListener (snd_t *snd, const vec3_t origin, const vec3_t forward,
const vec3_t right, const vec3_t up,
const byte *ambient_sound_level)
{
int i, j;
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);
// update general area ambient sound sources
s_updateAmbientSounds (ambient_sound_level);
s_updateAmbientSounds (snd, ambient_sound_level);
// update spatialization for dynamic sounds
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)
s_update_channel (ch);
s_update_channel (snd, ch);
// update spatialization for static sounds
combine = 0;
for (i = 0; i < snd_num_statics; i++) {
ch = static_channels[i];
if (!s_update_channel (ch))
if (!s_update_channel (snd, ch))
continue;
// 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
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)
{
if (!check || check == target_chan)
return 0;
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;
return 1;
}
@ -587,19 +594,19 @@ snd_check_channels (channel_t *target_chan, const channel_t *check,
}
void
SND_StartSound (int entnum, int entchannel, sfx_t *sfx, const vec3_t origin,
float fvol, float attenuation)
SND_StartSound (snd_t *snd, int entnum, int entchannel, sfx_t *sfx,
const vec3_t origin, float fvol, float attenuation)
{
int vol;
int looped;
channel_t *target_chan, *check;
sfx_t *osfx;
if (!sfx || !snd_shm->speed)
if (!sfx || !snd->speed)
return;
// pick a channel to play on
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)
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->entnum = entnum;
target_chan->entchannel = entchannel;
s_spatialize (target_chan);
s_spatialize (snd, target_chan);
// new channel
if (!(osfx = sfx->open (sfx))) {
SND_ChannelStop (unlink_channel (looped ? &looped_dynamic_channels
SND_ChannelStop (snd, unlink_channel (looped ? &looped_dynamic_channels
: &dynamic_channels));
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
// a bit to keep it from just making the first one louder
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;
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;
if (!osfx->retain (osfx)) {
SND_ChannelStop (unlink_channel (looped ? &looped_dynamic_channels
SND_ChannelStop (snd, unlink_channel (looped ? &looped_dynamic_channels
: &dynamic_channels));
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
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) {
SND_ChannelStop (unlink_channel (_ch));
SND_ChannelStop (snd, unlink_channel (_ch));
return 1;
}
return 0;
}
void
SND_StopSound (int entnum, int entchannel)
SND_StopSound (snd_t *snd, int entnum, int entchannel)
{
channel_t **_ch;
for (_ch = &dynamic_channels; *_ch; )
if (!s_check_stop (_ch, entnum, entchannel))
if (!s_check_stop (snd, _ch, entnum, entchannel))
_ch = &(*_ch)->next;
for (_ch = &looped_dynamic_channels; *_ch; )
if (!s_check_stop (_ch, entnum, entchannel))
if (!s_check_stop (snd, _ch, entnum, entchannel))
_ch = &(*_ch)->next;
}
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)
{
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] = SND_AllocChannel ())) {
if (!(static_channels[snd_num_statics] = SND_AllocChannel (snd))) {
Sys_Printf ("ran out of channels\n");
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->end = 0;
s_spatialize (ss);
s_spatialize (snd, ss);
ss->oldphase = ss->phase;
if (!osfx->retain (osfx))
@ -702,17 +709,17 @@ SND_StaticSound (sfx_t *sfx, const vec3_t origin, float vol,
}
void
SND_LocalSound (const char *sound)
SND_LocalSound (snd_t *snd, const char *sound)
{
sfx_t *sfx;
int viewent = 0;
sfx = SND_PrecacheSound (sound);
sfx = SND_PrecacheSound (snd, sound);
if (!sfx) {
Sys_Printf ("S_LocalSound: can't cache %s\n", sound);
return;
}
if (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
@ -69,23 +69,26 @@ static general_data_t plugin_info_general_data;
static snd_output_funcs_t *snd_output_funcs;
static snd_t snd;
static int snd_shutdown = 0;
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)
{
int out_idx, out_max, step, val;
float *p;
p = (float *) paintbuffer;
count *= snd_shm->channels;
out_max = (snd_shm->frames * snd_shm->channels) - 1;
out_idx = snd_paintedtime * snd_shm->channels;
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_shm->channels;
step = 3 - snd->channels;
if (snd_shm->samplebits == 16) {
short *out = (short *) snd_shm->buffer;
if (snd->samplebits == 16) {
short *out = (short *) snd->buffer;
while (count--) {
val = (*p * volume) * 0x8000;
@ -98,8 +101,8 @@ s_xfer_paint_buffer (portable_samplepair_t *paintbuffer, int count,
if (out_idx > out_max)
out_idx = 0;
}
} else if (snd_shm->samplebits == 8) {
unsigned char *out = (unsigned char *) snd_shm->buffer;
} else if (snd->samplebits == 8) {
unsigned char *out = (unsigned char *) snd->buffer;
while (count--) {
val = (*p * volume) * 128;
@ -116,35 +119,35 @@ s_xfer_paint_buffer (portable_samplepair_t *paintbuffer, int count,
}
static void
s_clear_buffer (void)
s_clear_buffer (snd_t *snd)
{
int clear, i;
int count;
if (!sound_started || !snd_shm || !snd_shm->buffer)
if (!sound_started || !snd || !snd->buffer)
return;
if (snd_shm->samplebits == 8)
if (snd->samplebits == 8)
clear = 0x80;
else
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++)
snd_shm->buffer[i] = clear;
snd->buffer[i] = clear;
}
static void
s_stop_all_sounds (void)
{
SND_StopAllSounds ();
SND_ScanChannels (0);
s_clear_buffer ();
SND_StopAllSounds (&snd);
SND_ScanChannels (&snd, 0);
s_clear_buffer (&snd);
}
//=============================================================================
static void
/*static void
s_get_soundtime (void)
{
int frames, framepos;
@ -196,7 +199,7 @@ s_update_ (void)
SND_PaintChannels (endtime);
snd_output_funcs->pS_O_Submit ();
}
}*/
/*
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))
return;
SND_SetListener (origin, forward, right, up, ambient_sound_level);
SND_SetListener (&snd, origin, forward, right, up, ambient_sound_level);
// mix some sound
s_update_ ();
SND_ScanChannels (0);
//s_update_ ();
//SND_ScanChannels (0);
}
static void
s_extra_update (void)
{
if (!sound_started || snd_noextraupdate->int_val)
return; // don't pollute timings
s_update_ ();
}
//static void
//s_extra_update (void)
//{
// if (!sound_started || snd_noextraupdate->int_val)
// return; // don't pollute timings
// s_update_ ();
//}
static void
s_block_sound (void)
{
if (++snd_blocked == 1) {
snd_output_funcs->pS_O_BlockSound ();
s_clear_buffer ();
snd_output_funcs->block_sound (&snd);
s_clear_buffer (&snd);
}
}
@ -241,8 +244,8 @@ s_unblock_sound (void)
return;
if (!--snd_blocked) {
s_clear_buffer ();
snd_output_funcs->pS_O_UnblockSound ();
s_clear_buffer (&snd);
snd_output_funcs->unblock_sound (&snd);
}
}
@ -251,18 +254,20 @@ s_unblock_sound (void)
static void
s_soundinfo_f (void)
{
if (!sound_started || !snd_shm) {
if (!sound_started) {
Sys_Printf ("sound system not started\n");
return;
}
Sys_Printf ("%5d channels\n", snd_shm->channels);
Sys_Printf ("%5d frames\n", snd_shm->frames);
Sys_Printf ("%5d framepos\n", snd_shm->framepos);
Sys_Printf ("%5d samplebits\n", snd_shm->samplebits);
Sys_Printf ("%5d submission_chunk\n", snd_shm->submission_chunk);
Sys_Printf ("%5d speed\n", snd_shm->speed);
Sys_Printf ("0x%"PRIxPTR" dma buffer\n", (intptr_t) snd_shm->buffer);
Sys_Printf ("%5d channels\n", snd.channels);
Sys_Printf ("%5d frames (%.1fms)\n", snd.frames,
1000.0 * snd.frames / snd.speed);
Sys_Printf ("%5d framepos\n", snd.framepos);
Sys_Printf ("%5d samplebits\n", snd.samplebits);
Sys_Printf ("%5d submission_chunk (%.1fms)\n", snd.submission_chunk,
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);
}
@ -278,15 +283,13 @@ s_startup (void)
if (!snd_initialized)
return;
snd_shm = snd_output_funcs->pS_O_Init ();
if (!snd_shm) {
if (!snd_output_funcs->init (&snd)) {
Sys_Printf ("S_Startup: S_O_Init failed.\n");
sound_started = 0;
return;
}
if (!snd_shm->xfer)
snd_shm->xfer = s_xfer_paint_buffer;
if (!snd.xfer)
snd.xfer = s_xfer_paint_buffer;
sound_started = 1;
}
@ -337,8 +340,8 @@ s_init (void)
if (sound_started == 0) // sound startup failed? Bail out.
return;
SND_SFX_Init ();
SND_Channels_Init ();
SND_SFX_Init (&snd);
SND_Channels_Init (&snd);
s_stop_all_sounds ();
}
@ -350,10 +353,96 @@ s_shutdown (void)
return;
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 = {
@ -362,21 +451,24 @@ static general_funcs_t plugin_info_general_funcs = {
};
static snd_render_funcs_t plugin_info_render_funcs = {
.ambient_off = SND_AmbientOff,
.ambient_on = SND_AmbientOn,
.static_sound = SND_StaticSound,
.start_sound = SND_StartSound,
.stop_sound = SND_StopSound,
.precache_sound = SND_PrecacheSound,
.update = s_update,
.ambient_off = s_ambient_off,
.ambient_on = s_ambient_on,
.static_sound = s_static_sound,
.start_sound = s_start_sound,
.local_sound = s_local_sound,
.stop_sound = s_stop_sound,
.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,
.extra_update = s_extra_update,
.local_sound = SND_LocalSound,
.block_sound = s_block_sound,
.unblock_sound = s_unblock_sound,
.load_sound = SND_LoadSound,
.alloc_channel = SND_AllocChannel,
.channel_stop = SND_ChannelStop,
//.extra_update = s_extra_update,
.block_sound = s_block_sound,
.unblock_sound = s_unblock_sound,
};
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 jack_client_t *jack_handle;
static jack_port_t *jack_out[2];
static dma_t _snd_shm;
static snd_t snd;
static float *output[2];
static cvar_t *snd_jack_server;
@ -65,8 +65,8 @@ s_stop_all_sounds (void)
{
if (!sound_started)
return;
SND_StopAllSounds ();
SND_ScanChannels (1);
SND_StopAllSounds (&snd);
SND_ScanChannels (&snd, 1);
}
static void
@ -76,7 +76,8 @@ s_start_sound (int entnum, int entchannel, sfx_t *sfx, const vec3_t origin,
if (!sound_started)
return;
if (!snd_shutdown)
SND_StartSound (entnum, entchannel, sfx, origin, fvol, attenuation);
SND_StartSound (&snd, entnum, entchannel, sfx, origin, fvol,
attenuation);
}
static void
@ -120,7 +121,7 @@ s_update (const vec3_t origin, const vec3_t forward, const vec3_t right,
if (snd_shutdown)
return;
}
SND_SetListener (origin, forward, right, up, ambient_sound_level);
SND_SetListener (&snd, origin, forward, right, up, ambient_sound_level);
}
static void
@ -129,7 +130,7 @@ s_local_sound (const char *sound)
if (!sound_started)
return;
if (!snd_shutdown)
SND_LocalSound (sound);
SND_LocalSound (&snd, sound);
}
static void
@ -184,7 +185,7 @@ s_alloc_channel (void)
if (!sound_started)
return 0;
if (!snd_shutdown)
return SND_AllocChannel ();
return SND_AllocChannel (&snd);
return 0;
}
@ -202,7 +203,7 @@ s_ambient_off (void)
{
if (!sound_started)
return;
SND_AmbientOff ();
SND_AmbientOff (&snd);
}
static void
@ -210,7 +211,7 @@ s_ambient_on (void)
{
if (!sound_started)
return;
SND_AmbientOn ();
SND_AmbientOn (&snd);
}
static void
@ -219,7 +220,7 @@ s_static_sound (sfx_t *sfx, const vec3_t origin, float vol,
{
if (!sound_started)
return;
SND_StaticSound (sfx, origin, vol, attenuation);
SND_StaticSound (&snd, sfx, origin, vol, attenuation);
}
static void
@ -227,7 +228,7 @@ s_stop_sound (int entnum, int entchannel)
{
if (!sound_started)
return;
SND_StopSound (entnum, entchannel);
SND_StopSound (&snd, entnum, entchannel);
}
static sfx_t *
@ -235,7 +236,7 @@ s_precache_sound (const char *name)
{
if (!sound_started)
return 0;
return SND_PrecacheSound (name);
return SND_PrecacheSound (&snd, name);
}
static sfx_t *
@ -243,7 +244,7 @@ s_load_sound (const char *name)
{
if (!sound_started)
return 0;
return SND_LoadSound (name);
return SND_LoadSound (&snd, name);
}
static void
@ -251,11 +252,12 @@ s_channel_stop (channel_t *chan)
{
if (!sound_started)
return;
SND_ChannelStop (chan);
SND_ChannelStop (&snd, chan);
}
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;
@ -281,7 +283,7 @@ snd_jack_process (jack_nframes_t nframes, void *arg)
snd_alive = 1;
for (i = 0; i < 2; i++)
output[i] = (float *) jack_port_get_buffer (jack_out[i], nframes);
SND_PaintChannels (snd_paintedtime + nframes);
SND_PaintChannels (&snd, snd_paintedtime + nframes);
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_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);
snd_shm->speed = jack_get_sample_rate (jack_handle);
snd.speed = jack_get_sample_rate (jack_handle);
s_jack_activate ();
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
s_init (void)
{
snd_shm = &_snd_shm;
snd_shm->xfer = snd_jack_xfer;
snd.xfer = snd_jack_xfer;
Cmd_AddCommand ("snd_force_unblock", s_snd_force_unblock,
"fix permanently blocked sound");
@ -347,8 +348,8 @@ s_init (void)
snd_jack_server = Cvar_Get ("snd_jack_server", "default", CVAR_ROM, NULL,
"The name of the JACK server to connect to");
SND_SFX_Init ();
SND_Channels_Init ();
SND_SFX_Init (&snd);
SND_Channels_Init (&snd);
s_jack_connect ();
}

View file

@ -51,7 +51,6 @@
#define SAMPLE_GAP 4
volatile dma_t *snd_shm;
snd_render_data_t snd_render_data = {
0,
0,
@ -212,7 +211,7 @@ SND_StreamSetPos (sfxbuffer_t *buffer, unsigned int pos)
sfxstream_t *stream = sfx->data.stream;
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->pos = pos;
@ -235,7 +234,7 @@ SND_StreamAdvance (sfxbuffer_t *buffer, unsigned int count)
if (!count)
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
samples = buffer->head - buffer->tail;
@ -360,8 +359,9 @@ SND_GetCache (long frames, int rate, int channels,
float stepscale;
sfxbuffer_t *sc;
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;
size *= sizeof (float) * channels;
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
SND_PaintChannels (unsigned endtime)
SND_PaintChannels (snd_t *snd, unsigned endtime)
{
unsigned end, ltime;
int i, count;
@ -171,8 +171,8 @@ SND_PaintChannels (unsigned endtime)
}
// transfer out according to DMA format
snd_shm->xfer (snd_paintbuffer, end - snd_paintedtime,
snd_volume->value);
snd->xfer (snd, snd_paintbuffer, end - snd_paintedtime,
snd_volume->value);
memmove (snd_paintbuffer, snd_paintbuffer + end - snd_paintedtime,
max_overpaint * sizeof (snd_paintbuffer[0]));

View file

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

View file

@ -112,6 +112,7 @@ SND_SFX_StreamOpen (sfx_t *sfx, void *file,
int (*seek)(sfxstream_t *, int),
void (*close) (sfx_t *))
{
snd_t *snd = sfx->snd;
sfxstream_t *stream = sfx->data.stream;
wavinfo_t *info = &stream->wavinfo;
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
// to jackd)
if (!snd_shm->speed)
if (!snd->speed)
return 0;
sfx_t *new_sfx = calloc (1, sizeof (sfx_t));
new_sfx->snd = sfx->snd;
new_sfx->name = sfx->name;
new_sfx->owner = sfx;
new_sfx->wavinfo = SND_CacheWavinfo;
@ -132,7 +134,7 @@ SND_SFX_StreamOpen (sfx_t *sfx, void *file,
new_sfx->getbuffer = SND_StreamGetBuffer;
new_sfx->close = close;
frames = snd_shm->speed * 0.3;
frames = snd->speed * 0.3;
frames = (frames + 255) & ~255;
size = frames * info->channels * sizeof (float);
@ -168,7 +170,7 @@ SND_SFX_StreamClose (sfx_t *sfx)
}
sfx_t *
SND_LoadSound (const char *name)
SND_LoadSound (snd_t *snd, const char *name)
{
sfx_t *sfx;
@ -181,6 +183,7 @@ SND_LoadSound (const char *name)
Sys_Error ("s_load_sound: out of sfx_t");
sfx = &snd_sfx[snd_num_sfx++];
sfx->snd = snd;
sfx->name = strdup (name);
sfx->owner = sfx;
if (SND_Load (sfx) == -1) {
@ -192,14 +195,14 @@ SND_LoadSound (const char *name)
}
sfx_t *
SND_PrecacheSound (const char *name)
SND_PrecacheSound (snd_t *snd, const char *name)
{
sfx_t *sfx;
if (!name)
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->retain (sfx))
sfx->release (sfx);
@ -243,7 +246,7 @@ s_soundlist_f (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);
precache = Cvar_Get ("precache", "1", CVAR_NONE, NULL,

View file

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

View file

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