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
32
configure.in
32
configure.in
|
@ -332,6 +332,7 @@ CheckDMEDIA()
|
||||||
],[
|
],[
|
||||||
have_dmedia=yes
|
have_dmedia=yes
|
||||||
])
|
])
|
||||||
|
AC_MSG_RESULT($have_dmedia)
|
||||||
# Set up files for the audio library
|
# Set up files for the audio library
|
||||||
if test x$have_dmedia = xyes; then
|
if test x$have_dmedia = xyes; then
|
||||||
CFLAGS="$CFLAGS -DDMEDIA_SUPPORT"
|
CFLAGS="$CFLAGS -DDMEDIA_SUPPORT"
|
||||||
|
@ -489,6 +490,29 @@ CheckAtariAudio()
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dnl Check whether we want to use CoreAudio
|
||||||
|
CheckCoreAudio()
|
||||||
|
{
|
||||||
|
if test x$enable_audio = xyes; then
|
||||||
|
AC_MSG_CHECKING(for CoreAudio audio support)
|
||||||
|
have_coreaudio=no
|
||||||
|
AC_TRY_COMPILE([
|
||||||
|
#include <AudioUnit/AudioUnit.h>
|
||||||
|
],[
|
||||||
|
AudioUnitInputCallback callback;
|
||||||
|
],[
|
||||||
|
have_coreaudio=yes
|
||||||
|
])
|
||||||
|
AC_MSG_RESULT($have_coreaudio)
|
||||||
|
# Set up files for the audio library
|
||||||
|
if test x$have_coreaudio = xyes; then
|
||||||
|
CFLAGS="$CFLAGS -DCOREAUDIO_SUPPORT"
|
||||||
|
AUDIO_SUBDIRS="$AUDIO_SUBDIRS macosx"
|
||||||
|
AUDIO_DRIVERS="$AUDIO_DRIVERS macosx/libaudio_macosx.la"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
dnl See if we can use x86 assembly blitters
|
dnl See if we can use x86 assembly blitters
|
||||||
# NASM is available from: http://nasm.octium.net/
|
# NASM is available from: http://nasm.octium.net/
|
||||||
CheckNASM()
|
CheckNASM()
|
||||||
|
@ -2507,10 +2531,15 @@ case "$target" in
|
||||||
ARCH=macosx
|
ARCH=macosx
|
||||||
CheckDummyVideo
|
CheckDummyVideo
|
||||||
CheckDiskAudio
|
CheckDiskAudio
|
||||||
|
CheckCoreAudio
|
||||||
CheckQUARTZ
|
CheckQUARTZ
|
||||||
CheckMacGL
|
CheckMacGL
|
||||||
CheckPTHREAD
|
CheckPTHREAD
|
||||||
CheckSIGACTION
|
CheckSIGACTION
|
||||||
|
# If either the audio or CD driver is used, add the AudioUnit framework
|
||||||
|
if test x$enable_audio = xyes -o x$enable_cdrom = xyes; then
|
||||||
|
SYSTEM_LIBS="$SYSTEM_LIBS -framework AudioToolbox -framework AudioUnit"
|
||||||
|
fi
|
||||||
# Set up files for the audio library
|
# Set up files for the audio library
|
||||||
if test x$enable_audio = xyes; then
|
if test x$enable_audio = xyes; then
|
||||||
AUDIO_SUBDIRS="$AUDIO_SUBDIRS macrom"
|
AUDIO_SUBDIRS="$AUDIO_SUBDIRS macrom"
|
||||||
|
@ -2526,7 +2555,7 @@ case "$target" in
|
||||||
if test x$enable_cdrom = xyes; then
|
if test x$enable_cdrom = xyes; then
|
||||||
CDROM_SUBDIRS="$CDROM_SUBDIRS macosx"
|
CDROM_SUBDIRS="$CDROM_SUBDIRS macosx"
|
||||||
CDROM_DRIVERS="$CDROM_DRIVERS macosx/libcdrom_macosx.la"
|
CDROM_DRIVERS="$CDROM_DRIVERS macosx/libcdrom_macosx.la"
|
||||||
SYSTEM_LIBS="$SYSTEM_LIBS -framework AudioToolbox -framework AudioUnit -lstdc++"
|
SYSTEM_LIBS="$SYSTEM_LIBS -lstdc++"
|
||||||
fi
|
fi
|
||||||
# Set up files for the thread library
|
# Set up files for the thread library
|
||||||
if test x$enable_threads = xyes; then
|
if test x$enable_threads = xyes; then
|
||||||
|
@ -2766,6 +2795,7 @@ src/audio/dma/Makefile
|
||||||
src/audio/dmedia/Makefile
|
src/audio/dmedia/Makefile
|
||||||
src/audio/dsp/Makefile
|
src/audio/dsp/Makefile
|
||||||
src/audio/esd/Makefile
|
src/audio/esd/Makefile
|
||||||
|
src/audio/macosx/Makefile
|
||||||
src/audio/macrom/Makefile
|
src/audio/macrom/Makefile
|
||||||
src/audio/mint/Makefile
|
src/audio/mint/Makefile
|
||||||
src/audio/mme/Makefile
|
src/audio/mme/Makefile
|
||||||
|
|
|
@ -15,6 +15,7 @@ DIST_SUBDIRS = \
|
||||||
dmedia \
|
dmedia \
|
||||||
dsp \
|
dsp \
|
||||||
esd \
|
esd \
|
||||||
|
macosx \
|
||||||
macrom \
|
macrom \
|
||||||
mint \
|
mint \
|
||||||
mme \
|
mme \
|
||||||
|
|
|
@ -77,6 +77,9 @@ static AudioBootStrap *bootstrap[] = {
|
||||||
#ifdef __BEOS__
|
#ifdef __BEOS__
|
||||||
&BAUDIO_bootstrap,
|
&BAUDIO_bootstrap,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef COREAUDIO_SUPPORT
|
||||||
|
&COREAUDIO_bootstrap,
|
||||||
|
#endif
|
||||||
#if defined(macintosh) || TARGET_API_MAC_CARBON
|
#if defined(macintosh) || TARGET_API_MAC_CARBON
|
||||||
&SNDMGR_bootstrap,
|
&SNDMGR_bootstrap,
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -144,6 +144,9 @@ extern AudioBootStrap Paud_bootstrap;
|
||||||
#ifdef __BEOS__
|
#ifdef __BEOS__
|
||||||
extern AudioBootStrap BAUDIO_bootstrap;
|
extern AudioBootStrap BAUDIO_bootstrap;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef COREAUDIO_SUPPORT
|
||||||
|
extern AudioBootStrap COREAUDIO_bootstrap;
|
||||||
|
#endif
|
||||||
#if defined(macintosh) || TARGET_API_MAC_CARBON
|
#if defined(macintosh) || TARGET_API_MAC_CARBON
|
||||||
extern AudioBootStrap SNDMGR_bootstrap;
|
extern AudioBootStrap SNDMGR_bootstrap;
|
||||||
#endif
|
#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 */
|
|
@ -67,28 +67,27 @@ OSStatus AudioFileManager::FileInputProc (void *inRefCo
|
||||||
|
|
||||||
OSStatus AudioFileManager::Render (AudioBuffer &ioData)
|
OSStatus AudioFileManager::Render (AudioBuffer &ioData)
|
||||||
{
|
{
|
||||||
OSStatus result = AudioConverterFillBuffer(mParentConverter,
|
OSStatus result = noErr;
|
||||||
AudioFileManager::ACInputProc,
|
|
||||||
this,
|
if (mBufferOffset >= mBufferSize) {
|
||||||
&ioData.mDataByteSize,
|
result = GetFileData(&mTmpBuffer, &mBufferSize);
|
||||||
ioData.mData);
|
if (result) {
|
||||||
if (result) {
|
SDL_SetError ("AudioConverterFillBuffer:%ld\n", result);
|
||||||
SDL_SetError ("AudioConverterFillBuffer:%ld\n", result);
|
mParent.DoNotification (result);
|
||||||
mParent.DoNotification (result);
|
return result;
|
||||||
} else {
|
}
|
||||||
mByteCounter += ioData.mDataByteSize / 2;
|
|
||||||
AfterRender();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
OSStatus AudioFileManager::ACInputProc (AudioConverterRef inAudioConverter,
|
mBufferOffset = 0;
|
||||||
UInt32* outDataSize,
|
}
|
||||||
void** outData,
|
|
||||||
void* inUserData)
|
if (ioData.mDataByteSize > mBufferSize - mBufferOffset)
|
||||||
{
|
ioData.mDataByteSize = mBufferSize - mBufferOffset;
|
||||||
AudioFileManager* THIS = (AudioFileManager*)inUserData;
|
ioData.mData = (char *)mTmpBuffer + mBufferOffset;
|
||||||
return THIS->GetFileData(outData, outDataSize);
|
mBufferOffset += ioData.mDataByteSize;
|
||||||
|
|
||||||
|
mByteCounter += ioData.mDataByteSize;
|
||||||
|
AfterRender();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioFileManager::~AudioFileManager ()
|
AudioFileManager::~AudioFileManager ()
|
||||||
|
@ -102,7 +101,6 @@ AudioFileManager::~AudioFileManager ()
|
||||||
AudioFilePlayer::AudioFilePlayer (const FSRef *inFileRef)
|
AudioFilePlayer::AudioFilePlayer (const FSRef *inFileRef)
|
||||||
: mConnected (false),
|
: mConnected (false),
|
||||||
mAudioFileManager (0),
|
mAudioFileManager (0),
|
||||||
mConverter (0),
|
|
||||||
mNotifier (0),
|
mNotifier (0),
|
||||||
mStartFrame (0)
|
mStartFrame (0)
|
||||||
{
|
{
|
||||||
|
@ -124,39 +122,14 @@ AudioFilePlayer::AudioFilePlayer (const FSRef *inFileRef)
|
||||||
bytesPerSecond);
|
bytesPerSecond);
|
||||||
}
|
}
|
||||||
|
|
||||||
// you can put a rate scalar here to play the file faster or slower
|
void AudioFilePlayer::SetDestination (AudioUnit &inDestUnit)
|
||||||
// by multiplying the same rate by the desired factor
|
|
||||||
// eg fileSampleRate * 2 -> twice as fast
|
|
||||||
// before you create the AudioConverter
|
|
||||||
void AudioFilePlayer::SetDestination (AudioUnit &inDestUnit,
|
|
||||||
int inBusNumber)
|
|
||||||
{
|
{
|
||||||
if (mConnected) throw static_cast<OSStatus>(-1); //can't set dest if already engaged
|
if (mConnected) throw static_cast<OSStatus>(-1); //can't set dest if already engaged
|
||||||
|
|
||||||
mPlayUnit = inDestUnit;
|
mPlayUnit = inDestUnit;
|
||||||
mBusNumber = inBusNumber;
|
|
||||||
|
|
||||||
OSStatus result = noErr;
|
OSStatus result = noErr;
|
||||||
|
|
||||||
if (mConverter) {
|
|
||||||
result = AudioConverterDispose (mConverter);
|
|
||||||
THROW_RESULT("AudioConverterDispose")
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioStreamBasicDescription destDesc;
|
|
||||||
UInt32 size = sizeof (destDesc);
|
|
||||||
result = AudioUnitGetProperty (inDestUnit,
|
|
||||||
kAudioUnitProperty_StreamFormat,
|
|
||||||
kAudioUnitScope_Input,
|
|
||||||
inBusNumber,
|
|
||||||
&destDesc,
|
|
||||||
&size);
|
|
||||||
THROW_RESULT("AudioUnitGetProperty")
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
printf("Destination format:\n");
|
|
||||||
PrintStreamDesc (&destDesc);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//we can "down" cast a component instance to a component
|
//we can "down" cast a component instance to a component
|
||||||
ComponentDescription desc;
|
ComponentDescription desc;
|
||||||
|
@ -171,19 +144,14 @@ void AudioFilePlayer::SetDestination (AudioUnit &inDestUnit,
|
||||||
THROW_RESULT("BAD COMPONENT")
|
THROW_RESULT("BAD COMPONENT")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set the input format of the audio unit. */
|
||||||
result = AudioConverterNew (&mFileDescription, &destDesc, &mConverter);
|
result = AudioUnitSetProperty (inDestUnit,
|
||||||
THROW_RESULT("AudioConverterNew")
|
kAudioUnitProperty_StreamFormat,
|
||||||
|
kAudioUnitScope_Input,
|
||||||
#if 0
|
0,
|
||||||
// this uses the better quality SRC
|
&mFileDescription,
|
||||||
UInt32 srcID = kAudioUnitSRCAlgorithm_Polyphase;
|
sizeof (mFileDescription));
|
||||||
result = AudioConverterSetProperty(mConverter,
|
THROW_RESULT("AudioUnitSetProperty")
|
||||||
kAudioConverterSampleRateConverterAlgorithm,
|
|
||||||
sizeof(srcID),
|
|
||||||
&srcID);
|
|
||||||
THROW_RESULT("AudioConverterSetProperty")
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioFilePlayer::SetStartFrame (int frame)
|
void AudioFilePlayer::SetStartFrame (int frame)
|
||||||
|
@ -220,22 +188,18 @@ AudioFilePlayer::~AudioFilePlayer()
|
||||||
FSClose (mForkRefNum);
|
FSClose (mForkRefNum);
|
||||||
mForkRefNum = 0;
|
mForkRefNum = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mConverter) {
|
|
||||||
AudioConverterDispose (mConverter);
|
|
||||||
mConverter = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioFilePlayer::Connect()
|
void AudioFilePlayer::Connect()
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
printf ("Connect:%x,%ld, engaged=%d\n", (int)mPlayUnit, mBusNumber, (mConnected ? 1 : 0));
|
printf ("Connect:%x, engaged=%d\n", (int)mPlayUnit, (mConnected ? 1 : 0));
|
||||||
#endif
|
#endif
|
||||||
if (!mConnected)
|
if (!mConnected)
|
||||||
{
|
{
|
||||||
mAudioFileManager->Connect(mConverter);
|
mAudioFileManager->DoConnect();
|
||||||
|
|
||||||
|
|
||||||
// set the render callback for the file data to be supplied to the sound converter AU
|
// set the render callback for the file data to be supplied to the sound converter AU
|
||||||
mInputCallback.inputProc = AudioFileManager::FileInputProc;
|
mInputCallback.inputProc = AudioFileManager::FileInputProc;
|
||||||
mInputCallback.inputProcRefCon = mAudioFileManager;
|
mInputCallback.inputProcRefCon = mAudioFileManager;
|
||||||
|
@ -243,7 +207,7 @@ void AudioFilePlayer::Connect()
|
||||||
OSStatus result = AudioUnitSetProperty (mPlayUnit,
|
OSStatus result = AudioUnitSetProperty (mPlayUnit,
|
||||||
kAudioUnitProperty_SetInputCallback,
|
kAudioUnitProperty_SetInputCallback,
|
||||||
kAudioUnitScope_Input,
|
kAudioUnitScope_Input,
|
||||||
mBusNumber,
|
0,
|
||||||
&mInputCallback,
|
&mInputCallback,
|
||||||
sizeof(mInputCallback));
|
sizeof(mInputCallback));
|
||||||
THROW_RESULT("AudioUnitSetProperty")
|
THROW_RESULT("AudioUnitSetProperty")
|
||||||
|
@ -272,7 +236,7 @@ void AudioFilePlayer::DoNotification (OSStatus inStatus) const
|
||||||
void AudioFilePlayer::Disconnect ()
|
void AudioFilePlayer::Disconnect ()
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
printf ("Disconnect:%x,%ld, engaged=%d\n", (int)mPlayUnit, mBusNumber, (mConnected ? 1 : 0));
|
printf ("Disconnect:%x,%ld, engaged=%d\n", (int)mPlayUnit, 0, (mConnected ? 1 : 0));
|
||||||
#endif
|
#endif
|
||||||
if (mConnected)
|
if (mConnected)
|
||||||
{
|
{
|
||||||
|
@ -283,7 +247,7 @@ void AudioFilePlayer::Disconnect ()
|
||||||
OSStatus result = AudioUnitSetProperty (mPlayUnit,
|
OSStatus result = AudioUnitSetProperty (mPlayUnit,
|
||||||
kAudioUnitProperty_SetInputCallback,
|
kAudioUnitProperty_SetInputCallback,
|
||||||
kAudioUnitScope_Input,
|
kAudioUnitScope_Input,
|
||||||
mBusNumber,
|
0,
|
||||||
&mInputCallback,
|
&mInputCallback,
|
||||||
sizeof(mInputCallback));
|
sizeof(mInputCallback));
|
||||||
if (result)
|
if (result)
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
|
|
||||||
#include <CoreServices/CoreServices.h>
|
#include <CoreServices/CoreServices.h>
|
||||||
|
|
||||||
#include <AudioToolbox/AudioConverter.h>
|
|
||||||
#include <AudioUnit/AudioUnit.h>
|
#include <AudioUnit/AudioUnit.h>
|
||||||
|
|
||||||
#include "SDL_error.h"
|
#include "SDL_error.h"
|
||||||
|
@ -65,8 +64,7 @@ public:
|
||||||
|
|
||||||
~AudioFilePlayer();
|
~AudioFilePlayer();
|
||||||
|
|
||||||
void SetDestination (AudioUnit &inDestUnit,
|
void SetDestination (AudioUnit &inDestUnit);
|
||||||
int inBusNumber);
|
|
||||||
|
|
||||||
void SetNotifier (AudioFilePlayNotifier inNotifier, void *inRefCon)
|
void SetNotifier (AudioFilePlayNotifier inNotifier, void *inRefCon)
|
||||||
{
|
{
|
||||||
|
@ -88,26 +86,18 @@ public:
|
||||||
|
|
||||||
bool IsConnected () const { return mConnected; }
|
bool IsConnected () const { return mConnected; }
|
||||||
|
|
||||||
UInt32 GetBusNumber () const { return mBusNumber; }
|
|
||||||
|
|
||||||
AudioUnit GetDestUnit () const { return mPlayUnit; }
|
AudioUnit GetDestUnit () const { return mPlayUnit; }
|
||||||
|
|
||||||
AudioConverterRef GetAudioConverter() const { return mConverter; }
|
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
void Print() const
|
void Print() const
|
||||||
{
|
{
|
||||||
printf ("Destination Bus:%ld\n", GetBusNumber());
|
|
||||||
printf ("Is Connected:%s\n", (IsConnected() ? "true" : "false"));
|
printf ("Is Connected:%s\n", (IsConnected() ? "true" : "false"));
|
||||||
printf ("- - - - - - - - - - - - - - \n");
|
printf ("- - - - - - - - - - - - - - \n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const AudioStreamBasicDescription& GetFileFormat() const { return mFileDescription; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AudioUnit mPlayUnit;
|
AudioUnit mPlayUnit;
|
||||||
UInt32 mBusNumber;
|
|
||||||
SInt16 mForkRefNum;
|
SInt16 mForkRefNum;
|
||||||
|
|
||||||
AudioUnitInputCallback mInputCallback;
|
AudioUnitInputCallback mInputCallback;
|
||||||
|
@ -117,7 +107,6 @@ private:
|
||||||
bool mConnected;
|
bool mConnected;
|
||||||
|
|
||||||
AudioFileManager* mAudioFileManager;
|
AudioFileManager* mAudioFileManager;
|
||||||
AudioConverterRef mConverter;
|
|
||||||
|
|
||||||
AudioFilePlayNotifier mNotifier;
|
AudioFilePlayNotifier mNotifier;
|
||||||
void* mRefCon;
|
void* mRefCon;
|
||||||
|
@ -141,15 +130,11 @@ public:
|
||||||
~AudioFileManager();
|
~AudioFileManager();
|
||||||
|
|
||||||
|
|
||||||
void Connect (AudioConverterRef inConverter)
|
|
||||||
{
|
|
||||||
mParentConverter = inConverter;
|
|
||||||
DoConnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
// this method should NOT be called by an object of this class
|
// this method should NOT be called by an object of this class
|
||||||
// as it is called by the parent's Disconnect() method
|
// as it is called by the parent's Disconnect() method
|
||||||
void Disconnect ();
|
void Disconnect ();
|
||||||
|
|
||||||
|
void DoConnect ();
|
||||||
|
|
||||||
OSStatus Read(char *buffer, UInt32 *len);
|
OSStatus Read(char *buffer, UInt32 *len);
|
||||||
|
|
||||||
|
@ -165,7 +150,6 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AudioFilePlayer& mParent;
|
AudioFilePlayer& mParent;
|
||||||
AudioConverterRef mParentConverter;
|
|
||||||
SInt16 mForkRefNum;
|
SInt16 mForkRefNum;
|
||||||
SInt64 mAudioDataOffset;
|
SInt64 mAudioDataOffset;
|
||||||
|
|
||||||
|
@ -179,6 +163,10 @@ protected:
|
||||||
|
|
||||||
int mNumTimesAskedSinceFinished;
|
int mNumTimesAskedSinceFinished;
|
||||||
|
|
||||||
|
|
||||||
|
void* mTmpBuffer;
|
||||||
|
UInt32 mBufferSize;
|
||||||
|
UInt32 mBufferOffset;
|
||||||
public:
|
public:
|
||||||
const UInt32 mChunkSize;
|
const UInt32 mChunkSize;
|
||||||
SInt64 mFileLength;
|
SInt64 mFileLength;
|
||||||
|
@ -190,8 +178,6 @@ protected:
|
||||||
OSStatus Render (AudioBuffer &ioData);
|
OSStatus Render (AudioBuffer &ioData);
|
||||||
|
|
||||||
OSStatus GetFileData (void** inOutData, UInt32 *inOutDataSize);
|
OSStatus GetFileData (void** inOutData, UInt32 *inOutDataSize);
|
||||||
|
|
||||||
void DoConnect ();
|
|
||||||
|
|
||||||
void AfterRender ();
|
void AfterRender ();
|
||||||
|
|
||||||
|
@ -201,10 +187,6 @@ public:
|
||||||
const AudioTimeStamp *inTimeStamp,
|
const AudioTimeStamp *inTimeStamp,
|
||||||
UInt32 inBusNumber,
|
UInt32 inBusNumber,
|
||||||
AudioBuffer *ioData);
|
AudioBuffer *ioData);
|
||||||
static OSStatus ACInputProc (AudioConverterRef inAudioConverter,
|
|
||||||
UInt32* outDataSize,
|
|
||||||
void** outData,
|
|
||||||
void* inUserData);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -287,6 +287,8 @@ AudioFileManager::AudioFileManager (AudioFilePlayer &inParent,
|
||||||
mLockUnsuccessful (false),
|
mLockUnsuccessful (false),
|
||||||
mIsEngaged (false),
|
mIsEngaged (false),
|
||||||
|
|
||||||
|
mBufferSize (inChunkSize),
|
||||||
|
mBufferOffset (inChunkSize),
|
||||||
mChunkSize (inChunkSize),
|
mChunkSize (inChunkSize),
|
||||||
mFileLength (inFileLength),
|
mFileLength (inFileLength),
|
||||||
mReadFilePosition (0),
|
mReadFilePosition (0),
|
||||||
|
@ -364,7 +366,7 @@ OSStatus AudioFileManager::GetFileData (void** inOutData, UInt32 *inOutDataSize)
|
||||||
|
|
||||||
if (mReadFromFirstBuffer == mWriteToFirstBuffer) {
|
if (mReadFromFirstBuffer == mWriteToFirstBuffer) {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
printf ("* * * * * * * Can't keep up with reading file:%ld\n", mParent.GetBusNumber());
|
printf ("* * * * * * * Can't keep up with reading file\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mParent.DoNotification (kAudioFilePlayErr_FilePlayUnderrun);
|
mParent.DoNotification (kAudioFilePlayErr_FilePlayUnderrun);
|
||||||
|
|
|
@ -68,8 +68,6 @@ static SDL_CD* theCDROM;
|
||||||
|
|
||||||
static OSStatus CheckInit ();
|
static OSStatus CheckInit ();
|
||||||
|
|
||||||
static OSStatus MatchAUFormats (AudioUnit theUnit, UInt32 theInputBus);
|
|
||||||
|
|
||||||
static void FilePlayNotificationHandler (void* inRefCon, OSStatus inStatus);
|
static void FilePlayNotificationHandler (void* inRefCon, OSStatus inStatus);
|
||||||
|
|
||||||
static int RunCallBackThread (void* inRefCon);
|
static int RunCallBackThread (void* inRefCon);
|
||||||
|
@ -423,7 +421,7 @@ int LoadFile (const FSRef *ref, int startFrame, int stopFrame)
|
||||||
throw (-3);
|
throw (-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
thePlayer->SetDestination(theUnit, 0);
|
thePlayer->SetDestination(theUnit);
|
||||||
|
|
||||||
if (startFrame >= 0)
|
if (startFrame >= 0)
|
||||||
thePlayer->SetStartFrame (startFrame);
|
thePlayer->SetStartFrame (startFrame);
|
||||||
|
@ -605,16 +603,6 @@ static OSStatus CheckInit ()
|
||||||
THROW_RESULT("CheckInit: AudioUnitInitialize")
|
THROW_RESULT("CheckInit: AudioUnitInitialize")
|
||||||
|
|
||||||
|
|
||||||
// In this case we first want to get the output format of the OutputUnit
|
|
||||||
// Then we set that as the input format. Why?
|
|
||||||
// So that only a single conversion process is done
|
|
||||||
// when SetDestination is called it will get the input format of the
|
|
||||||
// unit its supplying data to. This defaults to 44.1K, stereo, so if
|
|
||||||
// the device is not that, then we lose a possibly rendering of data
|
|
||||||
|
|
||||||
result = MatchAUFormats (theUnit, 0);
|
|
||||||
THROW_RESULT("CheckInit: MatchAUFormats")
|
|
||||||
|
|
||||||
playBackWasInit = true;
|
playBackWasInit = true;
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
|
@ -625,29 +613,6 @@ static OSStatus CheckInit ()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static OSStatus MatchAUFormats (AudioUnit theUnit, UInt32 theInputBus)
|
|
||||||
{
|
|
||||||
AudioStreamBasicDescription theDesc;
|
|
||||||
UInt32 size = sizeof (theDesc);
|
|
||||||
OSStatus result = AudioUnitGetProperty (theUnit,
|
|
||||||
kAudioUnitProperty_StreamFormat,
|
|
||||||
kAudioUnitScope_Output,
|
|
||||||
0,
|
|
||||||
&theDesc,
|
|
||||||
&size);
|
|
||||||
THROW_RESULT("MatchAUFormats: AudioUnitGetProperty")
|
|
||||||
|
|
||||||
result = AudioUnitSetProperty (theUnit,
|
|
||||||
kAudioUnitProperty_StreamFormat,
|
|
||||||
kAudioUnitScope_Input,
|
|
||||||
theInputBus,
|
|
||||||
&theDesc,
|
|
||||||
size);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FilePlayNotificationHandler(void * inRefCon, OSStatus inStatus)
|
static void FilePlayNotificationHandler(void * inRefCon, OSStatus inStatus)
|
||||||
{
|
{
|
||||||
if (inStatus == kAudioFilePlay_FileIsFinished) {
|
if (inStatus == kAudioFilePlay_FileIsFinished) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue