mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-17 01:11:45 +00:00
[audio] Allow output plugins to specify model
Output plugins can use either a push model (synchronous) or a pull model (asynchronous). The ALSA plugin now uses the pull model. This paves the way for making jack output a simple output plugin rather than the combined render/output plugin it currently is (for #16) as now snd_dma works with both models.
This commit is contained in:
parent
79825db539
commit
db7e99d842
3 changed files with 87 additions and 119 deletions
|
@ -41,9 +41,15 @@ typedef struct snd_output_funcs_s {
|
|||
void (*unblock_sound) (struct snd_s *snd);
|
||||
} snd_output_funcs_t;
|
||||
|
||||
typedef enum {
|
||||
som_push, // synchronous io (mixer pushes data to driver)
|
||||
som_pull, // asynchronous io (driver pulls data from mixer)
|
||||
} snd_output_model_t;
|
||||
|
||||
typedef struct snd_output_data_s {
|
||||
unsigned *soundtime;
|
||||
unsigned *paintedtime;
|
||||
snd_output_model_t model;
|
||||
} snd_output_data_t;
|
||||
|
||||
#endif // __QF_plugin_snd_output_h
|
||||
|
|
|
@ -68,6 +68,7 @@ static cvar_t *snd_show;
|
|||
static general_data_t plugin_info_general_data;
|
||||
|
||||
static snd_output_funcs_t *snd_output_funcs;
|
||||
static snd_output_data_t *snd_output_data;
|
||||
|
||||
static snd_t snd;
|
||||
static int snd_shutdown = 0;
|
||||
|
@ -147,17 +148,17 @@ s_stop_all_sounds (void)
|
|||
|
||||
//=============================================================================
|
||||
|
||||
/*static void
|
||||
static void
|
||||
s_get_soundtime (void)
|
||||
{
|
||||
int frames, framepos;
|
||||
static int buffers, oldframepos;
|
||||
|
||||
frames = snd_shm->frames;
|
||||
frames = snd.frames;
|
||||
|
||||
// it is possible to miscount buffers if it has wrapped twice between
|
||||
// calls to s_update. Oh well.
|
||||
if ((framepos = snd_output_funcs->pS_O_GetDMAPos ()) == -1)
|
||||
if ((framepos = snd_output_funcs->get_dma_pos (&snd)) == -1)
|
||||
return;
|
||||
|
||||
if (framepos < oldframepos) {
|
||||
|
@ -192,14 +193,14 @@ s_update_ (void)
|
|||
snd_paintedtime = soundtime;
|
||||
}
|
||||
// mix ahead of current position
|
||||
endtime = soundtime + snd_mixahead->value * snd_shm->speed;
|
||||
samps = snd_shm->frames;
|
||||
endtime = soundtime + snd_mixahead->value * snd.speed;
|
||||
samps = snd.frames;
|
||||
if (endtime - soundtime > samps)
|
||||
endtime = soundtime + samps;
|
||||
|
||||
SND_PaintChannels (endtime);
|
||||
snd_output_funcs->pS_O_Submit ();
|
||||
}*/
|
||||
SND_PaintChannels (&snd, endtime);
|
||||
snd_output_funcs->submit (&snd);
|
||||
}
|
||||
|
||||
/*
|
||||
s_update
|
||||
|
@ -215,18 +216,20 @@ s_update (const vec3_t origin, const vec3_t forward, const vec3_t right,
|
|||
|
||||
SND_SetListener (&snd, origin, forward, right, up, ambient_sound_level);
|
||||
|
||||
// mix some sound
|
||||
//s_update_ ();
|
||||
//SND_ScanChannels (0);
|
||||
if (snd_output_data->model == som_push) {
|
||||
// mix some sound
|
||||
s_update_ ();
|
||||
SND_ScanChannels (&snd, 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)
|
||||
|
@ -305,6 +308,7 @@ static void
|
|||
s_init (void)
|
||||
{
|
||||
snd_output_funcs = snd_render_data.output->functions->snd_output;
|
||||
snd_output_data = snd_render_data.output->data->snd_output;
|
||||
snd_render_data.soundtime = &soundtime;
|
||||
Sys_Printf ("\nSound Initialization\n");
|
||||
|
||||
|
@ -466,7 +470,7 @@ static snd_render_funcs_t plugin_info_render_funcs = {
|
|||
|
||||
.update = s_update,
|
||||
.stop_all_sounds = s_stop_all_sounds,
|
||||
//.extra_update = s_extra_update,
|
||||
.extra_update = s_extra_update,
|
||||
.block_sound = s_block_sound,
|
||||
.unblock_sound = s_unblock_sound,
|
||||
};
|
||||
|
|
|
@ -53,19 +53,15 @@ static void *alsa_handle;
|
|||
static snd_pcm_t *pcm;
|
||||
static snd_async_handler_t *async_handler;
|
||||
|
||||
static plugin_t plugin_info;
|
||||
static plugin_data_t plugin_info_data;
|
||||
static plugin_funcs_t plugin_info_funcs;
|
||||
static general_data_t plugin_info_general_data;
|
||||
static general_funcs_t plugin_info_general_funcs;
|
||||
static snd_output_data_t plugin_info_snd_output_data;
|
||||
static snd_output_funcs_t plugin_info_snd_output_funcs;
|
||||
|
||||
static cvar_t *snd_bits;
|
||||
static cvar_t *snd_device;
|
||||
static cvar_t *snd_rate;
|
||||
static cvar_t *snd_stereo;
|
||||
|
||||
//FIXME xfer probably should not be touching this (such data should probably
|
||||
//come through snd_t)
|
||||
static snd_output_data_t plugin_info_snd_output_data;
|
||||
|
||||
#define QF_ALSA_NEED(ret, func, params) \
|
||||
static ret (*qf##func) params;
|
||||
#include "alsa_funcs_list.h"
|
||||
|
@ -106,8 +102,6 @@ SNDDMA_Init_Cvars (void)
|
|||
"sound sample depth. 0 is system default");
|
||||
}
|
||||
|
||||
static int SNDDMA_GetDMAPos (snd_t *snd);
|
||||
|
||||
static __attribute__((const)) snd_pcm_uframes_t
|
||||
round_buffer_size (snd_pcm_uframes_t sz)
|
||||
{
|
||||
|
@ -203,6 +197,7 @@ alsa_xfer (snd_t *snd, portable_samplepair_t *paintbuffer, int count,
|
|||
{
|
||||
int out_idx, out_max, step, val;
|
||||
float *p;
|
||||
alsa_pkt_t *packet = snd->xfer_data;;
|
||||
|
||||
p = (float *) paintbuffer;
|
||||
count *= snd->channels;
|
||||
|
@ -213,7 +208,7 @@ alsa_xfer (snd_t *snd, portable_samplepair_t *paintbuffer, int count,
|
|||
step = 3 - snd->channels;
|
||||
|
||||
if (snd->samplebits == 16) {
|
||||
short *out = (short *) snd->buffer;
|
||||
short *out = (short *) packet->areas[0].addr;
|
||||
|
||||
while (count--) {
|
||||
val = (*p * volume) * 0x8000;
|
||||
|
@ -227,7 +222,7 @@ alsa_xfer (snd_t *snd, portable_samplepair_t *paintbuffer, int count,
|
|||
out_idx = 0;
|
||||
}
|
||||
} else if (snd->samplebits == 8) {
|
||||
unsigned char *out = (unsigned char *) snd->buffer;
|
||||
unsigned char *out = (unsigned char *) packet->areas[0].addr;
|
||||
|
||||
while (count--) {
|
||||
val = (*p * volume) * 128;
|
||||
|
@ -292,6 +287,7 @@ alsa_process (snd_pcm_t *pcm, snd_t *snd)
|
|||
}
|
||||
ret = 0;
|
||||
}
|
||||
snd->buffer = packet.areas[0].addr;
|
||||
SND_PaintChannels (snd, snd_paintedtime + packet.nframes);
|
||||
if ((res = qfsnd_pcm_mmap_commit (pcm, packet.offset,
|
||||
packet.nframes)) < 0
|
||||
|
@ -630,7 +626,15 @@ SNDDMA_Init (snd_t *snd)
|
|||
}
|
||||
|
||||
snd->frames = buffer_size;
|
||||
SNDDMA_GetDMAPos (snd); //XXX sets snd->buffer
|
||||
|
||||
// send the first period to fill the buffer
|
||||
// also sets snd->buffer
|
||||
if (alsa_process (pcm, snd) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
qfsnd_pcm_start (pcm);
|
||||
|
||||
Sys_Printf ("%5d channels %sinterleaved\n", snd->channels,
|
||||
snd->xfer ? "non-" : "");
|
||||
Sys_Printf ("%5d samples (%.1fms)\n", snd->frames,
|
||||
|
@ -644,13 +648,6 @@ SNDDMA_Init (snd_t *snd)
|
|||
|
||||
snd_inited = 1;
|
||||
|
||||
// send the first period to fill the buffer
|
||||
if (alsa_process (pcm, snd) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
qfsnd_pcm_start (pcm);
|
||||
|
||||
return 1;
|
||||
error:
|
||||
qfsnd_pcm_close (pcm);
|
||||
|
@ -662,21 +659,6 @@ error:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
SNDDMA_GetDMAPos (snd_t *snd)
|
||||
{
|
||||
const snd_pcm_channel_area_t *areas;
|
||||
snd_pcm_uframes_t offset;
|
||||
snd_pcm_uframes_t nframes = snd->frames;
|
||||
|
||||
qfsnd_pcm_avail_update (pcm);
|
||||
qfsnd_pcm_mmap_begin (pcm, &areas, &offset, &nframes);
|
||||
snd->framepos = offset;
|
||||
snd->buffer = areas->addr;
|
||||
snd->xfer_data = (void *) areas;
|
||||
return snd->framepos;
|
||||
}
|
||||
|
||||
static void
|
||||
SNDDMA_shutdown (snd_t *snd)
|
||||
{
|
||||
|
@ -688,44 +670,6 @@ SNDDMA_shutdown (snd_t *snd)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
SNDDMA_Submit
|
||||
|
||||
Send sound to device if buffer isn't really the dma buffer
|
||||
*/
|
||||
static void
|
||||
SNDDMA_Submit (snd_t *snd)
|
||||
{
|
||||
int state;
|
||||
int count = (*plugin_info_snd_output_data.paintedtime -
|
||||
*plugin_info_snd_output_data.soundtime);
|
||||
const snd_pcm_channel_area_t *areas;
|
||||
snd_pcm_uframes_t nframes;
|
||||
snd_pcm_uframes_t offset;
|
||||
|
||||
if (snd_blocked)
|
||||
return;
|
||||
|
||||
nframes = count;
|
||||
|
||||
qfsnd_pcm_avail_update (pcm);
|
||||
qfsnd_pcm_mmap_begin (pcm, &areas, &offset, &nframes);
|
||||
|
||||
state = qfsnd_pcm_state (pcm);
|
||||
|
||||
switch (state) {
|
||||
case SND_PCM_STATE_PREPARED:
|
||||
qfsnd_pcm_mmap_commit (pcm, offset, nframes);
|
||||
qfsnd_pcm_start (pcm);
|
||||
break;
|
||||
case SND_PCM_STATE_RUNNING:
|
||||
qfsnd_pcm_mmap_commit (pcm, offset, nframes);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
SNDDMA_BlockSound (snd_t *snd)
|
||||
{
|
||||
|
@ -742,35 +686,49 @@ SNDDMA_UnblockSound (snd_t *snd)
|
|||
qfsnd_pcm_pause (pcm, 0);
|
||||
}
|
||||
|
||||
PLUGIN_INFO(snd_output, alsa)
|
||||
{
|
||||
plugin_info.type = qfp_snd_output;
|
||||
plugin_info.api_version = QFPLUGIN_VERSION;
|
||||
plugin_info.plugin_version = "0.1";
|
||||
plugin_info.description = "ALSA digital output";
|
||||
plugin_info.copyright = "Copyright (C) 1996-1997 id Software, Inc.\n"
|
||||
static general_data_t plugin_info_general_data = {
|
||||
};
|
||||
|
||||
static general_funcs_t plugin_info_general_funcs = {
|
||||
.init = SNDDMA_Init_Cvars,
|
||||
.shutdown = NULL,
|
||||
};
|
||||
|
||||
static snd_output_data_t plugin_info_snd_output_data = {
|
||||
.model = som_pull,
|
||||
};
|
||||
|
||||
static snd_output_funcs_t plugin_info_snd_output_funcs = {
|
||||
.init = SNDDMA_Init,
|
||||
.shutdown = SNDDMA_shutdown,
|
||||
.block_sound = SNDDMA_BlockSound,
|
||||
.unblock_sound = SNDDMA_UnblockSound,
|
||||
};
|
||||
|
||||
static plugin_data_t plugin_info_data = {
|
||||
.general = &plugin_info_general_data,
|
||||
.snd_output = &plugin_info_snd_output_data,
|
||||
};
|
||||
|
||||
static plugin_funcs_t plugin_info_funcs = {
|
||||
.general = &plugin_info_general_funcs,
|
||||
.snd_output = &plugin_info_snd_output_funcs,
|
||||
};
|
||||
|
||||
static plugin_t plugin_info = {
|
||||
.type = qfp_snd_output,
|
||||
.api_version = QFPLUGIN_VERSION,
|
||||
.plugin_version = "0.1",
|
||||
.description = "ALSA digital output",
|
||||
.copyright = "Copyright (C) 1996-1997 id Software, Inc.\n"
|
||||
"Copyright (C) 1999,2000,2001 contributors of the QuakeForge "
|
||||
"project\n"
|
||||
"Please see the file \"AUTHORS\" for a list of contributors";
|
||||
plugin_info.functions = &plugin_info_funcs;
|
||||
plugin_info.data = &plugin_info_data;
|
||||
|
||||
plugin_info_data.general = &plugin_info_general_data;
|
||||
plugin_info_data.input = NULL;
|
||||
plugin_info_data.snd_output = &plugin_info_snd_output_data;
|
||||
|
||||
plugin_info_funcs.general = &plugin_info_general_funcs;
|
||||
plugin_info_funcs.input = NULL;
|
||||
plugin_info_funcs.snd_output = &plugin_info_snd_output_funcs;
|
||||
|
||||
plugin_info_general_funcs.init = SNDDMA_Init_Cvars;
|
||||
plugin_info_general_funcs.shutdown = NULL;
|
||||
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;
|
||||
"Please see the file \"AUTHORS\" for a list of contributors",
|
||||
.functions = &plugin_info_funcs,
|
||||
.data = &plugin_info_data,
|
||||
};
|
||||
|
||||
PLUGIN_INFO(snd_output, alsa)
|
||||
{
|
||||
return &plugin_info;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue