aboutsummaryrefslogtreecommitdiffstats
path: root/code/macosx/macosx_sndcore.m
diff options
context:
space:
mode:
Diffstat (limited to 'code/macosx/macosx_sndcore.m')
-rwxr-xr-xcode/macosx/macosx_sndcore.m325
1 files changed, 325 insertions, 0 deletions
diff --git a/code/macosx/macosx_sndcore.m b/code/macosx/macosx_sndcore.m
new file mode 100755
index 0000000..a37ab0e
--- /dev/null
+++ b/code/macosx/macosx_sndcore.m
@@ -0,0 +1,325 @@
+/*
+===========================================================================
+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
+===========================================================================
+*/
+
+// mac_snddma.c
+// all other sound mixing is portable
+
+#include "../client/snd_local.h"
+
+#include <CoreServices/CoreServices.h>
+#include <CoreAudio/AudioHardware.h>
+#include <QuickTime/QuickTime.h>
+
+// For 'ri'
+#include "../renderer/tr_local.h"
+
+#import <Foundation/NSData.h>
+#import <Foundation/NSString.h>
+
+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;
+
+/*
+===============
+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, temp;
+
+ offset = ( s_chunkCount * submissionChunk ) % maxMixedSamples;
+ samples = s_mixedSamples + offset;
+
+ assert(outOutputData->mNumberBuffers == 1);
+ assert(outOutputData->mBuffers[0].mNumberChannels == 2);
+ //assert(outOutputData->mBuffers[0].mDataByteSize == (dma.submission_chunk * sizeof(float)));
+
+ outBuffer = (float *)outOutputData->mBuffers[0].mData;
+
+ // If we have run out of samples, return silence
+ if (s_chunkCount * submissionChunk > dma.channels * s_paintedtime) {
+ memset(outBuffer, 0, sizeof(*outBuffer) * dma.submission_chunk);
+ } else {
+ scale = (1.0f / SHRT_MAX);
+ if (outputStreamBasicDescription.mSampleRate == 44100 && dma.speed == 22050) {
+ for (sampleIndex = 0; sampleIndex < dma.submission_chunk; sampleIndex+=2) {
+ // Convert the samples from shorts to floats. Scale the floats to be [-1..1].
+ temp = samples[sampleIndex + 0] * scale;
+ outBuffer[(sampleIndex<<1)+0] = temp;
+ outBuffer[(sampleIndex<<1)+2] = temp;
+
+ temp = samples[sampleIndex + 1] * scale;
+ outBuffer[(sampleIndex<<1)+1] = temp;
+ outBuffer[(sampleIndex<<1)+3] = temp;
+ }
+ } else if (outputStreamBasicDescription.mSampleRate == 44100 && dma.speed == 11025) {
+ for (sampleIndex = 0; sampleIndex < dma.submission_chunk; sampleIndex+=4) {
+ // Convert the samples from shorts to floats. Scale the floats to be [-1..1].
+ temp = samples[sampleIndex + 0] * scale;
+ outBuffer[(sampleIndex<<1)+0] = temp;
+ outBuffer[(sampleIndex<<1)+2] = temp;
+ outBuffer[(sampleIndex<<1)+4] = temp;
+ outBuffer[(sampleIndex<<1)+6] = temp;
+
+ temp = samples[sampleIndex + 1] * scale;
+ outBuffer[(sampleIndex<<1)+1] = temp;
+ outBuffer[(sampleIndex<<1)+3] = temp;
+ outBuffer[(sampleIndex<<1)+5] = temp;
+ outBuffer[(sampleIndex<<1)+7] = temp;
+ }
+ } else {
+ for (sampleIndex = 0; sampleIndex < dma.submission_chunk; sampleIndex++) {
+ // Convert the samples from shorts to floats. Scale the floats to be [-1..1].
+ outBuffer[sampleIndex] = samples[sampleIndex] * scale;
+ }
+ }
+ }
+
+ s_chunkCount++; // this is the next buffer we will submit
+ return 0;
+}
+
+
+/*
+===============
+S_MakeTestPattern
+===============
+*/
+void S_MakeTestPattern( void ) {
+ int i;
+ float v;
+ int sample;
+
+ for ( i = 0 ; i < dma.samples / 2 ; i ++ ) {
+ v = sin( M_PI * 2 * i / 64 );
+ sample = v * 0x4000;
+ ((short *)dma.buffer)[i*2] = sample;
+ ((short *)dma.buffer)[i*2+1] = sample;
+ }
+}
+
+/*
+===============
+SNDDMA_Init
+===============
+*/
+qboolean SNDDMA_Init(void)
+{
+ cvar_t *bufferSize;
+ cvar_t *chunkSize;
+ OSStatus status;
+ UInt32 propertySize, bufferByteCount;
+
+ if (s_isRunning)
+ return qtrue;
+
+ chunkSize = ri.Cvar_Get( "s_chunksize", "2048", CVAR_ARCHIVE );
+ bufferSize = ri.Cvar_Get( "s_buffersize", "16384", CVAR_ARCHIVE );
+ Com_Printf(" Chunk size = %d\n", chunkSize->integer);
+ Com_Printf("Buffer size = %d\n", bufferSize->integer);
+
+ if (!chunkSize->integer)
+ ri.Error(ERR_FATAL, "s_chunksize must be non-zero\n");
+ if (!bufferSize->integer)
+ ri.Error(ERR_FATAL, "s_buffersize must be non-zero\n");
+ if (chunkSize->integer >= bufferSize->integer)
+ ri.Error(ERR_FATAL, "s_chunksize must be less than s_buffersize\n");
+ if (bufferSize->integer % chunkSize->integer)
+ ri.Error(ERR_FATAL, "s_buffersize must be an even multiple of s_chunksize\n");
+
+ // Get the output device
+ propertySize = sizeof(outputDeviceID);
+ status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propertySize, &outputDeviceID);
+ if (status) {
+ Com_Printf("AudioHardwareGetProperty returned %d\n", status);
+ return qfalse;
+ }
+
+ if (outputDeviceID == kAudioDeviceUnknown) {
+ Com_Printf("AudioHardwareGetProperty: outputDeviceID is kAudioDeviceUnknown\n");
+ return qfalse;
+ }
+
+ // Configure the output device
+ propertySize = sizeof(bufferByteCount);
+ bufferByteCount = chunkSize->integer * sizeof(float);
+ status = AudioDeviceSetProperty(outputDeviceID, NULL, 0, NO, kAudioDevicePropertyBufferSize, propertySize, &bufferByteCount);
+ if (status) {
+ Com_Printf("AudioDeviceSetProperty: returned %d when setting kAudioDevicePropertyBufferSize to %d\n", status, chunkSize->integer);
+ return qfalse;
+ }
+
+ propertySize = sizeof(bufferByteCount);
+ status = AudioDeviceGetProperty(outputDeviceID, 0, NO, kAudioDevicePropertyBufferSize, &propertySize, &bufferByteCount);
+ if (status) {
+ Com_Printf("AudioDeviceGetProperty: returned %d when setting kAudioDevicePropertyBufferSize\n", status);
+ return qfalse;
+ }
+
+ // Print out the device status
+ propertySize = sizeof(outputStreamBasicDescription);
+ status = AudioDeviceGetProperty(outputDeviceID, 0, NO, kAudioDevicePropertyStreamFormat, &propertySize, &outputStreamBasicDescription);
+ if (status) {
+ Com_Printf("AudioDeviceGetProperty: returned %d when getting kAudioDevicePropertyStreamFormat\n", status);
+ return qfalse;
+ }
+
+ Com_Printf("Hardware format:\n");
+ Com_Printf(" %f mSampleRate\n", outputStreamBasicDescription.mSampleRate);
+ Com_Printf(" %c%c%c%c mFormatID\n",
+ (outputStreamBasicDescription.mFormatID & 0xff000000) >> 24,
+ (outputStreamBasicDescription.mFormatID & 0x00ff0000) >> 16,
+ (outputStreamBasicDescription.mFormatID & 0x0000ff00) >> 8,
+ (outputStreamBasicDescription.mFormatID & 0x000000ff) >> 0);
+ Com_Printf(" %5d mBytesPerPacket\n", outputStreamBasicDescription.mBytesPerPacket);
+ Com_Printf(" %5d mFramesPerPacket\n", outputStreamBasicDescription.mFramesPerPacket);
+ Com_Printf(" %5d mBytesPerFrame\n", outputStreamBasicDescription.mBytesPerFrame);
+ Com_Printf(" %5d mChannelsPerFrame\n", outputStreamBasicDescription.mChannelsPerFrame);
+ Com_Printf(" %5d mBitsPerChannel\n", outputStreamBasicDescription.mBitsPerChannel);
+
+ if(outputStreamBasicDescription.mFormatID != kAudioFormatLinearPCM) {
+ Com_Printf("Default Audio Device doesn't support Linear PCM!");
+ return qfalse;
+ }
+
+ // Start sound running
+ status = AudioDeviceAddIOProc(outputDeviceID, audioDeviceIOProc, NULL);
+ if (status) {
+ Com_Printf("AudioDeviceAddIOProc: returned %d\n", status);
+ return qfalse;
+ }
+
+ submissionChunk = chunkSize->integer;
+ if (outputStreamBasicDescription.mSampleRate == 44100) {
+ submissionChunk = chunkSize->integer/2;
+ }
+ maxMixedSamples = bufferSize->integer;
+ s_mixedSamples = calloc(1, sizeof(*s_mixedSamples) * maxMixedSamples);
+ Com_Printf("Chunk Count = %d\n", (maxMixedSamples / submissionChunk));
+
+ // Tell the main app what we expect from it
+ dma.samples = maxMixedSamples;
+ dma.submission_chunk = submissionChunk;
+ dma.samplebits = 16;
+ dma.buffer = (byte *)s_mixedSamples;
+ dma.channels = outputStreamBasicDescription.mChannelsPerFrame;
+ dma.speed = 22050; //(unsigned long)outputStreamBasicDescription.mSampleRate;
+
+ // We haven't enqueued anything yet
+ s_chunkCount = 0;
+
+ status = AudioDeviceStart(outputDeviceID, audioDeviceIOProc);
+ if (status) {
+ Com_Printf("AudioDeviceStart: returned %d\n", status);
+ return qfalse;
+ }
+
+ s_isRunning = qtrue;
+
+ return qtrue;
+}
+
+/*
+===============
+SNDDMA_GetBufferDuration
+===============
+*/
+float SNDDMA_GetBufferDuration(void)
+{
+ return (float)dma.samples / (float)(dma.channels * dma.speed);
+}
+
+/*
+===============
+SNDDMA_GetDMAPos
+===============
+*/
+int SNDDMA_GetDMAPos(void)
+{
+ return s_chunkCount * dma.submission_chunk;
+}
+
+/*
+===============
+SNDDMA_Shutdown
+===============
+*/
+void SNDDMA_Shutdown(void)
+{
+ OSStatus status;
+
+ if (!s_isRunning)
+ return;
+
+ status = AudioDeviceStop(outputDeviceID, audioDeviceIOProc);
+ if (status) {
+ Com_Printf("AudioDeviceStop: returned %d\n", status);
+ return;
+ }
+
+ s_isRunning = qfalse;
+
+ status = AudioDeviceRemoveIOProc(outputDeviceID, audioDeviceIOProc);
+ if (status) {
+ Com_Printf("AudioDeviceRemoveIOProc: returned %d\n", status);
+ return;
+ }
+
+ free(s_mixedSamples);
+ s_mixedSamples = NULL;
+ dma.samples = NULL;
+}
+
+/*
+===============
+SNDDMA_BeginPainting
+===============
+*/
+void SNDDMA_BeginPainting(void) {
+}
+
+/*
+===============
+SNDDMA_Submit
+===============
+*/
+void SNDDMA_Submit(void) {
+}
+