From c30600aa22ad57f8f7dc48f7cb467bcaa66ed35b Mon Sep 17 00:00:00 2001 From: molivier Date: Wed, 7 Sep 2005 09:58:15 +0000 Subject: [PATCH] Added CoreAudio (Mac OS X) sound driver. Changed / fixed a couple of Mac OS X related lines in the makefiles. The sound format is now printed at sound module startup. git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@5691 d7cf8633-e32d-0410-b094-e92efae38249 --- makefile | 2 +- makefile.inc | 11 +- snd_coreaudio.c | 287 ++++++++++++++++++++++++++++++++++++++++++++++++ snd_main.c | 3 +- 4 files changed, 296 insertions(+), 7 deletions(-) create mode 100644 snd_coreaudio.c diff --git a/makefile b/makefile index 63ba438b..e5d8ce82 100644 --- a/makefile +++ b/makefile @@ -75,7 +75,7 @@ ifeq ($(DP_MAKE_TARGET), macosx) LDFLAGS_SV=$(LDFLAGS_MACOSXSV) LDFLAGS_SDL=$(LDFLAGS_MACOSXSDL) - EXE_CL=$(EXE_UNIXCL) + EXE_CL=$(EXE_MACOSXCL) EXE_SV=$(EXE_UNIXSV) EXE_SDL=$(EXE_UNIXSDL) endif diff --git a/makefile.inc b/makefile.inc index 07d73b30..f5242a69 100644 --- a/makefile.inc +++ b/makefile.inc @@ -35,7 +35,7 @@ LIB_SND_ALSA=-lasound # Core Audio (Mac OS X) OBJ_SND_COREAUDIO=$(OBJ_SND_COMMON) snd_coreaudio.c -LIB_SND_COREAUDIO= +LIB_SND_COREAUDIO=-framework CoreAudio # BSD / Sun audio API (NetBSD and OpenBSD) OBJ_SND_BSD=$(OBJ_SND_COMMON) snd_bsd.o @@ -187,18 +187,19 @@ LDFLAGS_LINUXSDL=$(LDFLAGS_UNIXCOMMON) -ldl $(LDFLAGS_UNIXSDL) ##### Mac OS X specific variables ##### -# If you want CD sound in Mac OS X -#OBJ_MACOSXCD=cd_macosx.o -# If you want no CD audio +# No CD support available OBJ_MACOSXCD=$(OBJ_NOCD) # Link -LDFLAGS_MACOSXCL=$(LDFLAGS_UNIXCOMMON) -ldl $(LDFLAGS_UNIXCL) +LDFLAGS_MACOSXCL=$(LDFLAGS_UNIXCOMMON) -ldl -framework Carbon $(LIB_SOUND) LDFLAGS_MACOSXSV=$(LDFLAGS_UNIXCOMMON) -ldl LDFLAGS_MACOSXSDL=$(LDFLAGS_UNIXCOMMON) -ldl `sdl-config --static-libs` OBJ_AGL= builddate.c sys_linux.o vid_agl.o $(OBJ_SOUND) $(OBJ_CD) $(OBJ_COMMON) +EXE_MACOSXCL=darkplaces-agl + + ##### SunOS specific variables ##### # No CD support available diff --git a/snd_coreaudio.c b/snd_coreaudio.c new file mode 100644 index 00000000..899ccf6d --- /dev/null +++ b/snd_coreaudio.c @@ -0,0 +1,287 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// snd_coreaudio.c +// all other sound mixing is portable + +#include + +#include + +#include "quakedef.h" +#include "snd_main.h" + +// BUFFER_SIZE must be an even multiple of CHUNK_SIZE +#define CHUNK_SIZE 2048 +#define BUFFER_SIZE 16384 + +static unsigned int submissionChunk; +static unsigned int maxMixedSamples; +static short *s_mixedSamples; +static int s_chunkCount; // number of chunks submitted +static qboolean s_isRunning; + +static AudioDeviceID outputDeviceID; +static AudioStreamBasicDescription outputStreamBasicDescription; + +extern mempool_t *snd_mempool; + + +/* +=============== +audioDeviceIOProc +=============== +*/ + +OSStatus audioDeviceIOProc(AudioDeviceID inDevice, + const AudioTimeStamp *inNow, + const AudioBufferList *inInputData, + const AudioTimeStamp *inInputTime, + AudioBufferList *outOutputData, + const AudioTimeStamp *inOutputTime, + void *inClientData) +{ + int offset; + short *samples; + unsigned int sampleIndex; + float *outBuffer; + float scale; + + offset = (s_chunkCount * submissionChunk) % maxMixedSamples; + samples = s_mixedSamples + offset; + + outBuffer = (float *)outOutputData->mBuffers[0].mData; + + // If we have run out of samples, return silence + if (s_chunkCount * submissionChunk > shm->format.channels * paintedtime) + { + memset(outBuffer, 0, sizeof(*outBuffer) * submissionChunk); + } + else + { + // Convert the samples from shorts to floats. Scale the floats to be [-1..1]. + scale = (1.0f / SHRT_MAX); + for (sampleIndex = 0; sampleIndex < submissionChunk; sampleIndex++) + outBuffer[sampleIndex] = samples[sampleIndex] * scale; + + s_chunkCount++; // this is the next buffer we will submit + } + + return 0; +} + +/* +=============== +SNDDMA_Init +=============== +*/ +qboolean SNDDMA_Init(void) +{ + OSStatus status; + UInt32 propertySize, bufferByteCount; + + if (s_isRunning) + return true; + + Con_Printf("Initializing CoreAudio...\n"); + + // Get the output device + propertySize = sizeof(outputDeviceID); + status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propertySize, &outputDeviceID); + if (status) + { + Con_Printf("AudioHardwareGetProperty returned %d\n", status); + return false; + } + + if (outputDeviceID == kAudioDeviceUnknown) + { + Con_Printf("AudioHardwareGetProperty: outputDeviceID is kAudioDeviceUnknown\n"); + return false; + } + + // Configure the output device + // TODO: support "-sndspeed", "-sndmono" and "-sndstereo" + propertySize = sizeof(bufferByteCount); + bufferByteCount = CHUNK_SIZE * sizeof(float); + status = AudioDeviceSetProperty(outputDeviceID, NULL, 0, false, kAudioDevicePropertyBufferSize, propertySize, &bufferByteCount); + if (status) + { + Con_Printf("AudioDeviceSetProperty: returned %d when setting kAudioDevicePropertyBufferSize to %d\n", status, CHUNK_SIZE); + return false; + } + + propertySize = sizeof(bufferByteCount); + status = AudioDeviceGetProperty(outputDeviceID, 0, false, kAudioDevicePropertyBufferSize, &propertySize, &bufferByteCount); + if (status) + { + Con_Printf("AudioDeviceGetProperty: returned %d when setting kAudioDevicePropertyBufferSize\n", status); + return false; + } + submissionChunk = bufferByteCount / sizeof(float); + Con_DPrintf(" Chunk size = %d samples\n", submissionChunk); + + // Print out the device status + propertySize = sizeof(outputStreamBasicDescription); + status = AudioDeviceGetProperty(outputDeviceID, 0, false, kAudioDevicePropertyStreamFormat, &propertySize, &outputStreamBasicDescription); + if (status) + { + Con_Printf("AudioDeviceGetProperty: returned %d when getting kAudioDevicePropertyStreamFormat\n", status); + return false; + } + Con_DPrintf(" Hardware format:\n"); + Con_DPrintf(" %5d mSampleRate\n", (unsigned int)outputStreamBasicDescription.mSampleRate); + Con_DPrintf(" %c%c%c%c mFormatID\n", + (outputStreamBasicDescription.mFormatID & 0xff000000) >> 24, + (outputStreamBasicDescription.mFormatID & 0x00ff0000) >> 16, + (outputStreamBasicDescription.mFormatID & 0x0000ff00) >> 8, + (outputStreamBasicDescription.mFormatID & 0x000000ff) >> 0); + Con_DPrintf(" %5d mBytesPerPacket\n", outputStreamBasicDescription.mBytesPerPacket); + Con_DPrintf(" %5d mFramesPerPacket\n", outputStreamBasicDescription.mFramesPerPacket); + Con_DPrintf(" %5d mBytesPerFrame\n", outputStreamBasicDescription.mBytesPerFrame); + Con_DPrintf(" %5d mChannelsPerFrame\n", outputStreamBasicDescription.mChannelsPerFrame); + Con_DPrintf(" %5d mBitsPerChannel\n", outputStreamBasicDescription.mBitsPerChannel); + + if(outputStreamBasicDescription.mFormatID != kAudioFormatLinearPCM) + { + Con_Printf("Default Audio Device doesn't support Linear PCM!\n"); + return false; + } + + // Start sound running + status = AudioDeviceAddIOProc(outputDeviceID, audioDeviceIOProc, NULL); + if (status) + { + Con_Printf("AudioDeviceAddIOProc: returned %d\n", status); + return false; + } + + maxMixedSamples = BUFFER_SIZE; + s_mixedSamples = Mem_Alloc (snd_mempool, sizeof(*s_mixedSamples) * maxMixedSamples); + Con_DPrintf(" Buffer size = %d samples (%d chunks)\n", + maxMixedSamples, (maxMixedSamples / submissionChunk)); + + // Tell the main app what we expect from it + memset ((void*)shm, 0, sizeof (*shm)); + shm->format.speed = outputStreamBasicDescription.mSampleRate; + shm->format.channels = outputStreamBasicDescription.mChannelsPerFrame; + shm->format.width = 2; + shm->samples = maxMixedSamples; + shm->buffer = (qbyte *)s_mixedSamples; + shm->samplepos = 0; + + // We haven't enqueued anything yet + s_chunkCount = 0; + + status = AudioDeviceStart(outputDeviceID, audioDeviceIOProc); + if (status) + { + Con_Printf("AudioDeviceStart: returned %d\n", status); + return false; + } + + s_isRunning = true; + + Con_Printf(" Initialization successful\n"); + + return true; +} + +/* +=============== +SNDDMA_GetDMAPos + +return the current sample position (in mono samples read) +inside the recirculating dma buffer, so the mixing code will know +how many sample are required to fill it up. +=============== +*/ +int SNDDMA_GetDMAPos(void) +{ + return (s_chunkCount * submissionChunk) % shm->samples; +} + +/* +=============== +SNDDMA_Shutdown + +Reset the sound device for exiting +=============== +*/ +void SNDDMA_Shutdown(void) +{ + OSStatus status; + + if (!s_isRunning) + return; + + status = AudioDeviceStop(outputDeviceID, audioDeviceIOProc); + if (status) + { + Con_Printf("AudioDeviceStop: returned %d\n", status); + return; + } + + s_isRunning = false; + + status = AudioDeviceRemoveIOProc(outputDeviceID, audioDeviceIOProc); + if (status) + { + Con_Printf("AudioDeviceRemoveIOProc: returned %d\n", status); + return; + } + + Mem_Free(s_mixedSamples); + s_mixedSamples = NULL; + shm->samples = NULL; +} + +/* +=============== +SNDDMA_Submit +=============== +*/ +void SNDDMA_Submit(void) +{ + // nothing to do (CoreAudio is callback-based) +} + +/* +=============== +S_LockBuffer +=============== +*/ +void *S_LockBuffer(void) +{ + // not necessary (just return the buffer) + return shm->buffer; +} + +/* +=============== +S_UnlockBuffer +=============== +*/ +void S_UnlockBuffer(void) +{ + // not necessary +} diff --git a/snd_main.c b/snd_main.c index fe590b12..bf0bc3da 100644 --- a/snd_main.c +++ b/snd_main.c @@ -140,7 +140,8 @@ void S_Startup(void) sound_started = true; - Con_DPrintf("Sound sampling rate: %i\n", shm->format.speed); + Con_Printf("Sound format: %dHz, %d bit, %d channels\n", shm->format.speed, + shm->format.width * 8, shm->format.channels); } void S_Shutdown(void) -- 2.39.2