diff options
Diffstat (limited to 'code/unix')
-rw-r--r-- | code/unix/Makefile | 27 | ||||
-rw-r--r-- | code/unix/sdl_snd.c | 428 |
2 files changed, 268 insertions, 187 deletions
diff --git a/code/unix/Makefile b/code/unix/Makefile index 43083d1..4d2ab9b 100644 --- a/code/unix/Makefile +++ b/code/unix/Makefile @@ -47,6 +47,10 @@ ifndef USE_SDL USE_SDL=1 endif +ifndef USE_OPENAL +USE_OPENAL=1 +endif + ifndef BUILD_CLIENT BUILD_CLIENT=1 endif @@ -115,6 +119,10 @@ ifeq ($(PLATFORM),linux) BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes + ifeq ($(USE_OPENAL),1) + BASE_CFLAGS += -DUSE_OPENAL=1 + endif + ifeq ($(USE_SDL),1) BASE_CFLAGS += -DUSE_SDL_VIDEO=1 -DUSE_SDL_SOUND=1 $(shell sdl-config --cflags) GL_CFLAGS = @@ -214,6 +222,10 @@ ifeq ($(PLATFORM),mingw32) BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes + ifeq ($(USE_OPENAL),1) + BASE_CFLAGS += -DUSE_OPENAL=1 + endif + DX_CFLAGS = -I$(DXSDK_DIR)/Include GL_CFLAGS = @@ -620,6 +632,13 @@ Q3OBJ = \ $(B)/client/snd_mix.o \ $(B)/client/snd_wavelet.o \ \ + $(B)/client/snd_main.o \ + $(B)/client/snd_codec.o \ + $(B)/client/snd_codec_wav.o \ + \ + $(B)/client/qal.o \ + $(B)/client/snd_openal.o \ + \ $(B)/client/sv_bot.o \ $(B)/client/sv_ccmds.o \ $(B)/client/sv_client.o \ @@ -891,6 +910,14 @@ $(B)/client/snd_dma.o : $(CDIR)/snd_dma.c; $(DO_CC) $(B)/client/snd_mem.o : $(CDIR)/snd_mem.c; $(DO_CC) $(B)/client/snd_mix.o : $(CDIR)/snd_mix.c; $(DO_CC) $(B)/client/snd_wavelet.o : $(CDIR)/snd_wavelet.c; $(DO_CC) + +$(B)/client/snd_main.o : $(CDIR)/snd_main.c; $(DO_CC) +$(B)/client/snd_codec.o : $(CDIR)/snd_codec.c; $(DO_CC) +$(B)/client/snd_codec_wav.o : $(CDIR)/snd_codec_wav.c; $(DO_CC) + +$(B)/client/qal.o : $(CDIR)/qal.c; $(DO_CC) +$(B)/client/snd_openal.o : $(CDIR)/snd_openal.c; $(DO_CC) + $(B)/client/sv_bot.o : $(SDIR)/sv_bot.c; $(DO_CC) $(B)/client/sv_client.o : $(SDIR)/sv_client.c; $(DO_CC) $(B)/client/sv_ccmds.o : $(SDIR)/sv_ccmds.c; $(DO_CC) diff --git a/code/unix/sdl_snd.c b/code/unix/sdl_snd.c index 3caf85a..ac4a614 100644 --- a/code/unix/sdl_snd.c +++ b/code/unix/sdl_snd.c @@ -56,233 +56,285 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../qcommon/q_shared.h" #include "../client/snd_local.h" -int snd_inited=0; +qboolean snd_inited = qfalse; -cvar_t *sndbits; -cvar_t *sndspeed; -cvar_t *sndchannels; -cvar_t *snddevice; -cvar_t *sdldevsamps; -cvar_t *sdlmixsamps; +cvar_t *s_sdlBits; +cvar_t *s_sdlSpeed; +cvar_t *s_sdlChannels; +cvar_t *s_sdlDevSamps; +cvar_t *s_sdlMixSamps; static qboolean use_custom_memset = qfalse; -// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371 + +/* +=============== +Snd_Memset + +https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371 + +<TTimo> some shitty mess with DMA buffers +<TTimo> the mmap'ing permissions were write only +<TTimo> and glibc optimized for mmx would do memcpy with a prefetch and a read +<TTimo> causing segfaults +<TTimo> some other systems would not let you mmap the DMA with read permissions +<TTimo> so I think I ended up attempting opening with read/write, then try write only +<TTimo> and use my own copy instead of the glibc crap +=============== +*/ void Snd_Memset (void* dest, const int val, const size_t count) { - int *pDest; - int i, iterate; - - if (!use_custom_memset) - { - Com_Memset(dest,val,count); - return; - } - iterate = count / sizeof(int); - pDest = (int*)dest; - for(i=0; i<iterate; i++) - { - pDest[i] = val; - } + int *pDest; + int i, iterate; + + if (!use_custom_memset) + { + Com_Memset(dest,val,count); + return; + } + iterate = count / sizeof(int); + pDest = (int*)dest; + for(i=0; i<iterate; i++) + { + pDest[i] = val; + } } /* The audio callback. All the magic happens here. */ static int dmapos = 0; static int dmasize = 0; + +/* +=============== +sdl_audio_callback +=============== +*/ static void sdl_audio_callback(void *userdata, Uint8 *stream, int len) { - int pos = (dmapos * (dma.samplebits/8)); - if (pos >= dmasize) - dmapos = pos = 0; - - if (!snd_inited) /* shouldn't happen, but just in case... */ - { - memset(stream, '\0', len); - return; - } - else - { - int tobufend = dmasize - pos; /* bytes to buffer's end. */ - int len1 = len; - int len2 = 0; - - if (len1 > tobufend) - { - len1 = tobufend; - len2 = len - len1; - } - memcpy(stream, dma.buffer + pos, len1); - if (len2 <= 0) - dmapos += (len1 / (dma.samplebits/8)); - else /* wraparound? */ - { - memcpy(stream+len1, dma.buffer, len2); - dmapos = (len2 / (dma.samplebits/8)); - } - } - - if (dmapos >= dmasize) - dmapos = 0; + int pos = (dmapos * (dma.samplebits/8)); + if (pos >= dmasize) + dmapos = pos = 0; + + if (!snd_inited) /* shouldn't happen, but just in case... */ + { + memset(stream, '\0', len); + return; + } + else + { + int tobufend = dmasize - pos; /* bytes to buffer's end. */ + int len1 = len; + int len2 = 0; + + if (len1 > tobufend) + { + len1 = tobufend; + len2 = len - len1; + } + memcpy(stream, dma.buffer + pos, len1); + if (len2 <= 0) + dmapos += (len1 / (dma.samplebits/8)); + else /* wraparound? */ + { + memcpy(stream+len1, dma.buffer, len2); + dmapos = (len2 / (dma.samplebits/8)); + } + } + + if (dmapos >= dmasize) + dmapos = 0; } +static struct +{ + Uint16 enumFormat; + char *stringFormat; +} formatToStringTable[ ] = +{ + { AUDIO_U8, "AUDIO_U8" }, + { AUDIO_S8, "AUDIO_S8" }, + { AUDIO_U16LSB, "AUDIO_U16LSB" }, + { AUDIO_S16LSB, "AUDIO_S16LSB" }, + { AUDIO_U16MSB, "AUDIO_U16MSB" }, + { AUDIO_S16MSB, "AUDIO_S16MSB" } +}; + +static int formatToStringTableSize = + sizeof( formatToStringTable ) / sizeof( formatToStringTable[ 0 ] ); + +/* +=============== +print_audiospec +=============== +*/ static void print_audiospec(const char *str, const SDL_AudioSpec *spec) { - Com_Printf("%s:\n", str); - - // I'm sorry this is nasty. - #define PRINT_AUDIO_FMT(x) \ - if (spec->format == x) Com_Printf("Format: %s\n", #x); else - PRINT_AUDIO_FMT(AUDIO_U8) - PRINT_AUDIO_FMT(AUDIO_S8) - PRINT_AUDIO_FMT(AUDIO_U16LSB) - PRINT_AUDIO_FMT(AUDIO_S16LSB) - PRINT_AUDIO_FMT(AUDIO_U16MSB) - PRINT_AUDIO_FMT(AUDIO_S16MSB) - Com_Printf("Format: UNKNOWN\n"); - #undef PRINT_AUDIO_FMT - - Com_Printf("Freq: %d\n", (int) spec->freq); - Com_Printf("Samples: %d\n", (int) spec->samples); - Com_Printf("Channels: %d\n", (int) spec->channels); - Com_Printf("\n"); + int i; + char *fmt = NULL; + + Com_Printf("%s:\n", str); + + for( i = 0; i < formatToStringTableSize; i++ ) { + if( spec->format == formatToStringTable[ i ].enumFormat ) { + fmt = formatToStringTable[ i ].stringFormat; + } + } + + if( fmt ) { + Com_Printf( " Format: %s\n", fmt ); + } else { + Com_Printf( " Format: " S_COLOR_RED "UNKNOWN\n", fmt ); + } + + Com_Printf( " Freq: %d\n", (int) spec->freq ); + Com_Printf( " Samples: %d\n", (int) spec->samples ); + Com_Printf( " Channels: %d\n", (int) spec->channels ); } +/* +=============== +SNDDMA_Init +=============== +*/ qboolean SNDDMA_Init(void) { - char drivername[128]; - SDL_AudioSpec desired; - SDL_AudioSpec obtained; + char drivername[128]; + SDL_AudioSpec desired; + SDL_AudioSpec obtained; int tmp; if (snd_inited) - return 1; + return qtrue; - Com_Printf("SDL Audio driver initializing...\n"); + Com_Printf("Initializing SDL audio driver...\n"); - if (!snddevice) { - sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE); - sndspeed = Cvar_Get("sndspeed", "0", CVAR_ARCHIVE); - sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE); - snddevice = Cvar_Get("snddevice", "/dev/dsp", CVAR_ARCHIVE); - sdldevsamps = Cvar_Get("sdldevsamps", "0", CVAR_ARCHIVE); - sdlmixsamps = Cvar_Get("sdlmixsamps", "0", CVAR_ARCHIVE); + if (!s_sdlBits) { + s_sdlBits = Cvar_Get("s_sdlBits", "16", CVAR_ARCHIVE); + s_sdlSpeed = Cvar_Get("s_sdlSpeed", "0", CVAR_ARCHIVE); + s_sdlChannels = Cvar_Get("s_sdlChannels", "2", CVAR_ARCHIVE); + s_sdlDevSamps = Cvar_Get("s_sdlDevSamps", "0", CVAR_ARCHIVE); + s_sdlMixSamps = Cvar_Get("s_sdlMixSamps", "0", CVAR_ARCHIVE); } - if (!SDL_WasInit(SDL_INIT_AUDIO)) - { - Com_Printf("Calling SDL_Init(SDL_INIT_AUDIO)...\n"); - if (SDL_Init(SDL_INIT_AUDIO) == -1) - { - Com_Printf("SDL_Init(SDL_INIT_AUDIO) failed: %s\n", SDL_GetError()); - return qfalse; - } - Com_Printf("SDL_Init(SDL_INIT_AUDIO) passed.\n"); - } - - if (SDL_AudioDriverName(drivername, sizeof (drivername)) == NULL) - strcpy(drivername, "(UNKNOWN)"); - Com_Printf("SDL audio driver is \"%s\"\n", drivername); - - memset(&desired, '\0', sizeof (desired)); - memset(&obtained, '\0', sizeof (obtained)); - - tmp = ((int) sndbits->value); - if ((tmp != 16) && (tmp != 8)) - tmp = 16; - - desired.freq = (int) sndspeed->value; - if(!desired.freq) desired.freq = 22050; - desired.format = ((tmp == 16) ? AUDIO_S16SYS : AUDIO_U8); - - // I dunno if this is the best idea, but I'll give it a try... - // should probably check a cvar for this... - if (sdldevsamps->value) - desired.samples = sdldevsamps->value; - else - { - // just pick a sane default. - 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.channels = (int) sndchannels->value; - desired.callback = sdl_audio_callback; - - print_audiospec("Format we requested from SDL audio device", &desired); - - if (SDL_OpenAudio(&desired, &obtained) == -1) - { - Com_Printf("SDL_OpenAudio() failed: %s\n", SDL_GetError()); - SDL_QuitSubSystem(SDL_INIT_AUDIO); - return qfalse; - } // if - - print_audiospec("Format we actually got", &obtained); - - // dma.samples needs to be big, or id's mixer will just refuse to - // work at all; we need to keep it significantly bigger than the - // amount of SDL callback samples, and just copy a little each time - // the callback runs. - // 32768 is what the OSS driver filled in here on my system. I don't - // know if it's a good value overall, but at least we know it's - // reasonable...this is why I let the user override. - tmp = sdlmixsamps->value; - if (!tmp) - tmp = (obtained.samples * obtained.channels) * 10; - - if (tmp & (tmp - 1)) // not a power of two? Seems to confuse something. - { - int val = 1; - while (val < tmp) - val <<= 1; - - Com_Printf("WARNING: sdlmixsamps wasn't a power of two (%d)," - " so we made it one (%d).\n", tmp, val); - tmp = val; - } - - dmapos = 0; + if (!SDL_WasInit(SDL_INIT_AUDIO)) + { + if (SDL_Init(SDL_INIT_AUDIO) == -1) + { + Com_Printf("SDL_Init(SDL_INIT_AUDIO) failed: %s\n", SDL_GetError()); + return qfalse; + } + } + + if (SDL_AudioDriverName(drivername, sizeof (drivername)) == NULL) + strcpy(drivername, "(UNKNOWN)"); + Com_Printf("SDL audio driver is \"%s\".\n", drivername); + + memset(&desired, '\0', sizeof (desired)); + memset(&obtained, '\0', sizeof (obtained)); + + tmp = ((int) s_sdlBits->value); + if ((tmp != 16) && (tmp != 8)) + tmp = 16; + + desired.freq = (int) s_sdlSpeed->value; + if(!desired.freq) desired.freq = 22050; + desired.format = ((tmp == 16) ? AUDIO_S16SYS : AUDIO_U8); + + // I dunno if this is the best idea, but I'll give it a try... + // should probably check a cvar for this... + if (s_sdlDevSamps->value) + desired.samples = s_sdlDevSamps->value; + else + { + // just pick a sane default. + 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.channels = (int) s_sdlChannels->value; + desired.callback = sdl_audio_callback; + + if (SDL_OpenAudio(&desired, &obtained) == -1) + { + Com_Printf("SDL_OpenAudio() failed: %s\n", SDL_GetError()); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + return qfalse; + } // if + + print_audiospec("SDL_AudioSpec", &obtained); + + // dma.samples needs to be big, or id's mixer will just refuse to + // work at all; we need to keep it significantly bigger than the + // amount of SDL callback samples, and just copy a little each time + // the callback runs. + // 32768 is what the OSS driver filled in here on my system. I don't + // know if it's a good value overall, but at least we know it's + // reasonable...this is why I let the user override. + tmp = s_sdlMixSamps->value; + if (!tmp) + tmp = (obtained.samples * obtained.channels) * 10; + + if (tmp & (tmp - 1)) // not a power of two? Seems to confuse something. + { + int val = 1; + while (val < tmp) + val <<= 1; + + tmp = val; + } + + dmapos = 0; dma.samplebits = obtained.format & 0xFF; // first byte of format is bits. - dma.channels = obtained.channels; - dma.samples = tmp; + dma.channels = obtained.channels; + dma.samples = tmp; dma.submission_chunk = 1; dma.speed = obtained.freq; - dmasize = (dma.samples * (dma.samplebits/8)); + dmasize = (dma.samples * (dma.samplebits/8)); dma.buffer = calloc(1, dmasize); - Com_Printf("Starting SDL audio callback...\n"); - SDL_PauseAudio(0); // start callback. + Com_Printf("Starting SDL audio callback...\n"); + SDL_PauseAudio(0); // start callback. - Com_Printf("SDL audio initialized.\n"); - snd_inited = 1; + Com_Printf("SDL audio initialized.\n"); + snd_inited = qtrue; return qtrue; } +/* +=============== +SNDDMA_GetDMAPos +=============== +*/ int SNDDMA_GetDMAPos(void) { - return dmapos; + return dmapos; } +/* +=============== +SNDDMA_Shutdown +=============== +*/ void SNDDMA_Shutdown(void) { - Com_Printf("Closing SDL audio device...\n"); - SDL_PauseAudio(1); - SDL_CloseAudio(); - SDL_QuitSubSystem(SDL_INIT_AUDIO); - free(dma.buffer); - dma.buffer = NULL; - dmapos = dmasize = 0; - snd_inited = 0; - Com_Printf("SDL audio device shut down.\n"); + Com_Printf("Closing SDL audio device...\n"); + SDL_PauseAudio(1); + SDL_CloseAudio(); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + free(dma.buffer); + dma.buffer = NULL; + dmapos = dmasize = 0; + snd_inited = qfalse; + Com_Printf("SDL audio device shut down.\n"); } /* -============== +=============== SNDDMA_Submit Send sound to device if buffer isn't really the dma buffer @@ -290,15 +342,17 @@ Send sound to device if buffer isn't really the dma buffer */ void SNDDMA_Submit(void) { - SDL_UnlockAudio(); + SDL_UnlockAudio(); } +/* +=============== +SNDDMA_BeginPainting +=============== +*/ void SNDDMA_BeginPainting (void) { - SDL_LockAudio(); + SDL_LockAudio(); } #endif // USE_SDL_SOUND - -// end of linux_snd_sdl.c ... - |