snd_dma.c: added SNDDMA_LockBuffer() as a new API, needed for, well, proper buffer

locking.  removed simsound. removed unused S_AmbientOff() and S_AmbientOn(). other
multiple cleanups and fixes.
snd_sdl.c: replaced the old broken implementation which used to cause LRU failures
with the one adapted from the uhexen2 project.
sound.h: added missing prototypes, including the new SNDDMA_LockBuffer().


git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@6 af15c1b1-3010-417e-b628-4374ebc0bcbd
This commit is contained in:
Ozkan Sezer 2010-02-15 23:45:06 +00:00
parent 141b4836ac
commit 5f028f87a3
3 changed files with 281 additions and 215 deletions

View File

@ -35,15 +35,13 @@ void S_StopAllSoundsC(void);
// =======================================================================
channel_t channels[MAX_CHANNELS];
int total_channels;
int total_channels;
int snd_blocked = 0;
static qboolean snd_ambient = 1;
qboolean snd_initialized = false;
int snd_blocked = 0;
qboolean snd_initialized = false;
// pointer should go away
volatile dma_t *shm = 0;
volatile dma_t sn;
volatile dma_t *shm = NULL;
volatile dma_t sn;
vec3_t listener_origin;
vec3_t listener_forward;
@ -51,17 +49,17 @@ vec3_t listener_right;
vec3_t listener_up;
vec_t sound_nominal_clip_dist=1000.0;
int soundtime; // sample PAIRS
int paintedtime; // sample PAIRS
int soundtime; // sample PAIRS
int paintedtime; // sample PAIRS
#define MAX_SFX 512
sfx_t *known_sfx; // hunk allocated [MAX_SFX]
int num_sfx;
int num_sfx;
sfx_t *ambient_sfx[NUM_AMBIENTS];
int sound_started=0;
qboolean sound_started = false;
cvar_t bgmvolume = {"bgmvolume", "1", true};
cvar_t volume = {"volume", "0.7", true};
@ -78,33 +76,6 @@ cvar_t _snd_mixahead = {"_snd_mixahead", "0.1", true};
cvar_t sndspeed = {"sndspeed", "11025"};
// ====================================================================
// User-setable variables
// ====================================================================
//
// Fake dma is a synchronous faking of the DMA progress used for
// isolating performance in the renderer. The fakedma_updates is
// number of times S_Update() is called per second.
//
qboolean fakedma = false;
int fakedma_updates = 15;
void S_AmbientOff (void)
{
snd_ambient = false;
}
void S_AmbientOn (void)
{
snd_ambient = true;
}
void S_SoundInfo_f(void)
{
if (!sound_started || !shm)
@ -113,14 +84,13 @@ void S_SoundInfo_f(void)
return;
}
Con_Printf("%5d stereo\n", shm->channels - 1);
Con_Printf("%5d samples\n", shm->samples);
Con_Printf("%5d samplepos\n", shm->samplepos);
Con_Printf("%5d samplebits\n", shm->samplebits);
Con_Printf("%5d submission_chunk\n", shm->submission_chunk);
Con_Printf("%5d speed\n", shm->speed);
Con_Printf("0x%x dma buffer\n", shm->buffer);
Con_Printf("%d bit, %s, %d Hz\n", shm->samplebits,
(shm->channels == 2) ? "stereo" : "mono", shm->speed);
Con_Printf("%5d samples\n", shm->samples);
Con_Printf("%5d samplepos\n", shm->samplepos);
Con_Printf("%5d submission_chunk\n", shm->submission_chunk);
Con_Printf("%5d total_channels\n", total_channels);
Con_Printf("%p dma buffer\n", shm->buffer);
}
@ -137,21 +107,19 @@ void S_Startup (void)
if (!snd_initialized)
return;
if (!fakedma)
sound_started = SNDDMA_Init();
if (!sound_started)
{
rc = SNDDMA_Init();
if (!rc)
{
#ifndef _WIN32
Con_Printf("S_Startup: SNDDMA_Init failed.\n");
#endif
sound_started = 0;
return;
}
Con_Printf("Failed initializing sound\n");
}
else
{
Con_Printf("Audio: %d bit, %s, %d Hz\n",
shm->samplebits,
(shm->channels == 2) ? "stereo" : "mono",
shm->speed);
}
sound_started = 1;
}
@ -162,23 +130,11 @@ S_Init
*/
void S_Init (void)
{
if (COM_CheckParm("-nosound"))
if (snd_initialized)
{
Con_Printf("Sound is already initialized\n");
return;
//johnfitz -- clean up init readouts
Con_Printf("Sound Initialization\n");
//Con_Printf("------------- Init Sound -------------\n");
//Con_Printf("%cSound Init\n", 2);
//johnfitz
if (COM_CheckParm("-simsound"))
fakedma = true;
Cmd_AddCommand("play", S_Play);
Cmd_AddCommand("playvol", S_PlayVol);
Cmd_AddCommand("stopsound", S_StopAllSoundsC);
Cmd_AddCommand("soundlist", S_SoundList);
Cmd_AddCommand("soundinfo", S_SoundInfo_f);
}
Cvar_RegisterVariable(&nosound, NULL);
Cvar_RegisterVariable(&volume, NULL);
@ -191,7 +147,18 @@ void S_Init (void)
Cvar_RegisterVariable(&snd_noextraupdate, NULL);
Cvar_RegisterVariable(&snd_show, NULL);
Cvar_RegisterVariable(&_snd_mixahead, NULL);
Cvar_RegisterVariable(&sndspeed, NULL);
Cvar_RegisterVariable(&sndspeed, NULL);
if (COM_CheckParm("-nosound"))
return;
Con_Printf("Sound Initialization\n");
Cmd_AddCommand("play", S_Play);
Cmd_AddCommand("playvol", S_PlayVol);
Cmd_AddCommand("stopsound", S_StopAllSoundsC);
Cmd_AddCommand("soundlist", S_SoundList);
Cmd_AddCommand("soundinfo", S_SoundInfo_f);
if (COM_CheckParm("-sndspeed"))
{
@ -204,38 +171,18 @@ void S_Init (void)
Con_Printf ("loading all sounds as 8bit\n");
}
snd_initialized = true;
S_Startup ();
SND_InitScaletable ();
known_sfx = Hunk_AllocName (MAX_SFX*sizeof(sfx_t), "sfx_t");
num_sfx = 0;
// create a piece of DMA memory
snd_initialized = true;
if (fakedma)
{
shm = (void *) Hunk_AllocName(sizeof(*shm), "shm");
shm->splitbuffer = 0;
shm->samplebits = 16;
shm->speed = 22050;
shm->channels = 2;
shm->samples = 32768;
shm->samplepos = 0;
shm->soundalive = true;
shm->gamealive = true;
shm->submission_chunk = 1;
shm->buffer = Hunk_AllocName(1<<16, "shmbuf");
}
Con_Printf ("Sound sampling rate: %i\n", shm->speed);
S_Startup ();
if (sound_started == 0)
return;
// provides a tick sound until washed clean
// if (shm->buffer)
// shm->buffer[4] = shm->buffer[5] = 0x7f; // force a pop for debugging
@ -252,20 +199,16 @@ void S_Init (void)
void S_Shutdown(void)
{
if (!sound_started)
return;
if (shm)
shm->gamealive = 0;
shm = 0;
sound_started = 0;
snd_blocked = 0;
if (!fakedma)
{
SNDDMA_Shutdown();
}
SNDDMA_Shutdown();
shm = NULL;
}
@ -285,17 +228,19 @@ sfx_t *S_FindName (char *name)
sfx_t *sfx;
if (!name)
Sys_Error ("S_FindName: NULL\n");
Sys_Error ("S_FindName: NULL");
if (Q_strlen(name) >= MAX_QPATH)
Sys_Error ("Sound name too long: %s", name);
// see if already loaded
for (i=0 ; i < num_sfx ; i++)
{
if (!Q_strcmp(known_sfx[i].name, name))
{
return &known_sfx[i];
}
}
if (num_sfx == MAX_SFX)
Sys_Error ("S_FindName: out of sfx_t");
@ -406,12 +351,8 @@ void SND_Spatialize(channel_t *ch)
vec_t dist;
vec_t lscale, rscale, scale;
vec3_t source_vec;
sfx_t *snd;
/* unused -- kristian
vec_t ldist, rdist;
*/
// anything coming from the view entity will allways be full volume
// anything coming from the view entity will always be full volume
if (ch->entnum == cl.viewentity)
{
ch->leftvol = ch->master_vol;
@ -420,12 +361,8 @@ void SND_Spatialize(channel_t *ch)
}
// calculate stereo seperation and distance attenuation
snd = ch->sfx;
VectorSubtract(ch->origin, listener_origin, source_vec);
dist = VectorNormalize(source_vec) * ch->dist_mult;
dot = DotProduct(listener_right, source_vec);
if (shm->channels == 1)
@ -460,7 +397,6 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f
{
channel_t *target_chan, *check;
sfxcache_t *sc;
int vol;
int ch_idx;
int skip;
@ -473,8 +409,6 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f
if (nosound.value)
return;
vol = fvol*255;
// pick a channel to play on
target_chan = SND_PickChannel(entnum, entchannel);
if (!target_chan)
@ -484,7 +418,7 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f
memset (target_chan, 0, sizeof(*target_chan));
VectorCopy(origin, target_chan->origin);
target_chan->dist_mult = attenuation / sound_nominal_clip_dist;
target_chan->master_vol = vol;
target_chan->master_vol = (int) (fvol * 255);
target_chan->entnum = entnum;
target_chan->entchannel = entchannel;
SND_Spatialize(target_chan);
@ -520,7 +454,6 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f
target_chan->end -= skip;
break;
}
}
}
@ -550,10 +483,12 @@ void S_StopAllSounds(qboolean clear)
total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics
for (i=0 ; i<MAX_CHANNELS ; i++)
{
if (channels[i].sfx)
channels[i].sfx = NULL;
}
Q_memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
if (clear)
S_ClearBuffer ();
@ -568,7 +503,11 @@ void S_ClearBuffer (void)
{
int clear;
if (!sound_started || !shm || !shm->buffer)
if (!sound_started || !shm)
return;
SNDDMA_LockBuffer ();
if (! shm->buffer)
return;
if (shm->samplebits == 8)
@ -576,7 +515,9 @@ void S_ClearBuffer (void)
else
clear = 0;
Q_memset(shm->buffer, clear, shm->samples * shm->samplebits/8);
memset(shm->buffer, clear, shm->samples * shm->samplebits / 8);
SNDDMA_Submit ();
}
@ -636,9 +577,6 @@ void S_UpdateAmbientSounds (void)
int ambient_channel;
channel_t *chan;
if (!snd_ambient)
return;
//johnfitz -- no ambients when disconnected
if (cls.state != ca_connected)
return;
@ -737,8 +675,10 @@ void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
// search for one
combine = channels+MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;
for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; j<i; j++, combine++)
{
if (combine->sfx == ch->sfx)
break;
}
if (j == total_channels)
{
@ -755,8 +695,6 @@ void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
continue;
}
}
}
//
@ -767,11 +705,13 @@ void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
total = 0;
ch = channels;
for (i=0 ; i<total_channels; i++, ch++)
{
if (ch->sfx && (ch->leftvol || ch->rightvol) )
{
//Con_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
total++;
}
}
Con_Printf ("----(%i)----\n", total);
}
@ -824,12 +764,17 @@ void S_ExtraUpdate (void)
void S_Update_(void)
{
unsigned endtime;
int samps;
#if 1
unsigned int endtime;
int samps;
if (!sound_started || (snd_blocked > 0))
return;
SNDDMA_LockBuffer ();
if (! shm->buffer)
return;
// Updates DMA time
GetSoundtime();
@ -848,7 +793,32 @@ void S_Update_(void)
S_PaintChannels (endtime);
// SNDDMA_Submit ();
SNDDMA_Submit ();
#endif
}
void S_BlockSound (void)
{
/* FIXME: do we really need the blocking at the
* driver level?
*/
if (sound_started && ++snd_blocked == 1)
{
S_ClearBuffer ();
if (shm)
SNDDMA_BlockSound();
}
}
void S_UnblockSound (void)
{
if (!sound_started || !snd_blocked)
return;
if (--snd_blocked == 0)
{
SNDDMA_UnblockSound();
S_ClearBuffer ();
}
}
/*
@ -932,7 +902,7 @@ void S_SoundList(void)
}
void S_LocalSound (char *sound)
void S_LocalSound (char *name)
{
sfx_t *sfx;
@ -941,10 +911,10 @@ void S_LocalSound (char *sound)
if (!sound_started)
return;
sfx = S_PrecacheSound (sound);
sfx = S_PrecacheSound (name);
if (!sfx)
{
Con_Printf ("S_LocalSound: can't cache %s\n", sound);
Con_Printf ("S_LocalSound: can't cache %s\n", name);
return;
}
S_StartSound (cl.viewentity, -1, sfx, vec3_origin, 1, 1);

View File

@ -1,125 +1,207 @@
/*
Copyright (C) 1996-2001 Id Software, Inc.
Copyright (C) 2002-2005 John Fitzgibbons and others
Copyright (C) 2007-2008 Kristian Duske
snd_sdl2.c
SDL audio driver for Hexen II: Hammer of Thyrion, based on the
implementations found in the quakeforge and quake3-icculus.org
projects.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
$Id: snd_sdl2.c,v 1.8 2010/01/23 12:01:23 sezero Exp $
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
See the GNU General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
51 Franklin St, Fifth Floor,
Boston, MA 02110-1301 USA
*/
// stolen from http://www.libsdl.org/projects/quake/ -- apologies, I don't know the author's name
#include <stdio.h>
#include "quakedef.h"
#include "SDL.h"
static dma_t the_shm;
static int snd_inited;
static int buffersize;
#define BUF_SIZE 512
static void paint_audio(void *unused, Uint8 *stream, int len)
static void paint_audio (void *unused, Uint8 *stream, int len)
{
if ( shm ) {
shm->buffer = stream;
shm->samplepos += len/(shm->samplebits/8)/2;
// Check for samplepos overflow?
S_PaintChannels (shm->samplepos);
int pos, tobufend;
int len1, len2;
if (!shm)
{ /* shouldn't happen, but just in case */
memset(stream, 0, len);
return;
}
pos = (shm->samplepos * (shm->samplebits / 8));
if (pos >= buffersize)
shm->samplepos = pos = 0;
tobufend = buffersize - pos; /* bytes to buffer's end. */
len1 = len;
len2 = 0;
if (len1 > tobufend)
{
len1 = tobufend;
len2 = len - len1;
}
memcpy(stream, shm->buffer + pos, len1);
if (len2 <= 0)
{
shm->samplepos += (len1 / (shm->samplebits / 8));
}
else
{ /* wraparound? */
memcpy(stream + len1, shm->buffer, len2);
shm->samplepos = (len2 / (shm->samplebits / 8));
}
if (shm->samplepos >= buffersize)
shm->samplepos = 0;
}
qboolean SNDDMA_Init(void)
qboolean SNDDMA_Init (void)
{
SDL_AudioSpec desired, obtained;
int tmp, val;
char drivername[128];
snd_inited = 0;
if (SDL_InitSubSystem(SDL_INIT_AUDIO) == -1)
{
Con_Printf("Couldn't init SDL audio: %s\n", SDL_GetError());
return false;
}
/* Set up the desired format */
desired.freq = sndspeed.value;
if (loadas8bit.value) {
desired.format = AUDIO_U8;
} else {
if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
desired.format = AUDIO_S16MSB;
else
desired.format = AUDIO_S16LSB;
}
desired.channels = 2;
desired.samples = BUF_SIZE;
desired.freq = tmp = sndspeed.value;
desired.format = (loadas8bit.value) ? AUDIO_U8 : AUDIO_S16SYS;
desired.channels = 2; /* = desired_channels; */
if (desired.freq <= 11025)
desired.samples = 256;
else if (desired.freq <= 22050)
desired.samples = 512;
else if (desired.freq <= 44100)
desired.samples = 1024;
else
desired.samples = 2048; /* shrug */
desired.callback = paint_audio;
desired.userdata = NULL;
/* Open the audio device */
if ( SDL_OpenAudio(&desired, &obtained) < 0 ) {
Con_Printf("Couldn't open SDL audio: %s\n", SDL_GetError());
return 0;
if (SDL_OpenAudio(&desired, &obtained) == -1)
{
Con_Printf("Couldn't open SDL audio: %s\n", SDL_GetError());
SDL_QuitSubSystem(SDL_INIT_AUDIO);
return false;
}
/* Make sure we can support the audio format */
switch (obtained.format) {
case AUDIO_U8:
/* Supported */
break;
case AUDIO_S16LSB:
case AUDIO_S16MSB:
if ( ((obtained.format == AUDIO_S16LSB) &&
(SDL_BYTEORDER == SDL_LIL_ENDIAN)) ||
((obtained.format == AUDIO_S16MSB) &&
(SDL_BYTEORDER == SDL_BIG_ENDIAN)) ) {
/* Supported */
break;
}
/* Unsupported, fall through */;
default:
/* Not supported -- force SDL to do our bidding */
SDL_CloseAudio();
if ( SDL_OpenAudio(&desired, NULL) < 0 ) {
Con_Printf("Couldn't open SDL audio: %s\n",
SDL_GetError());
return 0;
}
memcpy(&obtained, &desired, sizeof(desired));
break;
switch (obtained.format)
{
case AUDIO_U8:
case AUDIO_S16SYS:
/* Supported */
break;
default:
Con_Printf ("Unsupported audio format received (%u)\n", obtained.format);
SDL_CloseAudio();
SDL_QuitSubSystem(SDL_INIT_AUDIO);
return false;
}
SDL_PauseAudio(0);
memset ((void *) &sn, 0, sizeof(dma_t));
shm = &sn;
/* Fill the audio DMA information block */
shm = &the_shm;
shm->splitbuffer = 0;
shm->samplebits = (obtained.format & 0xFF);
shm->samplebits = (obtained.format & 0xFF); /* first byte of format is bits */
if (obtained.freq != tmp)
Con_Printf ("Warning: Rate set (%d) didn't match requested rate (%d)!\n", obtained.freq, tmp);
shm->speed = obtained.freq;
shm->channels = obtained.channels;
shm->samples = obtained.samples*shm->channels;
tmp = (obtained.samples * obtained.channels) * 10;
if (tmp & (tmp - 1))
{ /* make it a power of two */
val = 1;
while (val < tmp)
val <<= 1;
tmp = val;
}
shm->samples = tmp;
shm->samplepos = 0;
shm->submission_chunk = 1;
shm->buffer = NULL;
snd_inited = 1;
return 1;
Con_Printf ("SDL audio spec : %d Hz, %d samples, %d channels\n",
obtained.freq, obtained.samples, obtained.channels);
if (SDL_AudioDriverName(drivername, sizeof(drivername)) == NULL)
strcpy(drivername, "(UNKNOWN)");
buffersize = shm->samples * (shm->samplebits / 8);
Con_Printf ("SDL audio driver: %s, %d bytes buffer\n", drivername, buffersize);
shm->buffer = (unsigned char *) calloc (1, buffersize);
if (!shm->buffer)
{
SDL_CloseAudio();
SDL_QuitSubSystem(SDL_INIT_AUDIO);
shm = NULL;
Con_Printf ("Failed allocating memory for SDL audio\n");
return false;
}
SDL_PauseAudio(0);
return true;
}
int SNDDMA_GetDMAPos(void)
int SNDDMA_GetDMAPos (void)
{
return shm->samplepos;
}
void SNDDMA_Shutdown(void)
void SNDDMA_Shutdown (void)
{
if (snd_inited)
if (shm)
{
Con_Printf ("Shutting down SDL sound\n");
SDL_PauseAudio(1);
SDL_LockAudio ();
SDL_CloseAudio();
snd_inited = 0;
if (shm->buffer)
free (shm->buffer);
SDL_QuitSubSystem(SDL_INIT_AUDIO);
shm->buffer = NULL;
shm = NULL;
}
}
void SNDDMA_LockBuffer (void)
{
SDL_LockAudio ();
}
void SNDDMA_Submit (void)
{
SDL_UnlockAudio();
}
void SNDDMA_BlockSound (void)
{
SDL_PauseAudio(1);
}
void SNDDMA_UnblockSound (void)
{
SDL_PauseAudio(0);
}

View File

@ -102,6 +102,9 @@ void S_ClearBuffer (void);
void S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up);
void S_ExtraUpdate (void);
void S_BlockSound (void);
void S_UnblockSound (void);
sfx_t *S_PrecacheSound (char *sample);
void S_TouchSound (char *sample);
void S_ClearPrecache (void);
@ -125,6 +128,18 @@ int SNDDMA_GetDMAPos(void);
// shutdown the DMA xfer.
void SNDDMA_Shutdown(void);
/* validates & locks the dma buffer */
void SNDDMA_LockBuffer(void);
/* unlocks the dma buffer / sends sound to the device */
void SNDDMA_Submit(void);
/* blocks sound output upon window focus loss */
void SNDDMA_BlockSound(void);
/* unblocks the output upon window focus gain */
void SNDDMA_UnblockSound(void);
// ====================================================================
// User-setable variables
// ====================================================================
@ -172,7 +187,6 @@ sfxcache_t *S_LoadSound (sfx_t *s);
wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength);
void SND_InitScaletable (void);
void SNDDMA_Submit(void);
void S_AmbientOff (void);
void S_AmbientOn (void);