]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
Added CoreAudio (Mac OS X) sound driver. Changed / fixed a couple of Mac OS X related...
authormolivier <molivier@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 7 Sep 2005 09:58:15 +0000 (09:58 +0000)
committermolivier <molivier@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 7 Sep 2005 09:58:15 +0000 (09:58 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@5691 d7cf8633-e32d-0410-b094-e92efae38249

makefile
makefile.inc
snd_coreaudio.c [new file with mode: 0644]
snd_main.c

index 63ba438be4c25c1ede4d654cea1dc189273b736d..e5d8ce82880041865c1647660de2fddf3dc12de9 100644 (file)
--- 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
index 07d73b308d34eb0991f66dcbca2a29d04c7b23ea..f5242a696fa7e7fcec634a570f563a6354399a60 100644 (file)
@@ -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 (file)
index 0000000..899ccf6
--- /dev/null
@@ -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 <limits.h>
+
+#include <CoreAudio/AudioHardware.h>
+
+#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
+}
index fe590b1234d7e63ea81a5ef93f25854b653efc21..bf0bc3da90a063ff2da969c224f1535701ceb78b 100644 (file)
@@ -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)