Audio improvements from Max Horn, including a new CoreAudio driver for MacOSX
--HG-- extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%40936
This commit is contained in:
parent
fddd0153c8
commit
35c8da7adb
12 changed files with 436 additions and 135 deletions
|
@ -15,6 +15,7 @@ DIST_SUBDIRS = \
|
|||
dmedia \
|
||||
dsp \
|
||||
esd \
|
||||
macosx \
|
||||
macrom \
|
||||
mint \
|
||||
mme \
|
||||
|
|
|
@ -77,6 +77,9 @@ static AudioBootStrap *bootstrap[] = {
|
|||
#ifdef __BEOS__
|
||||
&BAUDIO_bootstrap,
|
||||
#endif
|
||||
#ifdef COREAUDIO_SUPPORT
|
||||
&COREAUDIO_bootstrap,
|
||||
#endif
|
||||
#if defined(macintosh) || TARGET_API_MAC_CARBON
|
||||
&SNDMGR_bootstrap,
|
||||
#endif
|
||||
|
|
|
@ -144,6 +144,9 @@ extern AudioBootStrap Paud_bootstrap;
|
|||
#ifdef __BEOS__
|
||||
extern AudioBootStrap BAUDIO_bootstrap;
|
||||
#endif
|
||||
#ifdef COREAUDIO_SUPPORT
|
||||
extern AudioBootStrap COREAUDIO_bootstrap;
|
||||
#endif
|
||||
#if defined(macintosh) || TARGET_API_MAC_CARBON
|
||||
extern AudioBootStrap SNDMGR_bootstrap;
|
||||
#endif
|
||||
|
|
6
src/audio/macosx/.cvsignore
Normal file
6
src/audio/macosx/.cvsignore
Normal file
|
@ -0,0 +1,6 @@
|
|||
Makefile.in
|
||||
Makefile
|
||||
.libs
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
9
src/audio/macosx/Makefile.am
Normal file
9
src/audio/macosx/Makefile.am
Normal file
|
@ -0,0 +1,9 @@
|
|||
|
||||
## Makefile.am for SDL using the Mac OS X CoreAudio driver
|
||||
|
||||
noinst_LTLIBRARIES = libaudio_macosx.la
|
||||
libaudio_macosx_la_SOURCES = $(SRCS)
|
||||
|
||||
# The SDL audio driver sources
|
||||
SRCS = SDL_coreaudio.c \
|
||||
SDL_coreaudio.h
|
287
src/audio/macosx/SDL_coreaudio.c
Normal file
287
src/audio/macosx/SDL_coreaudio.c
Normal file
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2004 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
*/
|
||||
|
||||
#ifdef SAVE_RCSID
|
||||
static char rcsid =
|
||||
"@(#) $Id$";
|
||||
#endif
|
||||
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "SDL_endian.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "SDL_audio_c.h"
|
||||
#include "SDL_audiomem.h"
|
||||
#include "SDL_sysaudio.h"
|
||||
#include "SDL_coreaudio.h"
|
||||
|
||||
|
||||
/* Audio driver functions */
|
||||
|
||||
static int Core_OpenAudio(_THIS, SDL_AudioSpec *spec);
|
||||
static void Core_WaitAudio(_THIS);
|
||||
static void Core_PlayAudio(_THIS);
|
||||
static Uint8 *Core_GetAudioBuf(_THIS);
|
||||
static void Core_CloseAudio(_THIS);
|
||||
|
||||
/* Audio driver bootstrap functions */
|
||||
|
||||
static int Audio_Available(void)
|
||||
{
|
||||
return(1);
|
||||
}
|
||||
|
||||
static void Audio_DeleteDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
free(device->hidden);
|
||||
free(device);
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
|
||||
{
|
||||
SDL_AudioDevice *this;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
|
||||
if ( this ) {
|
||||
memset(this, 0, (sizeof *this));
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
malloc((sizeof *this->hidden));
|
||||
}
|
||||
if ( (this == NULL) || (this->hidden == NULL) ) {
|
||||
SDL_OutOfMemory();
|
||||
if ( this ) {
|
||||
free(this);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
memset(this->hidden, 0, (sizeof *this->hidden));
|
||||
|
||||
/* Set the function pointers */
|
||||
this->OpenAudio = Core_OpenAudio;
|
||||
this->WaitAudio = Core_WaitAudio;
|
||||
this->PlayAudio = Core_PlayAudio;
|
||||
this->GetAudioBuf = Core_GetAudioBuf;
|
||||
this->CloseAudio = Core_CloseAudio;
|
||||
|
||||
this->free = Audio_DeleteDevice;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
AudioBootStrap COREAUDIO_bootstrap = {
|
||||
"coreaudio", "Mac OS X CoreAudio",
|
||||
Audio_Available, Audio_CreateDevice
|
||||
};
|
||||
|
||||
/* The CoreAudio callback */
|
||||
static OSStatus audioCallback (void *inRefCon,
|
||||
AudioUnitRenderActionFlags inActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
AudioBuffer *ioData)
|
||||
{
|
||||
SDL_AudioDevice *this = (SDL_AudioDevice *)inRefCon;
|
||||
UInt32 remaining, len;
|
||||
void *ptr;
|
||||
|
||||
/* Only do anything if audio is enabled and not paused */
|
||||
if ( ! this->enabled || this->paused ) {
|
||||
memset(ioData->mData, this->spec.silence, ioData->mDataByteSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No SDL conversion should be needed here, ever, since we accept
|
||||
any input format in OpenAudio, and leave the conversion to CoreAudio.
|
||||
*/
|
||||
assert(!this->convert.needed);
|
||||
assert(this->spec.channels == ioData->mNumberChannels);
|
||||
|
||||
remaining = ioData->mDataByteSize;
|
||||
ptr = ioData->mData;
|
||||
while (remaining > 0) {
|
||||
if (bufferOffset >= bufferSize) {
|
||||
/* Generate the data */
|
||||
memset(buffer, this->spec.silence, bufferSize);
|
||||
SDL_mutexP(this->mixer_lock);
|
||||
(*this->spec.callback)(this->spec.userdata,
|
||||
buffer, bufferSize);
|
||||
SDL_mutexV(this->mixer_lock);
|
||||
bufferOffset = 0;
|
||||
}
|
||||
|
||||
len = bufferSize - bufferOffset;
|
||||
if (len > remaining)
|
||||
len = remaining;
|
||||
memcpy(ptr, buffer + bufferOffset, len);
|
||||
ptr += len;
|
||||
remaining -= len;
|
||||
bufferOffset += len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Dummy functions -- we don't use thread-based audio */
|
||||
void Core_WaitAudio(_THIS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void Core_PlayAudio(_THIS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Uint8 *Core_GetAudioBuf(_THIS)
|
||||
{
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
void Core_CloseAudio(_THIS)
|
||||
{
|
||||
OSStatus result;
|
||||
AudioUnitInputCallback callback;
|
||||
|
||||
/* stop processing the audio unit */
|
||||
result = AudioOutputUnitStop (outputAudioUnit);
|
||||
if (result != noErr) {
|
||||
SDL_SetError("Core_CloseAudio: AudioOutputUnitStop");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Remove the input callback */
|
||||
callback.inputProc = 0;
|
||||
callback.inputProcRefCon = 0;
|
||||
result = AudioUnitSetProperty (outputAudioUnit,
|
||||
kAudioUnitProperty_SetInputCallback,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&callback,
|
||||
sizeof(callback));
|
||||
if (result != noErr) {
|
||||
SDL_SetError("Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)");
|
||||
return;
|
||||
}
|
||||
|
||||
result = CloseComponent(outputAudioUnit);
|
||||
if (result != noErr) {
|
||||
SDL_SetError("Core_CloseAudio: CloseComponent");
|
||||
return;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
#define CHECK_RESULT(msg) \
|
||||
if (result != noErr) { \
|
||||
SDL_SetError("Failed to start CoreAudio: " msg); \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
|
||||
int Core_OpenAudio(_THIS, SDL_AudioSpec *spec)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
Component comp;
|
||||
ComponentDescription desc;
|
||||
AudioUnitInputCallback callback;
|
||||
AudioStreamBasicDescription requestedDesc;
|
||||
|
||||
/* Setup a AudioStreamBasicDescription with the requested format */
|
||||
requestedDesc.mFormatID = kAudioFormatLinearPCM;
|
||||
requestedDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
|
||||
requestedDesc.mChannelsPerFrame = spec->channels;
|
||||
requestedDesc.mSampleRate = spec->freq;
|
||||
|
||||
requestedDesc.mBitsPerChannel = spec->format & 0xFF;
|
||||
if (spec->format & 0x8000)
|
||||
requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
|
||||
if (spec->format & 0x1000)
|
||||
requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
|
||||
|
||||
requestedDesc.mFramesPerPacket = 1;
|
||||
requestedDesc.mBytesPerFrame = requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8;
|
||||
requestedDesc.mBytesPerPacket = requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket;
|
||||
|
||||
|
||||
/* Locate the default output audio unit */
|
||||
desc.componentType = kAudioUnitComponentType;
|
||||
desc.componentSubType = kAudioUnitSubType_Output;
|
||||
desc.componentManufacturer = kAudioUnitID_DefaultOutput;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
|
||||
comp = FindNextComponent (NULL, &desc);
|
||||
if (comp == NULL) {
|
||||
SDL_SetError ("Failed to start CoreAudio: FindNextComponent returned NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Open & initialize the default output audio unit */
|
||||
result = OpenAComponent (comp, &outputAudioUnit);
|
||||
CHECK_RESULT("OpenAComponent")
|
||||
|
||||
result = AudioUnitInitialize (outputAudioUnit);
|
||||
CHECK_RESULT("AudioUnitInitialize")
|
||||
|
||||
/* Set the input format of the audio unit. */
|
||||
result = AudioUnitSetProperty (outputAudioUnit,
|
||||
kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&requestedDesc,
|
||||
sizeof (requestedDesc));
|
||||
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)")
|
||||
|
||||
/* Set the audio callback */
|
||||
callback.inputProc = audioCallback;
|
||||
callback.inputProcRefCon = this;
|
||||
result = AudioUnitSetProperty (outputAudioUnit,
|
||||
kAudioUnitProperty_SetInputCallback,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&callback,
|
||||
sizeof(callback));
|
||||
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)")
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
SDL_CalculateAudioSpec(spec);
|
||||
|
||||
/* Allocate a sample buffer */
|
||||
bufferOffset = bufferSize = this->spec.size;
|
||||
buffer = malloc(bufferSize);
|
||||
assert(buffer);
|
||||
|
||||
/* Finally, start processing of the audio unit */
|
||||
result = AudioOutputUnitStart (outputAudioUnit);
|
||||
CHECK_RESULT("AudioOutputUnitStart")
|
||||
|
||||
|
||||
/* We're running! */
|
||||
return(1);
|
||||
}
|
49
src/audio/macosx/SDL_coreaudio.h
Normal file
49
src/audio/macosx/SDL_coreaudio.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2004 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
*/
|
||||
|
||||
#ifdef SAVE_RCSID
|
||||
static char rcsid =
|
||||
"@(#) $Id$";
|
||||
#endif
|
||||
|
||||
#ifndef _SDL_coreaudio_h
|
||||
#define _SDL_coreaudio_h
|
||||
|
||||
#include "SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the video functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData {
|
||||
AudioUnit outputAudioUnit;
|
||||
void *buffer;
|
||||
UInt32 bufferOffset;
|
||||
UInt32 bufferSize;
|
||||
};
|
||||
|
||||
/* Old variable names */
|
||||
#define outputAudioUnit (this->hidden->outputAudioUnit)
|
||||
#define buffer (this->hidden->buffer)
|
||||
#define bufferOffset (this->hidden->bufferOffset)
|
||||
#define bufferSize (this->hidden->bufferSize)
|
||||
|
||||
#endif /* _SDL_coreaudio_h */
|
Loading…
Add table
Add a link
Reference in a new issue