From 86e7ecb0f47ddfa9900769c2f4d315657db03c09 Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Wed, 13 Oct 2010 21:04:59 +0000 Subject: [PATCH] Das SDL Soundbackend komplett reimplementiert. --- src/sdl/sound.c | 313 +++++++++++++++++++++++++----------------------- 1 file changed, 163 insertions(+), 150 deletions(-) diff --git a/src/sdl/sound.c b/src/sdl/sound.c index 35e76209..62dc926e 100644 --- a/src/sdl/sound.c +++ b/src/sdl/sound.c @@ -1,185 +1,198 @@ -/* - snd_sdl.c - - Sound code taken from SDLQuake and modified to work with Quake2 - Robert Bäuml 2001-12-25 - - 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. - - 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. - - 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. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - - $Id: snd_sdl.c,v 1.2 2002/02/09 20:29:38 relnev Exp $ -*/ - -#include "SDL.h" - +#include #include "../client/header/client.h" #include "../client/sound/header/local.h" -static int snd_inited; -static dma_t *shm; +/* Global stuff */ +int snd_inited = 0; +static int dmapos = 0; +static int dmasize = 0; +static dma_t *dmabackend; -static void -paint_audio (void *unused, Uint8 * stream, int len) +/* The callback */ +static void +sdl_audio_callback(void *data, Uint8 *stream, int length) { - if (shm) { - shm->buffer = stream; - shm->samplepos += len / (shm->samplebits / 4); - // Check for samplepos overflow? - S_PaintChannels (shm->samplepos); + int length1; + int length2; + int pos = (dmapos * (dmabackend->samplebits / 8)); + + if (pos >= dmasize) + { + dmapos = pos = 0; + } + + /* This can't happen! */ + if (!snd_inited) + { + memset(stream, '\0', length); + return; + } + + int tobufferend = dmasize - pos; + + if (length > tobufferend) + { + length1 = tobufferend; + length2 = length - length1; + } + else + { + length1= length; + length2 = 0; + } + + memcpy(stream, dmabackend->buffer + pos, length1); + + /* Set new position */ + if (length2 <= 0) + { + dmapos += (length1 / (dmabackend->samplebits / 8)); + } + else + { + memcpy(stream + length1, dmabackend->buffer, length2); + dmapos = (length2 / (dmabackend->samplebits / 8)); + } + + if (dmapos >= dmasize) + { + dmapos = 0; } } qboolean -SNDDMA_Init (void) +SNDDMA_Init(void) { - SDL_AudioSpec desired, obtained; - int desired_bits, freq; - - if (SDL_WasInit(SDL_INIT_EVERYTHING) == 0) { - if (SDL_Init(SDL_INIT_AUDIO) < 0) { - Com_Printf ("Couldn't init SDL audio: %s\n", SDL_GetError ()); - return 0; - } - } else if (SDL_WasInit(SDL_INIT_AUDIO) == 0) { - if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { - Com_Printf ("Couldn't init SDL audio: %s\n", SDL_GetError ()); - return 0; - } - } - - snd_inited = 0; - desired_bits = (Cvar_Get("sndbits", "16", CVAR_ARCHIVE))->value; + char drivername[128]; + SDL_AudioSpec desired; + SDL_AudioSpec optained; - /* Set up the desired format */ - freq = (Cvar_Get("s_khz", "0", CVAR_ARCHIVE))->value; - if (freq == 44) - desired.freq = 44100; - else if (freq == 22) - desired.freq = 22050; - else - desired.freq = 11025; - - switch (desired_bits) { - case 8: - desired.format = AUDIO_U8; - break; - case 16: - if (SDL_BYTEORDER == SDL_BIG_ENDIAN) - desired.format = AUDIO_S16MSB; - else - desired.format = AUDIO_S16LSB; - break; - default: - Com_Printf ("Unknown number of audio bits: %d\n", desired_bits); - return 0; + /* This should never happen, + but this is Quake 2 ... */ + if (snd_inited) + { + return 1; + } + + int sndbits = (Cvar_Get("sndbits", "16", CVAR_ARCHIVE))->value; + int sndfreq = (Cvar_Get("s_khz", "0", CVAR_ARCHIVE))->value; + int sndchans = (Cvar_Get("sndchannels", "2", CVAR_ARCHIVE))->value; + + if (!SDL_WasInit(SDL_INIT_AUDIO)) + { + if (SDL_Init(SDL_INIT_AUDIO) == -1) + { + Com_Printf ("Couldn't init SDL audio: %s\n", SDL_GetError ()); + return 0; + } } - desired.channels = (Cvar_Get("sndchannels", "2", CVAR_ARCHIVE))->value; - if (desired.freq == 44100) - desired.samples = 2048; - else if (desired.freq == 22050) - desired.samples = 1024; - else + if (SDL_AudioDriverName(drivername, sizeof(drivername)) == NULL) + { + strcpy(drivername, "(UNKNOW)"); + } + + Com_Printf("SDL audio driver is \"%s\"\n", drivername); + + memset(&desired, '\0', sizeof(desired)); + memset(&optained, '\0', sizeof(optained)); + + /* Users are stupid */ + if ((sndbits != 16) && (sndbits != 8)) + { + sndbits = 16; + } + + if (sndfreq == 22) + { + desired.freq = 22050; + } + else if (sndfreq == 11) + { + desired.freq = 11025; + } + + desired.format = ((sndbits == 16) ? AUDIO_S16SYS : AUDIO_U8); + + if (desired.freq <= 11025) + { + desired.samples = 256; + } + else if (desired.freq <= 22050) + { desired.samples = 512; - - desired.callback = paint_audio; - - /* Open the audio device */ - if (SDL_OpenAudio (&desired, &obtained) < 0) { - Com_Printf ("Couldn't open SDL audio: %s\n", SDL_GetError ()); + } + else + { + desired.samples = 2048; + } + + desired.channels = sndchans; + desired.callback = sdl_audio_callback; + + /* Okay, let's try our luck */ + if (SDL_OpenAudio(&desired, &optained) == -1) + { + Com_Printf("SDL_OpenAudio() failed: %s\n", SDL_GetError()); + SDL_QuitSubSystem(SDL_INIT_AUDIO); return 0; } - /* 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) { - Com_Printf ("Couldn't open SDL audio: %s\n", SDL_GetError ()); - return 0; - } - memcpy (&obtained, &desired, sizeof (desired)); - break; - } - SDL_PauseAudio (0); + /* Don't pollute the frontend dma_t */ + dmabackend = &dma; + + dmapos = 0; + dmabackend->samplebits = optained.format & 0xFF; + dmabackend->channels = optained.channels; + dmabackend->samples = 32768; + dmabackend->submission_chunk = 1; + dmabackend->speed = optained.freq; + dmasize = (dmabackend->samples * (dmabackend->samplebits / 8)); + dmabackend->buffer = calloc(1, dmasize); - /* Fill the audio DMA information block */ - shm = &dma; - shm->samplebits = (obtained.format & 0xFF); - shm->speed = obtained.freq; - shm->channels = obtained.channels; - shm->samples = obtained.samples * shm->channels; - shm->samplepos = 0; - shm->submission_chunk = 1; - shm->buffer = NULL; + Com_Printf("Starting SDL audio callback...\n"); + SDL_PauseAudio(0); - snd_inited = 1; - return 1; + Com_Printf("SDL audio initialized.\n"); + snd_inited = 1; + return 1; } int -SNDDMA_GetDMAPos (void) +SNDDMA_GetDMAPos(void) { - return shm->samplepos; + return dmapos; } void -SNDDMA_Shutdown (void) +SNDDMA_Shutdown(void) { - if (snd_inited) { - SDL_CloseAudio (); - snd_inited = 0; - } - - if (SDL_WasInit(SDL_INIT_EVERYTHING) == SDL_INIT_AUDIO) - SDL_Quit(); - else - SDL_QuitSubSystem(SDL_INIT_AUDIO); + Com_Printf("Closing SDL audio device...\n"); + SDL_PauseAudio(1); + SDL_CloseAudio(); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + free(dmabackend->buffer); + dmabackend->buffer = NULL; + dmapos = dmasize = 0; + snd_inited = 0; + Com_Printf("SDL audio device shut down.\n"); } -/* - - SNDDMA_Submit - - Send sound to device if buffer isn't really the dma buffer - -*/ +/* + * This sends the sound to the device, + * if the DMA isn't the device itself. + * This shouldn't be the case on all PCI + * and PCIe soundcards + */ void -SNDDMA_Submit (void) +SNDDMA_Submit(void) { + SDL_UnlockAudio(); } - -void SNDDMA_BeginPainting(void) -{ +void +SNDDMA_BeginPainting(void) +{ + SDL_LockAudio(); }