From 5f028f87a393b3ac5925a6d06b6afc998ce37a55 Mon Sep 17 00:00:00 2001 From: Ozkan Sezer Date: Mon, 15 Feb 2010 23:45:06 +0000 Subject: [PATCH] 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 --- Quake/snd_dma.c | 240 +++++++++++++++++++++--------------------------- Quake/snd_sdl.c | 240 ++++++++++++++++++++++++++++++++---------------- Quake/sound.h | 16 +++- 3 files changed, 281 insertions(+), 215 deletions(-) diff --git a/Quake/snd_dma.c b/Quake/snd_dma.c index 072de83c..3aaa237a 100644 --- a/Quake/snd_dma.c +++ b/Quake/snd_dma.c @@ -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 ; ibuffer) + 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 ; jsfx == 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 ; isfx && (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); diff --git a/Quake/snd_sdl.c b/Quake/snd_sdl.c index 619cf876..80769024 100644 --- a/Quake/snd_sdl.c +++ b/Quake/snd_sdl.c @@ -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 #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); +} + diff --git a/Quake/sound.h b/Quake/sound.h index 964162e7..6f0e9578 100644 --- a/Quake/sound.h +++ b/Quake/sound.h @@ -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);