mirror of
https://github.com/darlinghq/darling-openal.git
synced 2024-11-23 12:19:39 +00:00
Update Source To OpenAL-67
This commit is contained in:
parent
ee85e01fbc
commit
19c7b3ed2f
@ -1 +0,0 @@
|
||||
al
|
@ -12,8 +12,8 @@ _alGetIntegerv
|
||||
_alGetFloatv
|
||||
_alGetDoublev
|
||||
_alGetString
|
||||
_alSetInteger
|
||||
_alSetDouble
|
||||
#_alSetInteger
|
||||
#_alSetDouble
|
||||
_alGetError
|
||||
_alIsExtensionPresent
|
||||
_alGetProcAddress
|
||||
@ -75,7 +75,7 @@ _alDistanceModel
|
||||
_alDopplerFactor
|
||||
_alDopplerVelocity
|
||||
_alSpeedOfSound
|
||||
_alHint
|
||||
# _alHint
|
||||
|
||||
# from alc.h
|
||||
_alcGetString
|
||||
@ -108,18 +108,18 @@ _alutLoadWAVMemory
|
||||
_alutUnloadWAV
|
||||
|
||||
# from OSX_EXTENSION
|
||||
_alcMacOSXRenderingQuality
|
||||
_alMacOSXRenderChannelCount
|
||||
_alcMacOSXMixerMaxiumumBusses
|
||||
_alcMacOSXMixerOutputRate
|
||||
_alcMacOSXGetRenderingQuality
|
||||
_alMacOSXGetRenderChannelCount
|
||||
_alcMacOSXGetMixerMaxiumumBusses
|
||||
_alcMacOSXGetMixerOutputRate
|
||||
_alBufferDataStatic
|
||||
#_alcMacOSXRenderingQuality
|
||||
#_alMacOSXRenderChannelCount
|
||||
#_alcMacOSXMixerMaxiumumBusses
|
||||
#_alcMacOSXMixerOutputRate
|
||||
#_alcMacOSXGetRenderingQuality
|
||||
#_alMacOSXGetRenderChannelCount
|
||||
#_alcMacOSXGetMixerMaxiumumBusses
|
||||
#_alcMacOSXGetMixerOutputRate
|
||||
#_alBufferDataStatic
|
||||
|
||||
# from APPLE_ENVIRONMENTAL_AUDIO_EXTENSION
|
||||
_alcASAGetSource
|
||||
_alcASASetSource
|
||||
_alcASAGetListener
|
||||
_alcASASetListener
|
||||
#_alcASAGetSource
|
||||
#_alcASASetSource
|
||||
#_alcASAGetListener
|
||||
#_alcASASetListener
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef AL_AL_H
|
||||
#define AL_AL_H
|
||||
|
||||
#include <os/availability.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -30,6 +32,10 @@ extern "C" {
|
||||
#pragma export on
|
||||
#endif
|
||||
|
||||
#ifndef OPENAL_DEPRECATED
|
||||
#define OPENAL_DEPRECATED API_DEPRECATED("OpenAL is deprecated in favor of AVAudioEngine", macos(10.4, 10.15), ios(2.0, 13.0))
|
||||
#endif // OPENAL_DEPRECATED
|
||||
|
||||
/*
|
||||
* The OPENAL, ALAPI, ALAPIENTRY, AL_INVALID, AL_ILLEGAL_ENUM, and
|
||||
* AL_ILLEGAL_COMMAND macros are deprecated, but are included for
|
||||
@ -363,40 +369,40 @@ typedef void ALvoid;
|
||||
/*
|
||||
* Renderer State management
|
||||
*/
|
||||
AL_API void AL_APIENTRY alEnable( ALenum capability );
|
||||
AL_API void AL_APIENTRY alEnable( ALenum capability ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alDisable( ALenum capability );
|
||||
AL_API void AL_APIENTRY alDisable( ALenum capability ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API ALboolean AL_APIENTRY alIsEnabled( ALenum capability );
|
||||
AL_API ALboolean AL_APIENTRY alIsEnabled( ALenum capability ) OPENAL_DEPRECATED;
|
||||
|
||||
|
||||
/*
|
||||
* State retrieval
|
||||
*/
|
||||
AL_API const ALchar* AL_APIENTRY alGetString( ALenum param );
|
||||
AL_API const ALchar* AL_APIENTRY alGetString( ALenum param ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetBooleanv( ALenum param, ALboolean* data );
|
||||
AL_API void AL_APIENTRY alGetBooleanv( ALenum param, ALboolean* data ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetIntegerv( ALenum param, ALint* data );
|
||||
AL_API void AL_APIENTRY alGetIntegerv( ALenum param, ALint* data ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetFloatv( ALenum param, ALfloat* data );
|
||||
AL_API void AL_APIENTRY alGetFloatv( ALenum param, ALfloat* data ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetDoublev( ALenum param, ALdouble* data );
|
||||
AL_API void AL_APIENTRY alGetDoublev( ALenum param, ALdouble* data ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API ALboolean AL_APIENTRY alGetBoolean( ALenum param );
|
||||
AL_API ALboolean AL_APIENTRY alGetBoolean( ALenum param ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API ALint AL_APIENTRY alGetInteger( ALenum param );
|
||||
AL_API ALint AL_APIENTRY alGetInteger( ALenum param ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API ALfloat AL_APIENTRY alGetFloat( ALenum param );
|
||||
AL_API ALfloat AL_APIENTRY alGetFloat( ALenum param ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API ALdouble AL_APIENTRY alGetDouble( ALenum param );
|
||||
AL_API ALdouble AL_APIENTRY alGetDouble( ALenum param ) OPENAL_DEPRECATED;
|
||||
|
||||
|
||||
/*
|
||||
* Error support.
|
||||
* Obtain the most recent error generated in the AL state machine.
|
||||
*/
|
||||
AL_API ALenum AL_APIENTRY alGetError( void );
|
||||
AL_API ALenum AL_APIENTRY alGetError( void ) OPENAL_DEPRECATED;
|
||||
|
||||
|
||||
/*
|
||||
@ -404,11 +410,11 @@ AL_API ALenum AL_APIENTRY alGetError( void );
|
||||
* Query for the presence of an extension, and obtain any appropriate
|
||||
* function pointers and enum values.
|
||||
*/
|
||||
AL_API ALboolean AL_APIENTRY alIsExtensionPresent( const ALchar* extname );
|
||||
AL_API ALboolean AL_APIENTRY alIsExtensionPresent( const ALchar* extname ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void* AL_APIENTRY alGetProcAddress( const ALchar* fname );
|
||||
AL_API void* AL_APIENTRY alGetProcAddress( const ALchar* fname ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API ALenum AL_APIENTRY alGetEnumValue( const ALchar* ename );
|
||||
AL_API ALenum AL_APIENTRY alGetEnumValue( const ALchar* ename ) OPENAL_DEPRECATED;
|
||||
|
||||
|
||||
/*
|
||||
@ -427,32 +433,32 @@ AL_API ALenum AL_APIENTRY alGetEnumValue( const ALchar* ename );
|
||||
/*
|
||||
* Set Listener parameters
|
||||
*/
|
||||
AL_API void AL_APIENTRY alListenerf( ALenum param, ALfloat value );
|
||||
AL_API void AL_APIENTRY alListenerf( ALenum param, ALfloat value ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alListener3f( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 );
|
||||
AL_API void AL_APIENTRY alListener3f( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alListenerfv( ALenum param, const ALfloat* values );
|
||||
AL_API void AL_APIENTRY alListenerfv( ALenum param, const ALfloat* values ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alListeneri( ALenum param, ALint value );
|
||||
AL_API void AL_APIENTRY alListeneri( ALenum param, ALint value ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alListener3i( ALenum param, ALint value1, ALint value2, ALint value3 );
|
||||
AL_API void AL_APIENTRY alListener3i( ALenum param, ALint value1, ALint value2, ALint value3 ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alListeneriv( ALenum param, const ALint* values );
|
||||
AL_API void AL_APIENTRY alListeneriv( ALenum param, const ALint* values ) OPENAL_DEPRECATED;
|
||||
|
||||
/*
|
||||
* Get Listener parameters
|
||||
*/
|
||||
AL_API void AL_APIENTRY alGetListenerf( ALenum param, ALfloat* value );
|
||||
AL_API void AL_APIENTRY alGetListenerf( ALenum param, ALfloat* value ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetListener3f( ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3 );
|
||||
AL_API void AL_APIENTRY alGetListener3f( ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3 ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetListenerfv( ALenum param, ALfloat* values );
|
||||
AL_API void AL_APIENTRY alGetListenerfv( ALenum param, ALfloat* values ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetListeneri( ALenum param, ALint* value );
|
||||
AL_API void AL_APIENTRY alGetListeneri( ALenum param, ALint* value ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetListener3i( ALenum param, ALint *value1, ALint *value2, ALint *value3 );
|
||||
AL_API void AL_APIENTRY alGetListener3i( ALenum param, ALint *value1, ALint *value2, ALint *value3 ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetListeneriv( ALenum param, ALint* values );
|
||||
AL_API void AL_APIENTRY alGetListeneriv( ALenum param, ALint* values ) OPENAL_DEPRECATED;
|
||||
|
||||
|
||||
/**
|
||||
@ -489,43 +495,43 @@ AL_API void AL_APIENTRY alGetListeneriv( ALenum param, ALint* values );
|
||||
*/
|
||||
|
||||
/* Create Source objects */
|
||||
AL_API void AL_APIENTRY alGenSources( ALsizei n, ALuint* sources );
|
||||
AL_API void AL_APIENTRY alGenSources( ALsizei n, ALuint* sources ) OPENAL_DEPRECATED;
|
||||
|
||||
/* Delete Source objects */
|
||||
AL_API void AL_APIENTRY alDeleteSources( ALsizei n, const ALuint* sources );
|
||||
AL_API void AL_APIENTRY alDeleteSources( ALsizei n, const ALuint* sources ) OPENAL_DEPRECATED;
|
||||
|
||||
/* Verify a handle is a valid Source */
|
||||
AL_API ALboolean AL_APIENTRY alIsSource( ALuint sid );
|
||||
AL_API ALboolean AL_APIENTRY alIsSource( ALuint sid ) OPENAL_DEPRECATED;
|
||||
|
||||
/*
|
||||
* Set Source parameters
|
||||
*/
|
||||
AL_API void AL_APIENTRY alSourcef( ALuint sid, ALenum param, ALfloat value );
|
||||
AL_API void AL_APIENTRY alSourcef( ALuint sid, ALenum param, ALfloat value ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alSource3f( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 );
|
||||
AL_API void AL_APIENTRY alSource3f( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alSourcefv( ALuint sid, ALenum param, const ALfloat* values );
|
||||
AL_API void AL_APIENTRY alSourcefv( ALuint sid, ALenum param, const ALfloat* values ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alSourcei( ALuint sid, ALenum param, ALint value );
|
||||
AL_API void AL_APIENTRY alSourcei( ALuint sid, ALenum param, ALint value ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alSource3i( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 );
|
||||
AL_API void AL_APIENTRY alSource3i( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alSourceiv( ALuint sid, ALenum param, const ALint* values );
|
||||
AL_API void AL_APIENTRY alSourceiv( ALuint sid, ALenum param, const ALint* values ) OPENAL_DEPRECATED;
|
||||
|
||||
/*
|
||||
* Get Source parameters
|
||||
*/
|
||||
AL_API void AL_APIENTRY alGetSourcef( ALuint sid, ALenum param, ALfloat* value );
|
||||
AL_API void AL_APIENTRY alGetSourcef( ALuint sid, ALenum param, ALfloat* value ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetSource3f( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3);
|
||||
AL_API void AL_APIENTRY alGetSource3f( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetSourcefv( ALuint sid, ALenum param, ALfloat* values );
|
||||
AL_API void AL_APIENTRY alGetSourcefv( ALuint sid, ALenum param, ALfloat* values ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetSourcei( ALuint sid, ALenum param, ALint* value );
|
||||
AL_API void AL_APIENTRY alGetSourcei( ALuint sid, ALenum param, ALint* value ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetSource3i( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3);
|
||||
AL_API void AL_APIENTRY alGetSource3i( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetSourceiv( ALuint sid, ALenum param, ALint* values );
|
||||
AL_API void AL_APIENTRY alGetSourceiv( ALuint sid, ALenum param, ALint* values ) OPENAL_DEPRECATED;
|
||||
|
||||
|
||||
/*
|
||||
@ -533,39 +539,39 @@ AL_API void AL_APIENTRY alGetSourceiv( ALuint sid, ALenum param, ALint* values
|
||||
*/
|
||||
|
||||
/* Play, replay, or resume (if paused) a list of Sources */
|
||||
AL_API void AL_APIENTRY alSourcePlayv( ALsizei ns, const ALuint *sids );
|
||||
AL_API void AL_APIENTRY alSourcePlayv( ALsizei ns, const ALuint *sids ) OPENAL_DEPRECATED;
|
||||
|
||||
/* Stop a list of Sources */
|
||||
AL_API void AL_APIENTRY alSourceStopv( ALsizei ns, const ALuint *sids );
|
||||
AL_API void AL_APIENTRY alSourceStopv( ALsizei ns, const ALuint *sids ) OPENAL_DEPRECATED;
|
||||
|
||||
/* Rewind a list of Sources */
|
||||
AL_API void AL_APIENTRY alSourceRewindv( ALsizei ns, const ALuint *sids );
|
||||
AL_API void AL_APIENTRY alSourceRewindv( ALsizei ns, const ALuint *sids ) OPENAL_DEPRECATED;
|
||||
|
||||
/* Pause a list of Sources */
|
||||
AL_API void AL_APIENTRY alSourcePausev( ALsizei ns, const ALuint *sids );
|
||||
AL_API void AL_APIENTRY alSourcePausev( ALsizei ns, const ALuint *sids ) OPENAL_DEPRECATED;
|
||||
|
||||
/*
|
||||
* Source based playback calls
|
||||
*/
|
||||
|
||||
/* Play, replay, or resume a Source */
|
||||
AL_API void AL_APIENTRY alSourcePlay( ALuint sid );
|
||||
AL_API void AL_APIENTRY alSourcePlay( ALuint sid ) OPENAL_DEPRECATED;
|
||||
|
||||
/* Stop a Source */
|
||||
AL_API void AL_APIENTRY alSourceStop( ALuint sid );
|
||||
AL_API void AL_APIENTRY alSourceStop( ALuint sid ) OPENAL_DEPRECATED;
|
||||
|
||||
/* Rewind a Source (set playback postiton to beginning) */
|
||||
AL_API void AL_APIENTRY alSourceRewind( ALuint sid );
|
||||
AL_API void AL_APIENTRY alSourceRewind( ALuint sid ) OPENAL_DEPRECATED;
|
||||
|
||||
/* Pause a Source */
|
||||
AL_API void AL_APIENTRY alSourcePause( ALuint sid );
|
||||
AL_API void AL_APIENTRY alSourcePause( ALuint sid ) OPENAL_DEPRECATED;
|
||||
|
||||
/*
|
||||
* Source Queuing
|
||||
*/
|
||||
AL_API void AL_APIENTRY alSourceQueueBuffers( ALuint sid, ALsizei numEntries, const ALuint *bids );
|
||||
AL_API void AL_APIENTRY alSourceQueueBuffers( ALuint sid, ALsizei numEntries, const ALuint *bids ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alSourceUnqueueBuffers( ALuint sid, ALsizei numEntries, ALuint *bids );
|
||||
AL_API void AL_APIENTRY alSourceUnqueueBuffers( ALuint sid, ALsizei numEntries, ALuint *bids ) OPENAL_DEPRECATED;
|
||||
|
||||
|
||||
/**
|
||||
@ -583,58 +589,58 @@ AL_API void AL_APIENTRY alSourceUnqueueBuffers( ALuint sid, ALsizei numEntries,
|
||||
*/
|
||||
|
||||
/* Create Buffer objects */
|
||||
AL_API void AL_APIENTRY alGenBuffers( ALsizei n, ALuint* buffers );
|
||||
AL_API void AL_APIENTRY alGenBuffers( ALsizei n, ALuint* buffers ) OPENAL_DEPRECATED;
|
||||
|
||||
/* Delete Buffer objects */
|
||||
AL_API void AL_APIENTRY alDeleteBuffers( ALsizei n, const ALuint* buffers );
|
||||
AL_API void AL_APIENTRY alDeleteBuffers( ALsizei n, const ALuint* buffers ) OPENAL_DEPRECATED;
|
||||
|
||||
/* Verify a handle is a valid Buffer */
|
||||
AL_API ALboolean AL_APIENTRY alIsBuffer( ALuint bid );
|
||||
AL_API ALboolean AL_APIENTRY alIsBuffer( ALuint bid ) OPENAL_DEPRECATED;
|
||||
|
||||
/* Specify the data to be copied into a buffer */
|
||||
AL_API void AL_APIENTRY alBufferData( ALuint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq );
|
||||
AL_API void AL_APIENTRY alBufferData( ALuint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq ) OPENAL_DEPRECATED;
|
||||
|
||||
/*
|
||||
* Set Buffer parameters
|
||||
*/
|
||||
AL_API void AL_APIENTRY alBufferf( ALuint bid, ALenum param, ALfloat value );
|
||||
AL_API void AL_APIENTRY alBufferf( ALuint bid, ALenum param, ALfloat value ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alBuffer3f( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 );
|
||||
AL_API void AL_APIENTRY alBuffer3f( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alBufferfv( ALuint bid, ALenum param, const ALfloat* values );
|
||||
AL_API void AL_APIENTRY alBufferfv( ALuint bid, ALenum param, const ALfloat* values ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alBufferi( ALuint bid, ALenum param, ALint value );
|
||||
AL_API void AL_APIENTRY alBufferi( ALuint bid, ALenum param, ALint value ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alBuffer3i( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 );
|
||||
AL_API void AL_APIENTRY alBuffer3i( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alBufferiv( ALuint bid, ALenum param, const ALint* values );
|
||||
AL_API void AL_APIENTRY alBufferiv( ALuint bid, ALenum param, const ALint* values ) OPENAL_DEPRECATED;
|
||||
|
||||
/*
|
||||
* Get Buffer parameters
|
||||
*/
|
||||
AL_API void AL_APIENTRY alGetBufferf( ALuint bid, ALenum param, ALfloat* value );
|
||||
AL_API void AL_APIENTRY alGetBufferf( ALuint bid, ALenum param, ALfloat* value ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetBuffer3f( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3);
|
||||
AL_API void AL_APIENTRY alGetBuffer3f( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetBufferfv( ALuint bid, ALenum param, ALfloat* values );
|
||||
AL_API void AL_APIENTRY alGetBufferfv( ALuint bid, ALenum param, ALfloat* values ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetBufferi( ALuint bid, ALenum param, ALint* value );
|
||||
AL_API void AL_APIENTRY alGetBufferi( ALuint bid, ALenum param, ALint* value ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetBuffer3i( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3);
|
||||
AL_API void AL_APIENTRY alGetBuffer3i( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alGetBufferiv( ALuint bid, ALenum param, ALint* values );
|
||||
AL_API void AL_APIENTRY alGetBufferiv( ALuint bid, ALenum param, ALint* values ) OPENAL_DEPRECATED;
|
||||
|
||||
|
||||
/*
|
||||
* Global Parameters
|
||||
*/
|
||||
AL_API void AL_APIENTRY alDopplerFactor( ALfloat value );
|
||||
AL_API void AL_APIENTRY alDopplerFactor( ALfloat value ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alDopplerVelocity( ALfloat value );
|
||||
AL_API void AL_APIENTRY alDopplerVelocity( ALfloat value ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alSpeedOfSound( ALfloat value );
|
||||
AL_API void AL_APIENTRY alSpeedOfSound( ALfloat value ) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API void AL_APIENTRY alDistanceModel( ALenum distanceModel );
|
||||
AL_API void AL_APIENTRY alDistanceModel( ALenum distanceModel ) OPENAL_DEPRECATED;
|
||||
|
||||
/*
|
||||
* Pointer-to-function types, useful for dynamically getting AL entry points.
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef AL_ALC_H
|
||||
#define AL_ALC_H
|
||||
|
||||
#include <os/availability.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -38,6 +40,9 @@ extern "C" {
|
||||
#define ALCAPIENTRY ALC_APIENTRY
|
||||
#define ALC_INVALID 0
|
||||
|
||||
#ifndef OPENAL_DEPRECATED
|
||||
#define OPENAL_DEPRECATED API_DEPRECATED("OpenAL is deprecated", macos(10.4, 10.15), ios(2.0, 13.0))
|
||||
#endif // OPENAL_DEPRECATED
|
||||
|
||||
#define ALC_VERSION_0_1 1
|
||||
|
||||
@ -183,34 +188,34 @@ typedef void ALCvoid;
|
||||
/*
|
||||
* Context Management
|
||||
*/
|
||||
ALC_API ALCcontext * ALC_APIENTRY alcCreateContext( ALCdevice *device, const ALCint* attrlist );
|
||||
ALC_API ALCcontext * ALC_APIENTRY alcCreateContext( ALCdevice *device, const ALCint* attrlist ) OPENAL_DEPRECATED;
|
||||
|
||||
ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent( ALCcontext *context );
|
||||
ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent( ALCcontext *context ) OPENAL_DEPRECATED;
|
||||
|
||||
ALC_API void ALC_APIENTRY alcProcessContext( ALCcontext *context );
|
||||
ALC_API void ALC_APIENTRY alcProcessContext( ALCcontext *context ) OPENAL_DEPRECATED;
|
||||
|
||||
ALC_API void ALC_APIENTRY alcSuspendContext( ALCcontext *context );
|
||||
ALC_API void ALC_APIENTRY alcSuspendContext( ALCcontext *context ) OPENAL_DEPRECATED;
|
||||
|
||||
ALC_API void ALC_APIENTRY alcDestroyContext( ALCcontext *context );
|
||||
ALC_API void ALC_APIENTRY alcDestroyContext( ALCcontext *context ) OPENAL_DEPRECATED;
|
||||
|
||||
ALC_API ALCcontext * ALC_APIENTRY alcGetCurrentContext( void );
|
||||
ALC_API ALCcontext * ALC_APIENTRY alcGetCurrentContext( void ) OPENAL_DEPRECATED;
|
||||
|
||||
ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice( ALCcontext *context );
|
||||
ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice( ALCcontext *context ) OPENAL_DEPRECATED;
|
||||
|
||||
|
||||
/*
|
||||
* Device Management
|
||||
*/
|
||||
ALC_API ALCdevice * ALC_APIENTRY alcOpenDevice( const ALCchar *devicename );
|
||||
ALC_API ALCdevice * ALC_APIENTRY alcOpenDevice( const ALCchar *devicename ) OPENAL_DEPRECATED;
|
||||
|
||||
ALC_API ALCboolean ALC_APIENTRY alcCloseDevice( ALCdevice *device );
|
||||
ALC_API ALCboolean ALC_APIENTRY alcCloseDevice( ALCdevice *device ) OPENAL_DEPRECATED;
|
||||
|
||||
|
||||
/*
|
||||
* Error support.
|
||||
* Obtain the most recent Context error
|
||||
*/
|
||||
ALC_API ALCenum ALC_APIENTRY alcGetError( ALCdevice *device );
|
||||
ALC_API ALCenum ALC_APIENTRY alcGetError( ALCdevice *device ) OPENAL_DEPRECATED;
|
||||
|
||||
|
||||
/*
|
||||
@ -218,33 +223,33 @@ ALC_API ALCenum ALC_APIENTRY alcGetError( ALCdevice *device );
|
||||
* Query for the presence of an extension, and obtain any appropriate
|
||||
* function pointers and enum values.
|
||||
*/
|
||||
ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent( ALCdevice *device, const ALCchar *extname );
|
||||
ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent( ALCdevice *device, const ALCchar *extname ) OPENAL_DEPRECATED;
|
||||
|
||||
ALC_API void * ALC_APIENTRY alcGetProcAddress( ALCdevice *device, const ALCchar *funcname );
|
||||
ALC_API void * ALC_APIENTRY alcGetProcAddress( ALCdevice *device, const ALCchar *funcname ) OPENAL_DEPRECATED;
|
||||
|
||||
ALC_API ALCenum ALC_APIENTRY alcGetEnumValue( ALCdevice *device, const ALCchar *enumname );
|
||||
ALC_API ALCenum ALC_APIENTRY alcGetEnumValue( ALCdevice *device, const ALCchar *enumname ) OPENAL_DEPRECATED;
|
||||
|
||||
|
||||
/*
|
||||
* Query functions
|
||||
*/
|
||||
ALC_API const ALCchar * ALC_APIENTRY alcGetString( ALCdevice *device, ALCenum param );
|
||||
ALC_API const ALCchar * ALC_APIENTRY alcGetString( ALCdevice *device, ALCenum param ) OPENAL_DEPRECATED;
|
||||
|
||||
ALC_API void ALC_APIENTRY alcGetIntegerv( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *data );
|
||||
ALC_API void ALC_APIENTRY alcGetIntegerv( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *data ) OPENAL_DEPRECATED;
|
||||
|
||||
|
||||
/*
|
||||
* Capture functions
|
||||
*/
|
||||
ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize );
|
||||
ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize ) OPENAL_DEPRECATED;
|
||||
|
||||
ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice( ALCdevice *device );
|
||||
ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice( ALCdevice *device ) OPENAL_DEPRECATED;
|
||||
|
||||
ALC_API void ALC_APIENTRY alcCaptureStart( ALCdevice *device );
|
||||
ALC_API void ALC_APIENTRY alcCaptureStart( ALCdevice *device ) OPENAL_DEPRECATED;
|
||||
|
||||
ALC_API void ALC_APIENTRY alcCaptureStop( ALCdevice *device );
|
||||
ALC_API void ALC_APIENTRY alcCaptureStop( ALCdevice *device ) OPENAL_DEPRECATED;
|
||||
|
||||
ALC_API void ALC_APIENTRY alcCaptureSamples( ALCdevice *device, ALCvoid *buffer, ALCsizei samples );
|
||||
ALC_API void ALC_APIENTRY alcCaptureSamples( ALCdevice *device, ALCvoid *buffer, ALCsizei samples ) OPENAL_DEPRECATED;
|
||||
|
||||
/*
|
||||
* Pointer-to-function types, useful for dynamically getting ALC entry points.
|
||||
|
@ -36,11 +36,11 @@ extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ALUTAPI ALvoid ALUTAPIENTRY alutInit(ALint *argc,ALbyte **argv);
|
||||
ALUTAPI ALvoid ALUTAPIENTRY alutExit(ALvoid);
|
||||
ALUTAPI ALvoid ALUTAPIENTRY alutLoadWAVFile(ALbyte *file,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq);
|
||||
ALUTAPI ALvoid ALUTAPIENTRY alutLoadWAVMemory(ALbyte *memory,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq);
|
||||
ALUTAPI ALvoid ALUTAPIENTRY alutUnloadWAV(ALenum format,ALvoid *data,ALsizei size,ALsizei freq);
|
||||
ALUTAPI ALvoid ALUTAPIENTRY alutInit(ALint *argc,ALbyte **argv) OPENAL_DEPRECATED;
|
||||
ALUTAPI ALvoid ALUTAPIENTRY alutExit(ALvoid) OPENAL_DEPRECATED;
|
||||
ALUTAPI ALvoid ALUTAPIENTRY alutLoadWAVFile(ALbyte *file,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq) OPENAL_DEPRECATED;
|
||||
ALUTAPI ALvoid ALUTAPIENTRY alutLoadWAVMemory(ALbyte *memory,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq) OPENAL_DEPRECATED;
|
||||
ALUTAPI ALvoid ALUTAPIENTRY alutUnloadWAV(ALenum format,ALvoid *data,ALsizei size,ALsizei freq) OPENAL_DEPRECATED;
|
||||
|
||||
#ifdef TARGET_OS_MAC
|
||||
#if TARGET_OS_MAC
|
||||
|
@ -21,6 +21,7 @@
|
||||
*
|
||||
**********************************************************************************************************************************/
|
||||
|
||||
#import <AudioToolbox/AudioComponent.h>
|
||||
#include "OALCaptureDevice.h"
|
||||
|
||||
#define LOG_CAPTURE 0
|
||||
@ -101,7 +102,7 @@ OALCaptureDevice::~OALCaptureDevice()
|
||||
DebugMessageN1("OALCaptureDevice::~OALCaptureDevice() - OALCaptureDevice = %ld", (long int) mSelfToken);
|
||||
#endif
|
||||
if (mInputUnit)
|
||||
CloseComponent(mInputUnit);
|
||||
AudioComponentInstanceDispose(mInputUnit);
|
||||
if (mBufferData)
|
||||
free(mBufferData);
|
||||
delete mRingBuffer;
|
||||
@ -140,8 +141,8 @@ void OALCaptureDevice::InitializeAU(const char* inDeviceName)
|
||||
#endif
|
||||
// open input unit
|
||||
OSStatus result = noErr;
|
||||
Component comp;
|
||||
ComponentDescription desc;
|
||||
AudioComponent comp;
|
||||
AudioComponentDescription desc;
|
||||
|
||||
try {
|
||||
desc.componentType = kAudioUnitType_Output;
|
||||
@ -149,11 +150,11 @@ void OALCaptureDevice::InitializeAU(const char* inDeviceName)
|
||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
comp = FindNextComponent(NULL, &desc);
|
||||
comp = AudioComponentFindNext(NULL, &desc);
|
||||
if (comp == NULL)
|
||||
throw -1;
|
||||
|
||||
result = OpenAComponent(comp, &mInputUnit);
|
||||
result = AudioComponentInstanceNew(comp, &mInputUnit);
|
||||
THROW_RESULT
|
||||
|
||||
UInt32 enableIO;
|
||||
@ -207,11 +208,11 @@ void OALCaptureDevice::InitializeAU(const char* inDeviceName)
|
||||
|
||||
}
|
||||
catch (OSStatus result) {
|
||||
if (mInputUnit) CloseComponent(mInputUnit);
|
||||
if (mInputUnit) AudioComponentInstanceDispose(mInputUnit);
|
||||
throw result;
|
||||
}
|
||||
catch (...) {
|
||||
if (mInputUnit) CloseComponent(mInputUnit);
|
||||
if (mInputUnit) AudioComponentInstanceDispose(mInputUnit);
|
||||
throw - 1;
|
||||
}
|
||||
}
|
||||
|
@ -282,7 +282,7 @@ void OALContext::InitializeMixer(UInt32 inStereoBusCount)
|
||||
mSettableMixerAttenuationCurves = true;
|
||||
}
|
||||
|
||||
ComponentDescription mixerCD;
|
||||
AudioComponentDescription mixerCD;
|
||||
mixerCD.componentFlags = 0;
|
||||
mixerCD.componentFlagsMask = 0;
|
||||
mixerCD.componentType = kAudioUnitType_Mixer;
|
||||
@ -290,10 +290,10 @@ void OALContext::InitializeMixer(UInt32 inStereoBusCount)
|
||||
mixerCD.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
|
||||
// CREATE NEW NODE FOR THE GRAPH
|
||||
result = AUGraphNewNode (mOwningDevice->GetGraph(), &mixerCD, 0, NULL, &mMixerNode);
|
||||
result = AUGraphAddNode(mOwningDevice->GetGraph(), &mixerCD, &mMixerNode);
|
||||
THROW_RESULT
|
||||
|
||||
result = AUGraphGetNodeInfo (mOwningDevice->GetGraph(), mMixerNode, 0, 0, 0, &mMixerUnit);
|
||||
result = AUGraphNodeInfo(mOwningDevice->GetGraph(), mMixerNode, &mixerCD, &mMixerUnit);
|
||||
THROW_RESULT
|
||||
|
||||
// Get Default Distance Setting when the good 3DMixer is around
|
||||
|
@ -367,7 +367,7 @@ void OALDevice::InitializeGraph (const char* inDeviceName)
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~ SET UP OUTPUT NODE
|
||||
|
||||
ComponentDescription cd;
|
||||
AudioComponentDescription cd;
|
||||
cd.componentFlags = 0;
|
||||
cd.componentFlagsMask = 0;
|
||||
|
||||
@ -375,7 +375,7 @@ void OALDevice::InitializeGraph (const char* inDeviceName)
|
||||
cd.componentType = kAudioUnitType_Output;
|
||||
cd.componentSubType = kAudioUnitSubType_DefaultOutput;
|
||||
cd.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
result = AUGraphNewNode (mAUGraph, &cd, 0, NULL, &mOutputNode);
|
||||
result = AUGraphAddNode(mAUGraph, &cd, &mOutputNode);
|
||||
THROW_RESULT
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~ OPEN GRAPH
|
||||
@ -383,7 +383,7 @@ void OALDevice::InitializeGraph (const char* inDeviceName)
|
||||
result = AUGraphOpen (mAUGraph);
|
||||
THROW_RESULT
|
||||
|
||||
result = AUGraphGetNodeInfo (mAUGraph, mOutputNode, 0, 0, 0, &mOutputUnit);
|
||||
result = AUGraphNodeInfo (mAUGraph, mOutputNode, &cd, &mOutputUnit);
|
||||
THROW_RESULT
|
||||
|
||||
result = AudioUnitInitialize (mOutputUnit);
|
||||
|
@ -176,16 +176,24 @@ UInt32 Get3DMixerVersion ()
|
||||
|
||||
if (mixerVersion == kUnknown3DMixerVersion)
|
||||
{
|
||||
ComponentDescription mixerCD;
|
||||
mixerCD.componentFlags = 0;
|
||||
mixerCD.componentFlagsMask = 0;
|
||||
mixerCD.componentType = kAudioUnitType_Mixer;
|
||||
mixerCD.componentSubType = kAudioUnitSubType_3DMixer;
|
||||
mixerCD.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
|
||||
ComponentInstance mixerInstance = OpenComponent(FindNextComponent(0, &mixerCD));
|
||||
long version = CallComponentVersion(mixerInstance);
|
||||
CloseComponent(mixerInstance);
|
||||
AudioComponentDescription mixerDesc;
|
||||
UInt32 version = 0;
|
||||
|
||||
mixerDesc.componentType = kAudioUnitType_Mixer;
|
||||
mixerDesc.componentSubType = kAudioUnitSubType_3DMixer;
|
||||
mixerDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
mixerDesc.componentFlags = 0;
|
||||
mixerDesc.componentFlagsMask = 0;
|
||||
|
||||
AudioComponent auComp = AudioComponentFindNext(NULL, &mixerDesc);
|
||||
|
||||
if ( auComp )
|
||||
{
|
||||
if ( AudioComponentGetVersion(auComp, &version) != noErr )
|
||||
version = 0;
|
||||
|
||||
}
|
||||
|
||||
if (version < kMinimumMixerVersion)
|
||||
{
|
||||
@ -569,14 +577,14 @@ ALCint alcCheckUnitIsPresent(OSType componentSubType)
|
||||
{
|
||||
ALCint isPresent = kUnknownAUState;
|
||||
|
||||
ComponentDescription desc;
|
||||
AudioComponentDescription desc;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
desc.componentType = kAudioUnitType_Effect;
|
||||
desc.componentSubType = componentSubType;
|
||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
|
||||
isPresent = (FindNextComponent(0, &desc) != 0) ? kAUIsPresent : kAUIsNotPresent;
|
||||
isPresent = (AudioComponentFindNext(0, &desc) != 0) ? kAUIsPresent : kAUIsNotPresent;
|
||||
|
||||
return isPresent;
|
||||
}
|
||||
|
@ -37,42 +37,42 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
// added for OSX Extension
|
||||
ALC_API ALvoid alcMacOSXRenderingQuality (ALint value);
|
||||
ALC_API ALvoid alMacOSXRenderChannelCount (ALint value);
|
||||
ALC_API ALvoid alcMacOSXMixerMaxiumumBusses (ALint value);
|
||||
ALC_API ALvoid alcMacOSXMixerOutputRate(ALdouble value);
|
||||
ALC_API ALvoid alcMacOSXRenderingQuality (ALint value) OPENAL_DEPRECATED;
|
||||
ALC_API ALvoid alMacOSXRenderChannelCount (ALint value) OPENAL_DEPRECATED;
|
||||
ALC_API ALvoid alcMacOSXMixerMaxiumumBusses (ALint value) OPENAL_DEPRECATED;
|
||||
ALC_API ALvoid alcMacOSXMixerOutputRate(ALdouble value) OPENAL_DEPRECATED;
|
||||
|
||||
ALC_API ALint alcMacOSXGetRenderingQuality ();
|
||||
ALC_API ALint alMacOSXGetRenderChannelCount ();
|
||||
ALC_API ALint alcMacOSXGetMixerMaxiumumBusses ();
|
||||
ALC_API ALdouble alcMacOSXGetMixerOutputRate();
|
||||
ALC_API ALint alcMacOSXGetRenderingQuality () OPENAL_DEPRECATED;
|
||||
ALC_API ALint alMacOSXGetRenderChannelCount () OPENAL_DEPRECATED;
|
||||
ALC_API ALint alcMacOSXGetMixerMaxiumumBusses () OPENAL_DEPRECATED;
|
||||
ALC_API ALdouble alcMacOSXGetMixerOutputRate() OPENAL_DEPRECATED;
|
||||
|
||||
AL_API ALvoid AL_APIENTRY alSetInteger (ALenum pname, ALint value);
|
||||
AL_API ALvoid AL_APIENTRY alSetDouble (ALenum pname, ALdouble value);
|
||||
AL_API ALvoid AL_APIENTRY alSetInteger (ALenum pname, ALint value) OPENAL_DEPRECATED;
|
||||
AL_API ALvoid AL_APIENTRY alSetDouble (ALenum pname, ALdouble value) OPENAL_DEPRECATED;
|
||||
|
||||
AL_API ALvoid AL_APIENTRY alBufferDataStatic (ALint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq);
|
||||
AL_API ALvoid AL_APIENTRY alBufferDataStatic (ALint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq) OPENAL_DEPRECATED;
|
||||
|
||||
// source notifications
|
||||
AL_API ALenum alSourceAddNotification (ALuint sid, ALuint notificationID, alSourceNotificationProc notifyProc, ALvoid* userData);
|
||||
AL_API ALvoid alSourceRemoveNotification (ALuint sid, ALuint notificationID, alSourceNotificationProc notifyProc, ALvoid* userData);
|
||||
AL_API ALenum alSourceAddNotification (ALuint sid, ALuint notificationID, alSourceNotificationProc notifyProc, ALvoid* userData) OPENAL_DEPRECATED;
|
||||
AL_API ALvoid alSourceRemoveNotification (ALuint sid, ALuint notificationID, alSourceNotificationProc notifyProc, ALvoid* userData) OPENAL_DEPRECATED;
|
||||
|
||||
// source spatialization
|
||||
AL_API ALvoid alSourceRenderingQuality (ALuint sid, ALint value);
|
||||
AL_API ALint alSourceGetRenderingQuality (ALuint sid);
|
||||
AL_API ALvoid alSourceRenderingQuality (ALuint sid, ALint value) OPENAL_DEPRECATED;
|
||||
AL_API ALint alSourceGetRenderingQuality (ALuint sid) OPENAL_DEPRECATED;
|
||||
|
||||
// added for ASA (Apple Environmental Audio)
|
||||
|
||||
ALC_API ALenum alcASAGetSource(ALuint property, ALuint source, ALvoid *data, ALuint* dataSize);
|
||||
ALC_API ALenum alcASASetSource(ALuint property, ALuint source, ALvoid *data, ALuint dataSize);
|
||||
ALC_API ALenum alcASAGetListener(ALuint property, ALvoid *data, ALuint* dataSize);
|
||||
ALC_API ALenum alcASASetListener(ALuint property, ALvoid *data, ALuint dataSize);
|
||||
ALC_API ALenum alcASAGetSource(ALuint property, ALuint source, ALvoid *data, ALuint* dataSize) OPENAL_DEPRECATED;
|
||||
ALC_API ALenum alcASASetSource(ALuint property, ALuint source, ALvoid *data, ALuint dataSize) OPENAL_DEPRECATED;
|
||||
ALC_API ALenum alcASAGetListener(ALuint property, ALvoid *data, ALuint* dataSize) OPENAL_DEPRECATED;
|
||||
ALC_API ALenum alcASASetListener(ALuint property, ALvoid *data, ALuint dataSize) OPENAL_DEPRECATED;
|
||||
|
||||
// 3DMixer output capturer
|
||||
ALC_API ALvoid alcOutputCapturerPrepare( ALCuint frequency, ALCenum format, ALCsizei buffersize );
|
||||
ALC_API ALvoid alcOutputCapturerStart();
|
||||
ALC_API ALvoid alcOutputCapturerStop();
|
||||
ALC_API ALint alcOutputCapturerAvailableSamples();
|
||||
ALC_API ALvoid alcOutputCapturerSamples( ALCvoid *buffer, ALCsizei samples );
|
||||
ALC_API ALvoid alcOutputCapturerPrepare( ALCuint frequency, ALCenum format, ALCsizei buffersize ) OPENAL_DEPRECATED;
|
||||
ALC_API ALvoid alcOutputCapturerStart() OPENAL_DEPRECATED;
|
||||
ALC_API ALvoid alcOutputCapturerStop() OPENAL_DEPRECATED;
|
||||
ALC_API ALint alcOutputCapturerAvailableSamples() OPENAL_DEPRECATED;
|
||||
ALC_API ALvoid alcOutputCapturerSamples( ALCvoid *buffer, ALCsizei samples ) OPENAL_DEPRECATED;
|
||||
|
||||
// Used internally but no longer available via a header file. Some OpenAL applications may have been built with a header
|
||||
// that defined these constants so keep defining them.
|
||||
|
@ -603,7 +603,7 @@ ALUTAPI ALvoid ALUTAPIENTRY alutLoadWAVMemory(ALbyte *memory,ALenum *format,ALvo
|
||||
memset(*data,0,ChunkHdr.Size+31);
|
||||
}
|
||||
else{
|
||||
realloc(*data,ChunkHdr.Size + 31);
|
||||
*data = realloc(*data,ChunkHdr.Size + 31);
|
||||
memset(*data,0,ChunkHdr.Size+31);
|
||||
}
|
||||
if (*data)
|
||||
@ -782,42 +782,3 @@ AL_API ALvoid AL_APIENTRY alExit(void)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
#pragma mark ***** OALRingBuffer *****
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// count the leading zeroes in a word
|
||||
static __inline__ int CountLeadingZeroes(int arg) {
|
||||
|
||||
#if TARGET_CPU_X86 || TARGET_CPU_X86_64
|
||||
__asm__ volatile(
|
||||
"bsrl %0, %0\n\t"
|
||||
"movl $63, %%ecx\n\t"
|
||||
"cmove %%ecx, %0\n\t"
|
||||
"xorl $31, %0"
|
||||
: "=r" (arg)
|
||||
: "0" (arg)
|
||||
);
|
||||
#elif TARGET_CPU_PPC || TARGET_CPU_PPC64
|
||||
__asm__ volatile("cntlzw %0, %1" : "=r" (arg) : "r" (arg));
|
||||
#else
|
||||
#error "ERROR - assembly instructions for counting leading zeroes not present"
|
||||
#endif
|
||||
return arg;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// base 2 log of next power of two greater or equal to x
|
||||
inline UInt32 Log2Ceil(UInt32 x)
|
||||
{
|
||||
return 32 - CountLeadingZeroes(x - 1);
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// next power of two greater or equal to x
|
||||
inline UInt32 NextPowerOfTwo(UInt32 x)
|
||||
{
|
||||
return 1L << Log2Ceil(x);
|
||||
}
|
||||
|
@ -1635,7 +1635,7 @@ void OALSource::SetupRogerBeepAU()
|
||||
DebugMessageN1("OALSource::SetupRogerBeepAU called - OALSource = %ld\n", (long int) mSelfToken);
|
||||
#endif
|
||||
|
||||
ComponentDescription desc;
|
||||
AudioComponentDescription desc;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
desc.componentType = kAudioUnitType_Effect;
|
||||
@ -1643,10 +1643,10 @@ void OALSource::SetupRogerBeepAU()
|
||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
|
||||
// CREATE NEW NODE FOR THE GRAPH
|
||||
OSStatus result = AUGraphNewNode (mOwningContext->GetGraph(), &desc, 0, NULL, &mRogerBeepNode);
|
||||
OSStatus result = AUGraphAddNode(mOwningContext->GetGraph(), &desc, &mRogerBeepNode);
|
||||
THROW_RESULT
|
||||
|
||||
result = AUGraphGetNodeInfo (mOwningContext->GetGraph(), mRogerBeepNode, 0, 0, 0, &mRogerBeepAU);
|
||||
result = AUGraphNodeInfo (mOwningContext->GetGraph(), mRogerBeepNode, &desc, &mRogerBeepAU);
|
||||
THROW_RESULT
|
||||
}
|
||||
|
||||
@ -1655,7 +1655,7 @@ void OALSource::SetupDistortionAU()
|
||||
#if LOG_VERBOSE
|
||||
DebugMessageN1("OALSource::SetupDistortionAU called - OALSource = %ld\n", (long int) mSelfToken);
|
||||
#endif
|
||||
ComponentDescription desc;
|
||||
AudioComponentDescription desc;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
desc.componentType = kAudioUnitType_Effect;
|
||||
@ -1663,10 +1663,10 @@ void OALSource::SetupDistortionAU()
|
||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
|
||||
// CREATE NEW NODE FOR THE GRAPH
|
||||
OSStatus result = AUGraphNewNode (mOwningContext->GetGraph(), &desc, 0, NULL, &mDistortionNode);
|
||||
OSStatus result = AUGraphAddNode (mOwningContext->GetGraph(), &desc, &mDistortionNode);
|
||||
THROW_RESULT
|
||||
|
||||
result = AUGraphGetNodeInfo (mOwningContext->GetGraph(), mDistortionNode, 0, 0, 0, &mDistortionAU);
|
||||
result = AUGraphNodeInfo (mOwningContext->GetGraph(), mDistortionNode, &desc, &mDistortionAU);
|
||||
THROW_RESULT
|
||||
}
|
||||
|
||||
@ -1807,7 +1807,7 @@ void OALSource::Play()
|
||||
if(!mASADistortionEnable)
|
||||
{
|
||||
// connect render proc to unit if distortion is not enabled
|
||||
result = AUGraphGetNodeInfo (mOwningContext->GetGraph(), mRogerBeepNode, 0, 0, 0, &mRenderUnit);
|
||||
result = AUGraphNodeInfo (mOwningContext->GetGraph(), mRogerBeepNode, NULL, &mRenderUnit);
|
||||
THROW_RESULT;
|
||||
}
|
||||
}
|
||||
@ -1824,7 +1824,7 @@ void OALSource::Play()
|
||||
THROW_RESULT
|
||||
|
||||
// distortion unit will always be first if it exists
|
||||
result = AUGraphGetNodeInfo (mOwningContext->GetGraph(), mDistortionNode, 0, 0, 0, &mRenderUnit);
|
||||
result = AUGraphNodeInfo (mOwningContext->GetGraph(), mDistortionNode, NULL, &mRenderUnit);
|
||||
THROW_RESULT
|
||||
|
||||
if(mASARogerBeepEnable)
|
||||
|
@ -1,189 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#include "CAAUMIDIMap.h"
|
||||
#include <pthread.h>
|
||||
|
||||
struct AllMidiTransformers
|
||||
{
|
||||
MIDILinearTransformer linearTrans;
|
||||
MIDILogTransformer logTrans;
|
||||
MIDIExpTransformer expTrans;
|
||||
MIDISqrtTransformer sqrtTrans;
|
||||
MIDISquareTransformer squareTrans;
|
||||
MIDICubeRtTransformer cubeRtTrans;
|
||||
MIDICubeTransformer cubeTrans;
|
||||
};
|
||||
|
||||
AllMidiTransformers* gAllMidiTransformers = NULL;
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
static pthread_once_t sOnce = PTHREAD_ONCE_INIT;
|
||||
|
||||
static void InitAllMidiTransformers()
|
||||
{
|
||||
gAllMidiTransformers = new AllMidiTransformers();
|
||||
}
|
||||
|
||||
static void CheckInitAllMidiTransformers()
|
||||
{
|
||||
pthread_once(&sOnce, InitAllMidiTransformers);
|
||||
}
|
||||
#endif
|
||||
|
||||
MIDIValueTransformer * CAAUMIDIMap::GetTransformer (UInt32 inFlags)
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
if (gAllMidiTransformers == NULL)
|
||||
CheckInitAllMidiTransformers();
|
||||
#else
|
||||
if (gAllMidiTransformers == NULL)
|
||||
gAllMidiTransformers = new AllMidiTransformers();
|
||||
#endif
|
||||
|
||||
if (AudioUnitDisplayTypeIsLogarithmic(inFlags))
|
||||
return &gAllMidiTransformers->logTrans;
|
||||
else if (AudioUnitDisplayTypeIsExponential(inFlags))
|
||||
return &gAllMidiTransformers->expTrans;
|
||||
else if (AudioUnitDisplayTypeIsSquareRoot(inFlags))
|
||||
return &gAllMidiTransformers->sqrtTrans;
|
||||
else if (AudioUnitDisplayTypeIsSquared(inFlags))
|
||||
return &gAllMidiTransformers->squareTrans;
|
||||
else if (AudioUnitDisplayTypeIsCubed(inFlags))
|
||||
return &gAllMidiTransformers->cubeTrans;
|
||||
else if (AudioUnitDisplayTypeIsCubeRoot(inFlags))
|
||||
return &gAllMidiTransformers->cubeRtTrans;
|
||||
else
|
||||
return &gAllMidiTransformers->linearTrans;
|
||||
}
|
||||
|
||||
// The CALLER of this method must ensure that the status byte's MIDI Command matches!!!
|
||||
bool CAAUMIDIMap::MIDI_Matches (UInt8 inChannel, UInt8 inData1, UInt8 inData2, Float32 &outLinear) const
|
||||
{
|
||||
// see if the channels match first
|
||||
SInt8 chan = Channel();
|
||||
// channel matches (if chan is less than zero, "Any Channel" flag is set)
|
||||
if (chan >= 0 && chan != inChannel)
|
||||
return false;
|
||||
|
||||
// match the special cases first
|
||||
if (IsKeyEvent()) {
|
||||
// we're using this key event as an on/off type switch
|
||||
if (IsBipolar()) {
|
||||
if (IsKeyPressure()){
|
||||
if (IsBipolar_OnValue()) {
|
||||
if (inData2 > 63) {
|
||||
outLinear = 1;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (inData2 < 64) {
|
||||
outLinear = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (IsBipolar_OnValue()) {
|
||||
if (inData1 > 63) {
|
||||
outLinear = 1;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (inData1 < 64) {
|
||||
outLinear = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (IsAnyNote()) {
|
||||
// not quite sure how to interpret this...
|
||||
if (IsKeyPressure())
|
||||
outLinear = inData2 / 127.0;
|
||||
else
|
||||
outLinear = inData1 / 127.0;
|
||||
return true;
|
||||
}
|
||||
if (mData1 == inData1) {
|
||||
if (IsKeyPressure())
|
||||
outLinear = inData2 / 127.0;
|
||||
else
|
||||
outLinear = 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (IsControlChange()) {
|
||||
// controller ID matches
|
||||
if (mData1 == inData1) {
|
||||
if (IsBipolar()) {
|
||||
if (IsBipolar_OnValue()) {
|
||||
if (inData2 > 63) {
|
||||
outLinear = 1;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (inData2 < 64) {
|
||||
outLinear = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//printf("this in midi matches %X with ", this);
|
||||
outLinear = inData2 / 127.;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// this just matches on the patch change value itself...
|
||||
if (IsPatchChange()) {
|
||||
if (mData1 == inData1) {
|
||||
outLinear = 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// finally, for the other two, just check the bi-polar matching conditions
|
||||
// pitch bend and after touch
|
||||
if (IsBipolar()) {
|
||||
if (IsBipolar_OnValue()) {
|
||||
if (inData1 > 63) {
|
||||
outLinear = 1;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (inData1 < 64) {
|
||||
outLinear = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsPitchBend()) {
|
||||
UInt16 value = (inData2 << 7) | inData1;
|
||||
outLinear = value / 16383.;
|
||||
}
|
||||
else if (IsChannelPressure()) {
|
||||
outLinear = inData1 / 127.0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CAAUMIDIMap::Print () const
|
||||
{
|
||||
printf ("CAAUMIDIMap:%p, (%u/%u), mParamID %d, IsValid:%c, Status:0x%X, mData1 %d, Flags:0x%X\n", this, (unsigned int)mScope, (unsigned int)mElement, (int)mParameterID, (IsValid() ? 'T' : 'F'), mStatus, mData1, (int)mFlags);
|
||||
}
|
@ -1,503 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#ifndef __CAAUMIDIMap_h_
|
||||
#define __CAAUMIDIMap_h_
|
||||
|
||||
#include <AudioUnit/AudioUnitProperties.h>
|
||||
#include <algorithm>
|
||||
|
||||
/*
|
||||
enum {
|
||||
kAUParameterMIDIMapping_AnyChannelFlag = (1L << 0),
|
||||
// If this flag is set and mStatus is a MIDI channel message, then the MIDI channel number
|
||||
// in the status byte is ignored; the mapping is from the specified MIDI message on ANY channel.
|
||||
|
||||
kAUParameterMIDIMapping_AnyNoteFlag = (1L << 1),
|
||||
// If this flag is set and mStatus is a Note On, Note Off, or Polyphonic Pressure message,
|
||||
// the message's note number is ignored; the mapping is from ANY note number.
|
||||
|
||||
kAUParameterMIDIMapping_SubRange = (1L << 2),
|
||||
// set this flag if the midi control should map only to a sub-range of the parameter's value
|
||||
// then specify that range in the mSubRangeMin and mSubRangeMax members
|
||||
|
||||
kAUParameterMIDIMapping_Toggle = (1L << 3),
|
||||
// this is only useful for boolean typed parameters. When set, it means that the parameter's
|
||||
// value should be toggled (if true, become false and vice versa) when the represented MIDI message
|
||||
// is received
|
||||
|
||||
kAUParameterMIDIMapping_Bipolar = (1L << 4),
|
||||
// this can be set to when mapping a MIDI Controller to indicate that the parameter (typically a boolean
|
||||
// style parameter) will only have its value changed to either the on or off state of a MIDI controller message
|
||||
// (0 < 64 is off, 64 < 127 is on) such as the sustain pedal. The seeting of the next flag
|
||||
// (kAUParameterMIDIMapping_Bipolar_On) determine whether the parameter is mapped to the on or off
|
||||
// state of the controller
|
||||
kAUParameterMIDIMapping_Bipolar_On = (1L << 5)
|
||||
// only a valid flag if kAUParameterMIDIMapping_Bipolar is set
|
||||
};
|
||||
|
||||
// The reserved fields here are being used to reserve space (as well as align to 64 bit size) for future use
|
||||
// When/If these fields are used, the names of the fields will be changed to reflect their functionality
|
||||
// so, apps should NOT refer to these reserved fields directly by name
|
||||
typedef struct AUParameterMIDIMapping
|
||||
{
|
||||
AudioUnitScope mScope;
|
||||
AudioUnitElement mElement;
|
||||
AudioUnitParameterID mParameterID;
|
||||
UInt32 mFlags;
|
||||
Float32 mSubRangeMin;
|
||||
Float32 mSubRangeMax;
|
||||
UInt8 mStatus;
|
||||
UInt8 mData1;
|
||||
UInt8 reserved1; // MUST be set to zero
|
||||
UInt8 reserved2; // MUST be set to zero
|
||||
UInt32 reserved3; // MUST be set to zero
|
||||
} AUParameterMIDIMapping;
|
||||
*/
|
||||
|
||||
/*
|
||||
Parameter To MIDI Mapping Properties
|
||||
These properties are used to:
|
||||
Describe a current set of mappings between MIDI messages and Parameter value setting
|
||||
Create a mapping between a parameter and a MIDI message through either:
|
||||
- explicitly adding (or removing) the mapping
|
||||
- telling the AU to hot-map the next MIDI message to a specified Parameter
|
||||
The same MIDI Message can map to one or more parameters
|
||||
One Parameter can be mapped from multiple MIDI messages
|
||||
|
||||
In general usage, these properties only apply to AU's that implement the MIDI API
|
||||
AU Instruments (type=='aumu') and Music Effects (type == 'aumf')
|
||||
|
||||
These properties are used in the Global scope. The scope and element members of the structure describe
|
||||
the scope and element of the parameter. In all usages, mScope, mElement and mParameterID must be
|
||||
correctly specified.
|
||||
|
||||
|
||||
* The AUParameterMIDIMapping Structure
|
||||
|
||||
Command mStatus mData1
|
||||
Note Off 0x8n Note Num
|
||||
Note On 0x9n Note Num
|
||||
Key Pressure 0xAn Note Num
|
||||
Control Change 0xBn ControllerID
|
||||
Patch Change 0xCn Patch Num
|
||||
Channel Pressure DxDn 0 (Unused)
|
||||
Pitch Bend 0xEn 0 (Unused)
|
||||
|
||||
(where n is 0-0xF to correspond to MIDI channels 1-16)
|
||||
|
||||
Details:
|
||||
|
||||
In general MIDI Commands can be mapped to either a specific channel as specified in the mStatus bit.
|
||||
If the kAUParameterMIDIMapping_AnyChannelFlag bit is set mStatus is a MIDI channel message, then the
|
||||
MIDI channel number in the status byte is ignored; the mapping is from the specified MIDI message on ANY channel.
|
||||
|
||||
For note commands (note on, note off, key pressure), the MIDI message can trigger either with just a specific
|
||||
note number, or any note number if the kAUParameterMIDIMapping_AnyNoteFlag bit is set. In these instances, the
|
||||
note number is used as the trigger value (for instance, a note message could be used to set the
|
||||
cut off frequency of a filter).
|
||||
|
||||
The Properties:
|
||||
|
||||
kAudioUnitProperty_AllParameterMIDIMappings array of AUParameterMIDIMapping (read/write)
|
||||
This property is used to both retreive and set the current mapping state between (some/many/all of) its parameters
|
||||
and MIDI messages. When set, it should replace any previous mapped settings the AU had.
|
||||
|
||||
If this property is implemented by a non-MIDI capable AU (such as an 'aufx' type), then the property is
|
||||
read only, and recommends a suggested set of mappings for the host to perform. In this case, it is the
|
||||
host's responsibility to map MIDI message to the AU parameters. As described previously, there are a set
|
||||
of default mappings (see AudioToolbox/AUMIDIController.h) that the host can recommend to the user
|
||||
in this circumstance.
|
||||
|
||||
This property's size will be very dynamic, depending on the number of mappings currently in affect, so the
|
||||
caller should always get the size of the property first before retrieving it. The AU should return an error
|
||||
if the caller doesn't provide enough space to return all of the current mappings.
|
||||
|
||||
kAudioUnitProperty_AddParameterMIDIMapping array of AUParameterMIDIMapping (write only)
|
||||
This property is used to Add mappings to the existing set of mappings the AU possesses. It does NOT replace
|
||||
any existing mappings.
|
||||
|
||||
kAudioUnitProperty_RemoveParameterMIDIMapping array of AUParameterMIDIMapping (write only)
|
||||
This property is used to remove the specified mappings from the AU. If a mapping is specified that does not
|
||||
currently exist in the AU, then it should just be ignored.
|
||||
|
||||
kAudioUnitProperty_HotMapParameterMIDIMapping AUParameterMIDIMapping (read/write)
|
||||
This property is used in two ways, determined by the value supplied by the caller.
|
||||
(1) If a mapping struct is provided, then that struct provides *all* of the information that the AU should
|
||||
use to map the parameter, *except* for the MIDI message. The AU should then listen for the next MIDI message
|
||||
and associate that MIDI message with the supplied AUParameter mapping. When this MIDI message is received and
|
||||
the mapping made, the AU should also issue a notification on this property
|
||||
(kAudioUnitProperty_HotMapParameterMIDIMapping) to indicate to the host that the mapping has been made. The host
|
||||
can then retrieve the mapping that was made by getting the value of this property.
|
||||
|
||||
To avoid possible confusion, it is recommended that once the host has retrieved this mapping (if it is
|
||||
presenting a UI to describe the mappings for example), that it then clears the mapping state as described next.
|
||||
|
||||
Thus, the only time this property will return a valid value is when the AU has made a mapping. If the AU's mapping
|
||||
state has been cleared (or it has not been asked to make a mapping), then the AU should return
|
||||
kAudioUnitErr_InvalidPropertyValue if the host tries to read this value.
|
||||
|
||||
(2) If the value passed in is NULL, then if the AU had a parameter that it was in the process of mapping, it
|
||||
should disregard that (stop listening to the MIDI messages to create a mapping) and discard the partially
|
||||
mapped struct. If the value is NULL and the AU is not in the process of mapping, the AU can ignore the request.
|
||||
|
||||
At all times, the _AllMappings property will completely describe the current known state of the AU's mappings
|
||||
of MIDI messages to parameters.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
When mapping, it is recommended that LSB controllers are in general not mapped (ie. the controller range of 32 < 64)
|
||||
as many host parsers will map 14 bit control values. If you know (or can present an option) that the host deals with
|
||||
7 bit controllers only, then these controller ID's can be mapped of course.
|
||||
*/
|
||||
|
||||
|
||||
struct MIDIValueTransformer {
|
||||
virtual double tolinear(double) = 0;
|
||||
virtual double fromlinear(double) = 0;
|
||||
#if DEBUG
|
||||
// suppress warning
|
||||
virtual ~MIDIValueTransformer() { }
|
||||
#endif
|
||||
};
|
||||
|
||||
struct MIDILinearTransformer : public MIDIValueTransformer {
|
||||
virtual double tolinear(double x) { return x; }
|
||||
virtual double fromlinear(double x) { return x; }
|
||||
};
|
||||
|
||||
struct MIDILogTransformer : public MIDIValueTransformer {
|
||||
virtual double tolinear(double x) { return log(std::max(x, .00001)); }
|
||||
virtual double fromlinear(double x) { return exp(x); }
|
||||
};
|
||||
|
||||
struct MIDIExpTransformer : public MIDIValueTransformer {
|
||||
virtual double tolinear(double x) { return exp(x); }
|
||||
virtual double fromlinear(double x) { return log(std::max(x, .00001)); }
|
||||
};
|
||||
|
||||
struct MIDISqrtTransformer : public MIDIValueTransformer {
|
||||
virtual double tolinear(double x) { return x < 0. ? -(sqrt(-x)) : sqrt(x); }
|
||||
virtual double fromlinear(double x) { return x < 0. ? -(x * x) : x * x; }
|
||||
};
|
||||
|
||||
struct MIDISquareTransformer : public MIDIValueTransformer {
|
||||
virtual double tolinear(double x) { return x < 0. ? -(x * x) : x * x; }
|
||||
virtual double fromlinear(double x) { return x < 0. ? -(sqrt(-x)) : sqrt(x); }
|
||||
};
|
||||
|
||||
struct MIDICubeRtTransformer : public MIDIValueTransformer {
|
||||
virtual double tolinear(double x) { return x < 0. ? -(pow(-x, 1./3.)) : pow(x, 1./3.); }
|
||||
virtual double fromlinear(double x) { return x * x * x; }
|
||||
};
|
||||
|
||||
struct MIDICubeTransformer : public MIDIValueTransformer {
|
||||
virtual double tolinear(double x) { return x * x * x; }
|
||||
virtual double fromlinear(double x) { return x < 0. ? -(pow(-x, 1./3.)) : pow(x, 1./3.); }
|
||||
};
|
||||
|
||||
|
||||
class CAAUMIDIMap : public AUParameterMIDIMapping {
|
||||
|
||||
public:
|
||||
// variables for more efficient parsing of MIDI to Param value
|
||||
Float32 mMinValue;
|
||||
Float32 mMaxValue;
|
||||
MIDIValueTransformer *mTransType;
|
||||
|
||||
// methods
|
||||
static MIDIValueTransformer *GetTransformer (UInt32 inFlags);
|
||||
|
||||
CAAUMIDIMap() { memset(this, 0, sizeof(CAAUMIDIMap)); }
|
||||
CAAUMIDIMap (const AUParameterMIDIMapping& inMap)
|
||||
{
|
||||
memset(this, 0, sizeof(CAAUMIDIMap));
|
||||
memcpy (this, &inMap, sizeof(inMap));
|
||||
}
|
||||
CAAUMIDIMap (AudioUnitScope inScope, AudioUnitElement inElement, AudioUnitParameterID inParam)
|
||||
{
|
||||
memset(this, 0, sizeof(CAAUMIDIMap));
|
||||
mScope = inScope;
|
||||
mElement = inElement;
|
||||
mParameterID = inParam;
|
||||
}
|
||||
|
||||
|
||||
bool IsValid () const { return mStatus != 0; }
|
||||
|
||||
// returns -1 if any channel bit is set
|
||||
SInt32 Channel () const { return IsAnyChannel() ? -1 : (mStatus & 0xF); }
|
||||
bool IsAnyChannel () const {
|
||||
return mFlags & kAUParameterMIDIMapping_AnyChannelFlag;
|
||||
}
|
||||
// preserves the existing channel info in the status byte
|
||||
// preserves any previously set mFlags value
|
||||
void SetAnyChannel (bool inFlag)
|
||||
{
|
||||
if (inFlag)
|
||||
mFlags |= kAUParameterMIDIMapping_AnyChannelFlag;
|
||||
else
|
||||
mFlags &= ~kAUParameterMIDIMapping_AnyChannelFlag;
|
||||
}
|
||||
|
||||
bool IsAnyNote () const {
|
||||
return (mFlags & kAUParameterMIDIMapping_AnyNoteFlag) != 0;
|
||||
}
|
||||
// preserves the existing key num in the mData1 byte
|
||||
// preserves any previously set mFlags value
|
||||
void SetAnyNote (bool inFlag)
|
||||
{
|
||||
if (inFlag)
|
||||
mFlags |= kAUParameterMIDIMapping_AnyNoteFlag;
|
||||
else
|
||||
mFlags &= ~kAUParameterMIDIMapping_AnyNoteFlag;
|
||||
}
|
||||
|
||||
bool IsToggle() const { return (mFlags & kAUParameterMIDIMapping_Toggle) != 0; }
|
||||
void SetToggle (bool inFlag)
|
||||
{
|
||||
if (inFlag)
|
||||
mFlags |= kAUParameterMIDIMapping_Toggle;
|
||||
else
|
||||
mFlags &= ~kAUParameterMIDIMapping_Toggle;
|
||||
}
|
||||
|
||||
bool IsBipolar() const { return (mFlags & kAUParameterMIDIMapping_Bipolar) != 0; }
|
||||
// inUseOnValue is valid ONLY if inFlag is true
|
||||
void SetBipolar (bool inFlag, bool inUseOnValue = false)
|
||||
{
|
||||
if (inFlag) {
|
||||
mFlags |= kAUParameterMIDIMapping_Bipolar;
|
||||
if (inUseOnValue)
|
||||
mFlags |= kAUParameterMIDIMapping_Bipolar_On;
|
||||
else
|
||||
mFlags &= ~kAUParameterMIDIMapping_Bipolar_On;
|
||||
} else {
|
||||
mFlags &= ~kAUParameterMIDIMapping_Bipolar;
|
||||
mFlags &= ~kAUParameterMIDIMapping_Bipolar_On;
|
||||
}
|
||||
}
|
||||
bool IsBipolar_OnValue () const { return (mFlags & kAUParameterMIDIMapping_Bipolar_On) != 0; }
|
||||
|
||||
bool IsSubRange () const { return (mFlags & kAUParameterMIDIMapping_SubRange) != 0; }
|
||||
void SetSubRange (Float32 inStartValue, Float32 inStopValue)
|
||||
{
|
||||
mFlags |= kAUParameterMIDIMapping_SubRange;
|
||||
|
||||
mSubRangeMin = inStartValue;
|
||||
mSubRangeMax = inStopValue;
|
||||
}
|
||||
|
||||
void SetParamRange(Float32 minValue, Float32 maxValue)
|
||||
{
|
||||
mMinValue = minValue;
|
||||
mMaxValue = maxValue;
|
||||
}
|
||||
|
||||
// this will retain the subrange values previously set.
|
||||
void SetSubRange (bool inFlag)
|
||||
{
|
||||
if (inFlag)
|
||||
mFlags |= kAUParameterMIDIMapping_SubRange;
|
||||
else
|
||||
mFlags &= ~kAUParameterMIDIMapping_SubRange;
|
||||
}
|
||||
|
||||
bool IsAnyValue() const{return !IsBipolar();}
|
||||
bool IsOnValue() const{return IsBipolar_OnValue();}
|
||||
bool IsOffValue() const{return IsBipolar();}
|
||||
|
||||
bool IsNoteOff () const { return ((mStatus & 0xF0) == 0x80); }
|
||||
bool IsNoteOn () const { return ((mStatus & 0xF0) == 0x90); }
|
||||
|
||||
bool IsKeyPressure () const { return ((mStatus & 0xF0) == 0xA0); }
|
||||
|
||||
bool IsKeyEvent () const { return (mStatus > 0x7F) && (mStatus < 0xB0); }
|
||||
|
||||
bool IsPatchChange () const { return ((mStatus & 0xF0) == 0xC0); }
|
||||
bool IsChannelPressure () const { return ((mStatus & 0xF0) == 0xD0); }
|
||||
bool IsPitchBend () const { return ((mStatus & 0xF0) == 0xE0); }
|
||||
bool IsControlChange () const { return ((mStatus & 0xF0) == 0xB0); }
|
||||
|
||||
|
||||
void SetControllerOnValue(){SetBipolar(true,true);}
|
||||
void SetControllerOffValue(){SetBipolar(true,false);}
|
||||
void SetControllerAnyValue(){SetBipolar(false,false);}
|
||||
|
||||
// All of these Set calls will reset the mFlags field based on the
|
||||
// anyChannel param value
|
||||
void SetNoteOff (UInt8 key, SInt8 channel, bool anyChannel = false)
|
||||
{
|
||||
mStatus = 0x80 | (channel & 0xF);
|
||||
mData1 = key;
|
||||
mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
|
||||
|
||||
}
|
||||
|
||||
void SetNoteOn (UInt8 key, SInt8 channel, bool anyChannel = false)
|
||||
{
|
||||
mStatus = 0x90 | (channel & 0xF);
|
||||
mData1 = key;
|
||||
mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
|
||||
}
|
||||
|
||||
void SetPolyKey (UInt8 key, SInt8 channel, bool anyChannel = false)
|
||||
{
|
||||
mStatus = 0xA0 | (channel & 0xF);
|
||||
mData1 = key;
|
||||
mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
|
||||
}
|
||||
|
||||
void SetControlChange (UInt8 controllerID, SInt8 channel, bool anyChannel = false)
|
||||
{
|
||||
mStatus = 0xB0 | (channel & 0xF);
|
||||
mData1 = controllerID;
|
||||
mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
|
||||
}
|
||||
|
||||
void SetPatchChange (UInt8 patchChange, SInt8 channel, bool anyChannel = false)
|
||||
{
|
||||
mStatus = 0xC0 | (channel & 0xF);
|
||||
mData1 = patchChange;
|
||||
mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
|
||||
}
|
||||
|
||||
void SetChannelPressure (SInt8 channel, bool anyChannel = false)
|
||||
{
|
||||
mStatus = 0xD0 | (channel & 0xF);
|
||||
mData1 = 0;
|
||||
mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
|
||||
}
|
||||
|
||||
void SetPitchBend (SInt8 channel, bool anyChannel = false)
|
||||
{
|
||||
mStatus = 0xE0 | (channel & 0xF);
|
||||
mData1 = 0;
|
||||
mFlags = (anyChannel ? kAUParameterMIDIMapping_AnyChannelFlag : 0);
|
||||
}
|
||||
|
||||
|
||||
Float32 ParamValueFromMIDILinear (Float32 inLinearValue) const
|
||||
{
|
||||
Float32 low, high;
|
||||
if (IsSubRange()){
|
||||
low = mSubRangeMin;
|
||||
high = mSubRangeMax;
|
||||
}
|
||||
else {
|
||||
low = mMinValue;
|
||||
high = mMaxValue;
|
||||
}
|
||||
|
||||
|
||||
// WE ARE ASSUMING YOU HAVE SET THIS UP PROPERLY!!!!! (or this will crash cause it will be NULL)
|
||||
return (Float32)mTransType->fromlinear((inLinearValue * (high - low)) + low);
|
||||
}
|
||||
|
||||
|
||||
// The CALLER of this method must ensure that the status byte's MIDI Command (ignoring the channel) matches!!!
|
||||
bool MIDI_Matches (UInt8 inChannel, UInt8 inData1, UInt8 inData2, Float32 &outLinear) const;
|
||||
|
||||
void Print () const;
|
||||
|
||||
void Save (CFPropertyListRef &outData) const;
|
||||
void Restore (CFDictionaryRef inData);
|
||||
|
||||
static void SaveAsMapPList (AudioUnit inUnit,
|
||||
const AUParameterMIDIMapping * inMappings,
|
||||
UInt32 inNumMappings,
|
||||
CFPropertyListRef &outData,
|
||||
CFStringRef inName = NULL);
|
||||
|
||||
// inNumMappings describes how much memory is allocated in outMappings
|
||||
static void RestoreFromMapPList (const CFDictionaryRef inData,
|
||||
AUParameterMIDIMapping * outMappings,
|
||||
UInt32 inNumMappings);
|
||||
|
||||
static UInt32 NumberOfMaps (const CFDictionaryRef inData);
|
||||
};
|
||||
|
||||
|
||||
// these sorting operations sort for run-time efficiency based on the MIDI messages
|
||||
inline bool operator== (const CAAUMIDIMap &a, const CAAUMIDIMap &b)
|
||||
{
|
||||
// ignore channel first
|
||||
return (((a.mStatus & 0xF0) == (b.mStatus & 0xF0))
|
||||
&& (a.mData1 == b.mData1)
|
||||
&& ((a.mStatus & 0xF) == (b.mStatus & 0xf)) // now compare the channel
|
||||
&& (a.mParameterID == b.mParameterID)
|
||||
&& (a.mElement == b.mElement)
|
||||
&& (a.mScope == b.mScope));
|
||||
|
||||
// reserved field comparisons - ignored until/if they are used
|
||||
}
|
||||
|
||||
inline bool operator< (const CAAUMIDIMap &a, const CAAUMIDIMap &b)
|
||||
{
|
||||
if ((a.mStatus & 0xF0) != (b.mStatus & 0xF0))
|
||||
return ((a.mStatus & 0xF0) < (b.mStatus & 0xF0));
|
||||
|
||||
if (a.mData1 != b.mData1)
|
||||
return (a.mData1 < b.mData1);
|
||||
|
||||
if ((a.mStatus & 0xF) != (b.mStatus & 0xf)) // now compare the channel
|
||||
return ((a.mStatus & 0xF) < (b.mStatus & 0xf));
|
||||
|
||||
// reserved field comparisons - ignored until/if they are used
|
||||
|
||||
// we're sorting this by MIDI, so we don't really care how the rest is sorted
|
||||
return ((a.mParameterID < b.mParameterID)
|
||||
&& (a.mElement < b.mElement)
|
||||
&& (a.mScope < b.mScope));
|
||||
}
|
||||
|
||||
|
||||
|
||||
class CompareMIDIMap {
|
||||
int compare (const CAAUMIDIMap &a, const CAAUMIDIMap &b)
|
||||
{
|
||||
if ((a.mStatus & 0xF0) < (b.mStatus & 0xF0))
|
||||
return -1;
|
||||
if ((a.mStatus & 0xF0) > (b.mStatus & 0xF0))
|
||||
return 1;
|
||||
|
||||
// note event
|
||||
if (a.mStatus < 0xB0 || a.mStatus >= 0xD0)
|
||||
return 0;
|
||||
if (a.mData1 > b.mData1) return 1;
|
||||
if (a.mData1 < b.mData1) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public:
|
||||
bool operator() (const CAAUMIDIMap &a, const CAAUMIDIMap &b) {
|
||||
return compare (a, b) < 0;
|
||||
}
|
||||
bool Finish (const CAAUMIDIMap &a, const CAAUMIDIMap &b) {
|
||||
return compare (a, b) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
usage: To find potential mapped events for a given status byte, where mMMapEvents is a sorted vec
|
||||
CompareMIDIMap comparObj;
|
||||
sortVecIter lower_iter = std::lower_bound(mMMapEvents.begin(), mMMapEvents.end(), inStatusByte, compareObj);
|
||||
for (;lower_iter < mMMapEvents.end(); ++lower_iter) {
|
||||
// then, see if we go out of the status byte range, using the Finish method
|
||||
if (compareObj.Finish(map, tempMap)) // tempMap is a CAAUMIDIMap object with the status/dataByte 1 set
|
||||
break;
|
||||
// ...
|
||||
}
|
||||
|
||||
in the for loop you call the MIDI_Matches call, to see if the MIDI event matches a given AUMIDIParam mapping
|
||||
special note: you HAVE to transform note on (with vel zero) events to the note off status byte
|
||||
*/
|
||||
|
||||
#endif
|
@ -1,195 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#include "CAAUMIDIMapManager.h"
|
||||
#include <AudioToolbox/AudioUnitUtilities.h>
|
||||
|
||||
CAAUMIDIMapManager::CAAUMIDIMapManager()
|
||||
{
|
||||
hotMapping = false;
|
||||
}
|
||||
|
||||
static void FillInMap (CAAUMIDIMap &map, AUBase &That)
|
||||
{
|
||||
AudioUnitParameterInfo info;
|
||||
That.GetParameterInfo (map.mScope, map.mParameterID, info);
|
||||
|
||||
if (map.IsSubRange()) {
|
||||
map.mMinValue = map.mSubRangeMin;
|
||||
map.mMaxValue = map.mSubRangeMax;
|
||||
} else {
|
||||
map.mMinValue = info.minValue;
|
||||
map.mMaxValue = info.maxValue;
|
||||
}
|
||||
|
||||
map.mTransType = CAAUMIDIMap::GetTransformer(info.flags);
|
||||
}
|
||||
|
||||
OSStatus CAAUMIDIMapManager::SortedInsertToParamaterMaps (AUParameterMIDIMapping *maps, UInt32 inNumMaps, AUBase &That)
|
||||
{
|
||||
for (unsigned int i = 0; i < inNumMaps; ++i)
|
||||
{
|
||||
CAAUMIDIMap map(maps[i]);
|
||||
|
||||
FillInMap (map, That);
|
||||
|
||||
int idx = FindParameterIndex (maps[i]);
|
||||
if (idx > -1)
|
||||
mParameterMaps.erase(mParameterMaps.begin() + idx);
|
||||
|
||||
// least disruptive place to put this is at the end
|
||||
mParameterMaps.push_back(map);
|
||||
}
|
||||
|
||||
std::sort(mParameterMaps.begin(), mParameterMaps.end(), CompareMIDIMap());
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
void CAAUMIDIMapManager::GetHotParameterMap(AUParameterMIDIMapping &outMap )
|
||||
{
|
||||
outMap = mHotMap;
|
||||
}
|
||||
|
||||
void CAAUMIDIMapManager::SortedRemoveFromParameterMaps(AUParameterMIDIMapping *maps, UInt32 inNumMaps, bool &outMapDidChange)
|
||||
{
|
||||
if (hotMapping) {
|
||||
hotMapping = false;
|
||||
}
|
||||
|
||||
outMapDidChange = false;
|
||||
for (unsigned int i = 0; i < inNumMaps; ++i) {
|
||||
int idx = FindParameterIndex (maps[i]);
|
||||
if (idx > -1) {
|
||||
//mParameterMaps[idx].Print();
|
||||
mParameterMaps.erase(mParameterMaps.begin() + idx);
|
||||
outMapDidChange = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CAAUMIDIMapManager::ReplaceAllMaps (AUParameterMIDIMapping* inMappings, UInt32 inNumMaps, AUBase &That)
|
||||
{
|
||||
mParameterMaps.clear();
|
||||
|
||||
for (unsigned int i = 0; i < inNumMaps; ++i) {
|
||||
CAAUMIDIMap mapping(inMappings[i]);
|
||||
|
||||
FillInMap (mapping, That);
|
||||
mParameterMaps.push_back (mapping);
|
||||
}
|
||||
|
||||
std::sort(mParameterMaps.begin(),mParameterMaps.end(), CompareMIDIMap());
|
||||
}
|
||||
|
||||
bool CAAUMIDIMapManager::HandleHotMapping(UInt8 inStatus,
|
||||
UInt8 inChannel,
|
||||
UInt8 inData1,
|
||||
AUBase &That)
|
||||
{ //used to set the hot map info
|
||||
|
||||
if (inStatus == 0xf0) return false;
|
||||
|
||||
if (!hotMapping) return false;
|
||||
hotMapping = false;
|
||||
|
||||
mHotMap.mStatus = inStatus | inChannel;
|
||||
mHotMap.mData1 = inData1;
|
||||
|
||||
SortedInsertToParamaterMaps (&mHotMap, 1, That);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
void CAAUMIDIMapManager::Print()
|
||||
{
|
||||
for ( ParameterMaps::iterator i = mParameterMaps.begin(); i < mParameterMaps.end(); ++i) {
|
||||
CAAUMIDIMap* listmap = &(*i);
|
||||
listmap->Print();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
void CAAUMIDIMapManager::GetMaps(AUParameterMIDIMapping* maps)
|
||||
{
|
||||
int i = 0;
|
||||
for ( ParameterMaps::iterator iter = mParameterMaps.begin(); iter < mParameterMaps.end(); ++iter, ++i) {
|
||||
AUParameterMIDIMapping &listmap = (*iter);
|
||||
maps[i] = listmap;
|
||||
}
|
||||
}
|
||||
|
||||
int CAAUMIDIMapManager::FindParameterIndex (AUParameterMIDIMapping &inMap)
|
||||
{
|
||||
//used to get back hot mapping and one at a time maps, for ui
|
||||
|
||||
int idx = 0;
|
||||
for ( ParameterMaps::iterator i = mParameterMaps.begin(); i < mParameterMaps.end(); ++i) {
|
||||
CAAUMIDIMap & listmap = (*i);
|
||||
if ( (listmap.mParameterID == inMap.mParameterID) &&
|
||||
(listmap.mScope == inMap.mScope) &&
|
||||
(listmap.mElement == inMap.mElement) )
|
||||
{
|
||||
return idx;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool CAAUMIDIMapManager::FindParameterMapEventMatch( UInt8 inStatus,
|
||||
UInt8 inChannel,
|
||||
UInt8 inData1,
|
||||
UInt8 inData2,
|
||||
UInt32 inBufferOffset,
|
||||
AUBase& inAUBase)
|
||||
{
|
||||
bool ret_value = false;
|
||||
|
||||
if (inStatus == 0x90 && !inData2)
|
||||
inStatus = 0x80 | inChannel;
|
||||
|
||||
//used to test for midi matches once map is made
|
||||
CAAUMIDIMap tempMap;
|
||||
tempMap.mStatus = inStatus | inChannel;
|
||||
tempMap.mData1 = inData1;
|
||||
|
||||
CompareMIDIMap compareObj;
|
||||
|
||||
AudioUnitEvent event;
|
||||
event.mEventType = kAudioUnitEvent_ParameterValueChange;
|
||||
event.mArgument.mParameter.mAudioUnit = inAUBase.GetComponentInstance();
|
||||
|
||||
ParameterMaps::iterator lower_iter =
|
||||
std::lower_bound(mParameterMaps.begin(), mParameterMaps.end(), tempMap, compareObj);
|
||||
|
||||
while (lower_iter < mParameterMaps.end())
|
||||
{
|
||||
CAAUMIDIMap & map = (*lower_iter);
|
||||
if (compareObj.Finish(map, tempMap))
|
||||
break;
|
||||
|
||||
Float32 value;
|
||||
if (map.MIDI_Matches(inChannel, inData1, inData2, value))
|
||||
{
|
||||
inAUBase.SetParameter ( map.mParameterID, map.mScope, map.mElement,
|
||||
map.ParamValueFromMIDILinear(value), inBufferOffset);
|
||||
|
||||
event.mArgument.mParameter.mParameterID = map.mParameterID;
|
||||
event.mArgument.mParameter.mScope = map.mScope;
|
||||
event.mArgument.mParameter.mElement = map.mElement;
|
||||
|
||||
AUEventListenerNotify(NULL, NULL, &event);
|
||||
ret_value = true;
|
||||
}
|
||||
++lower_iter;
|
||||
}
|
||||
return ret_value;
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#ifndef __CAAUMIDIMapManager_h_
|
||||
#define __CAAUMIDIMapManager_h_
|
||||
|
||||
#include "AUBase.h"
|
||||
#include "CAAUMIDIMap.h"
|
||||
#include <vector>
|
||||
#include <AudioToolbox/AudioUnitUtilities.h>
|
||||
|
||||
class CAAUMIDIMapManager {
|
||||
|
||||
protected:
|
||||
|
||||
typedef std::vector<CAAUMIDIMap> ParameterMaps;
|
||||
ParameterMaps mParameterMaps;
|
||||
|
||||
bool hotMapping;
|
||||
AUParameterMIDIMapping mHotMap;
|
||||
|
||||
public:
|
||||
|
||||
CAAUMIDIMapManager();
|
||||
|
||||
UInt32 NumMaps(){return static_cast<UInt32>(mParameterMaps.size());}
|
||||
void GetMaps(AUParameterMIDIMapping* maps);
|
||||
|
||||
int FindParameterIndex(AUParameterMIDIMapping &map);
|
||||
|
||||
void GetHotParameterMap(AUParameterMIDIMapping &outMap);
|
||||
|
||||
void SortedRemoveFromParameterMaps (AUParameterMIDIMapping *maps, UInt32 inNumMaps, bool &outMapDidChange);
|
||||
OSStatus SortedInsertToParamaterMaps (AUParameterMIDIMapping *maps, UInt32 inNumMaps, AUBase &That);
|
||||
|
||||
void ReplaceAllMaps (AUParameterMIDIMapping* inMappings, UInt32 inNumMaps, AUBase &That);
|
||||
|
||||
bool IsHotMapping(){return hotMapping;}
|
||||
void SetHotMapping (AUParameterMIDIMapping &inMap){hotMapping = true; mHotMap = inMap; }
|
||||
|
||||
bool HandleHotMapping( UInt8 inStatus,
|
||||
UInt8 inChannel,
|
||||
UInt8 inData1,
|
||||
AUBase &That);
|
||||
|
||||
|
||||
bool FindParameterMapEventMatch(UInt8 inStatus,
|
||||
UInt8 inChannel,
|
||||
UInt8 inData1,
|
||||
UInt8 inData2,
|
||||
UInt32 inBufferOffset,
|
||||
AUBase& inAUBase);
|
||||
#if DEBUG
|
||||
void Print();
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#endif
|
268
extra/CAAtomic.h
268
extra/CAAtomic.h
@ -1,268 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
/*
|
||||
This file implements all Atomic operations using Interlocked functions specified in
|
||||
Winbase.h
|
||||
NOTE: According to Microsoft documentation, all Interlocked functions generates a
|
||||
full barrier.
|
||||
On Windows:
|
||||
As the Interlocked functions returns the Old value, Extra checks and operations
|
||||
are made after the atomic operation to return value consistent with OSX counterparts.
|
||||
*/
|
||||
|
||||
#ifndef __CAAtomic_h__
|
||||
#define __CAAtomic_h__
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
#include <windows.h>
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_InterlockedOr)
|
||||
#pragma intrinsic(_InterlockedAnd)
|
||||
#else
|
||||
#include <CoreFoundation/CFBase.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
#endif
|
||||
|
||||
inline void CAMemoryBarrier()
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
MemoryBarrier();
|
||||
#else
|
||||
OSMemoryBarrier();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline SInt32 CAAtomicAdd32Barrier(SInt32 theAmt, volatile SInt32* theValue)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
long lRetVal = InterlockedExchangeAdd((volatile long*)theValue, theAmt);
|
||||
// InterlockedExchangeAdd returns the original value which differs from OSX version.
|
||||
// At this point the addition would have occured and hence returning the new value
|
||||
// to keep it sync with OSX.
|
||||
return lRetVal + theAmt;
|
||||
#else
|
||||
return OSAtomicAdd32Barrier(theAmt, (volatile int32_t *)theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline SInt32 CAAtomicOr32Barrier(UInt32 theMask, volatile UInt32* theValue)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
// InterlockedAnd macro is not defined in x86 platform, and hence using the intrinsic
|
||||
// function instead.
|
||||
long j = _InterlockedOr((volatile long*)theValue, theMask);
|
||||
// _InterlockedOr returns the original value which differs from OSX version.
|
||||
// Returning the new value similar to OSX
|
||||
return (SInt32)(j | theMask);
|
||||
#else
|
||||
return OSAtomicOr32Barrier(theMask, (volatile uint32_t *)theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline SInt32 CAAtomicAnd32Barrier(UInt32 theMask, volatile UInt32* theValue)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
// InterlockedAnd macro is not defined in x86 platform, and hence using the intrinsic
|
||||
// function instead.
|
||||
long j = _InterlockedAnd((volatile long*)theValue, theMask);
|
||||
// _InterlockedAnd returns the original value which differs from OSX version.
|
||||
// Returning the new value similar to OSX
|
||||
return (SInt32)(j & theMask);
|
||||
#else
|
||||
return OSAtomicAnd32Barrier(theMask, (volatile uint32_t *)theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool CAAtomicCompareAndSwap32Barrier(SInt32 oldValue, SInt32 newValue, volatile SInt32 *theValue)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
// InterlockedCompareExchange returns the old value. But we need to return bool value.
|
||||
long lRetVal = InterlockedCompareExchange((volatile long*)theValue, newValue, oldValue);
|
||||
// Hence we check if the new value is set and if it is we return true else false.
|
||||
// If theValue is equal to oldValue then the swap happens. Otherwise swap doesn't happen.
|
||||
return (oldValue == lRetVal);
|
||||
#else
|
||||
return OSAtomicCompareAndSwap32Barrier(oldValue, newValue, (volatile int32_t *)theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
inline SInt32 CAAtomicIncrement32(volatile SInt32* theValue)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
return (SInt32)InterlockedIncrement((volatile long*)theValue);
|
||||
#else
|
||||
return OSAtomicIncrement32((volatile int32_t *)theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline SInt32 CAAtomicDecrement32(volatile SInt32* theValue)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
return (SInt32)InterlockedDecrement((volatile long*)theValue);
|
||||
#else
|
||||
return OSAtomicDecrement32((volatile int32_t *)theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline SInt32 CAAtomicIncrement32Barrier(volatile SInt32* theValue)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
return CAAtomicIncrement32(theValue);
|
||||
#else
|
||||
return OSAtomicIncrement32Barrier((volatile int32_t *)theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline SInt32 CAAtomicDecrement32Barrier(volatile SInt32* theValue)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
return CAAtomicDecrement32(theValue);
|
||||
#else
|
||||
return OSAtomicDecrement32Barrier((volatile int32_t *)theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool CAAtomicTestAndClearBarrier(int bitToClear, void* theAddress)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
BOOL bOldVal = InterlockedBitTestAndReset((long*)theAddress, bitToClear);
|
||||
return (bOldVal ? true : false);
|
||||
#else
|
||||
return OSAtomicTestAndClearBarrier(bitToClear, (volatile void *)theAddress);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool CAAtomicTestAndClear(int bitToClear, void* theAddress)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
BOOL bOldVal = CAAtomicTestAndClearBarrier(bitToClear, (long*)theAddress);
|
||||
return (bOldVal ? true : false);
|
||||
#else
|
||||
return OSAtomicTestAndClear(bitToClear, (volatile void *)theAddress);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool CAAtomicTestAndSetBarrier(int bitToSet, void* theAddress)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
BOOL bOldVal = InterlockedBitTestAndSet((long*)theAddress, bitToSet);
|
||||
return (bOldVal ? true : false);
|
||||
#else
|
||||
return OSAtomicTestAndSetBarrier(bitToSet, (volatile void *)theAddress);
|
||||
#endif
|
||||
}
|
||||
|
||||
// int32_t flavors -- for C++ only since we can't overload in C
|
||||
// CFBase.h defines SInt32 as signed int which is similar to int32_t. If CFBase.h is included, then
|
||||
// this will generate redefinition error. But on Mac, CFBase.h, still includes MacTypes.h where
|
||||
// SInt32 is defined as signed long so this would work there.
|
||||
// So in order to fix the redefinition errors, we define these functions only if MacTypes.h is included.
|
||||
#if defined(__cplusplus) && defined(__MACTYPES__) && !__LP64__
|
||||
inline int32_t CAAtomicAdd32Barrier(int32_t theAmt, volatile int32_t* theValue)
|
||||
{
|
||||
return CAAtomicAdd32Barrier(theAmt, (volatile SInt32 *)theValue);
|
||||
}
|
||||
|
||||
inline int32_t CAAtomicOr32Barrier(uint32_t theMask, volatile uint32_t* theValue)
|
||||
{
|
||||
return CAAtomicOr32Barrier(theMask, (volatile UInt32 *)theValue);
|
||||
}
|
||||
|
||||
inline int32_t CAAtomicAnd32Barrier(uint32_t theMask, volatile uint32_t* theValue)
|
||||
{
|
||||
return CAAtomicAnd32Barrier(theMask, (volatile UInt32 *)theValue);
|
||||
}
|
||||
|
||||
inline bool CAAtomicCompareAndSwap32Barrier(int32_t oldValue, int32_t newValue, volatile int32_t *theValue)
|
||||
{
|
||||
return CAAtomicCompareAndSwap32Barrier(oldValue, newValue, (volatile SInt32 *)theValue);
|
||||
}
|
||||
|
||||
inline int32_t CAAtomicIncrement32(volatile int32_t* theValue)
|
||||
{
|
||||
return CAAtomicIncrement32((volatile SInt32 *)theValue);
|
||||
}
|
||||
|
||||
inline int32_t CAAtomicDecrement32(volatile int32_t* theValue)
|
||||
{
|
||||
return CAAtomicDecrement32((volatile SInt32 *)theValue);
|
||||
}
|
||||
|
||||
inline int32_t CAAtomicIncrement32Barrier(volatile int32_t* theValue)
|
||||
{
|
||||
return CAAtomicIncrement32Barrier((volatile SInt32 *)theValue);
|
||||
}
|
||||
|
||||
inline int32_t CAAtomicDecrement32Barrier(volatile int32_t* theValue)
|
||||
{
|
||||
return CAAtomicDecrement32Barrier((volatile SInt32 *)theValue);
|
||||
}
|
||||
#endif // __cplusplus && !__LP64__
|
||||
|
||||
#if __LP64__
|
||||
inline bool CAAtomicCompareAndSwap64Barrier( int64_t __oldValue, int64_t __newValue, volatile int64_t *__theValue )
|
||||
{
|
||||
return OSAtomicCompareAndSwap64Barrier(__oldValue, __newValue, __theValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline bool CAAtomicCompareAndSwapPtrBarrier(void *__oldValue, void *__newValue, volatile void ** __theValue)
|
||||
{
|
||||
#if __LP64__
|
||||
return CAAtomicCompareAndSwap64Barrier((int64_t)__oldValue, (int64_t)__newValue, (int64_t *)__theValue);
|
||||
#else
|
||||
return CAAtomicCompareAndSwap32Barrier((int32_t)__oldValue, (int32_t)__newValue, (int32_t *)__theValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Spinlocks. These use memory barriers as required to synchronize access to shared
|
||||
* memory protected by the lock. The lock operation spins, but employs various strategies
|
||||
* to back off if the lock is held, making it immune to most priority-inversion livelocks.
|
||||
* The try operation immediately returns false if the lock was held, true if it took the
|
||||
* lock. The convention is that unlocked is zero, locked is nonzero.
|
||||
*/
|
||||
#define CA_SPINLOCK_INIT 0
|
||||
|
||||
typedef int32_t CASpinLock;
|
||||
|
||||
bool CASpinLockTry( volatile CASpinLock *__lock );
|
||||
void CASpinLockLock( volatile CASpinLock *__lock );
|
||||
void CASpinLockUnlock( volatile CASpinLock *__lock );
|
||||
|
||||
inline void CASpinLockLock( volatile CASpinLock *__lock )
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
OSSpinLockLock(__lock);
|
||||
#else
|
||||
while (CAAtomicTestAndSetBarrier(0, (void*)__lock))
|
||||
usleep(1000); // ???
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void CASpinLockUnlock( volatile CASpinLock *__lock )
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
OSSpinLockUnlock(__lock);
|
||||
#else
|
||||
CAAtomicTestAndClearBarrier(0, (void*)__lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool CASpinLockTry( volatile CASpinLock *__lock )
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
return OSSpinLockTry(__lock);
|
||||
#else
|
||||
return (CAAtomicTestAndSetBarrier(0, (void*)__lock) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif // __CAAtomic_h__
|
@ -1,201 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#ifndef __CAAtomicStack_h__
|
||||
#define __CAAtomicStack_h__
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <libkern/OSAtomic.h>
|
||||
#else
|
||||
#include <CAAtomic.h>
|
||||
#endif
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#endif
|
||||
|
||||
// linked list LIFO or FIFO (pop_all_reversed) stack, elements are pushed and popped atomically
|
||||
// class T must implement T *& next().
|
||||
template <class T>
|
||||
class TAtomicStack {
|
||||
public:
|
||||
TAtomicStack() : mHead(NULL) { }
|
||||
|
||||
// non-atomic routines, for use when initializing/deinitializing, operate NON-atomically
|
||||
void push_NA(T *item)
|
||||
{
|
||||
item->next() = mHead;
|
||||
mHead = item;
|
||||
}
|
||||
|
||||
T * pop_NA()
|
||||
{
|
||||
T *result = mHead;
|
||||
if (result)
|
||||
mHead = result->next();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool empty() const { return mHead == NULL; }
|
||||
|
||||
T * head() { return mHead; }
|
||||
|
||||
// atomic routines
|
||||
void push_atomic(T *item)
|
||||
{
|
||||
T *head_;
|
||||
do {
|
||||
head_ = mHead;
|
||||
item->next() = head_;
|
||||
} while (!compare_and_swap(head_, item, &mHead));
|
||||
}
|
||||
|
||||
void push_multiple_atomic(T *item)
|
||||
// pushes entire linked list headed by item
|
||||
{
|
||||
T *head_, *p = item, *tail;
|
||||
// find the last one -- when done, it will be linked to head
|
||||
do {
|
||||
tail = p;
|
||||
p = p->next();
|
||||
} while (p);
|
||||
do {
|
||||
head_ = mHead;
|
||||
tail->next() = head_;
|
||||
} while (!compare_and_swap(head_, item, &mHead));
|
||||
}
|
||||
|
||||
T * pop_atomic_single_reader()
|
||||
// this may only be used when only one thread may potentially pop from the stack.
|
||||
// if multiple threads may pop, this suffers from the ABA problem.
|
||||
// <rdar://problem/4606346> TAtomicStack suffers from the ABA problem
|
||||
{
|
||||
T *result;
|
||||
do {
|
||||
if ((result = mHead) == NULL)
|
||||
break;
|
||||
} while (!compare_and_swap(result, result->next(), &mHead));
|
||||
return result;
|
||||
}
|
||||
|
||||
T * pop_atomic()
|
||||
// This is inefficient for large linked lists.
|
||||
// prefer pop_all() to a series of calls to pop_atomic.
|
||||
// push_multiple_atomic has to traverse the entire list.
|
||||
{
|
||||
T *result = pop_all();
|
||||
if (result) {
|
||||
T *next = result->next();
|
||||
if (next)
|
||||
// push all the remaining items back onto the stack
|
||||
push_multiple_atomic(next);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
T * pop_all()
|
||||
{
|
||||
T *result;
|
||||
do {
|
||||
if ((result = mHead) == NULL)
|
||||
break;
|
||||
} while (!compare_and_swap(result, NULL, &mHead));
|
||||
return result;
|
||||
}
|
||||
|
||||
T* pop_all_reversed()
|
||||
{
|
||||
TAtomicStack<T> reversed;
|
||||
T *p = pop_all(), *next;
|
||||
while (p != NULL) {
|
||||
next = p->next();
|
||||
reversed.push_NA(p);
|
||||
p = next;
|
||||
}
|
||||
return reversed.mHead;
|
||||
}
|
||||
|
||||
static bool compare_and_swap(T *oldvalue, T *newvalue, T **pvalue)
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
#if __LP64__
|
||||
return ::OSAtomicCompareAndSwap64Barrier(int64_t(oldvalue), int64_t(newvalue), (int64_t *)pvalue);
|
||||
#elif MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
|
||||
return ::OSAtomicCompareAndSwap32Barrier(int32_t(oldvalue), int32_t(newvalue), (int32_t *)pvalue);
|
||||
#else
|
||||
return ::CompareAndSwap(UInt32(oldvalue), UInt32(newvalue), (UInt32 *)pvalue);
|
||||
#endif
|
||||
#else
|
||||
//return ::CompareAndSwap(UInt32(oldvalue), UInt32(newvalue), (UInt32 *)pvalue);
|
||||
return CAAtomicCompareAndSwap32Barrier(SInt32(oldvalue), SInt32(newvalue), (SInt32*)pvalue);
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
T * mHead;
|
||||
};
|
||||
|
||||
#if ((MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) && !TARGET_OS_WIN32)
|
||||
#include <libkern/OSAtomic.h>
|
||||
|
||||
class CAAtomicStack {
|
||||
public:
|
||||
CAAtomicStack(size_t nextPtrOffset) : mNextPtrOffset(nextPtrOffset) {
|
||||
/*OSQueueHead h = OS_ATOMIC_QUEUE_INIT; mHead = h;*/
|
||||
mHead.opaque1 = 0; mHead.opaque2 = 0;
|
||||
}
|
||||
// a subset of the above
|
||||
void push_atomic(void *p) { OSAtomicEnqueue(&mHead, p, mNextPtrOffset); }
|
||||
void push_NA(void *p) { push_atomic(p); }
|
||||
|
||||
void * pop_atomic() { return OSAtomicDequeue(&mHead, mNextPtrOffset); }
|
||||
void * pop_atomic_single_reader() { return pop_atomic(); }
|
||||
void * pop_NA() { return pop_atomic(); }
|
||||
|
||||
private:
|
||||
OSQueueHead mHead;
|
||||
size_t mNextPtrOffset;
|
||||
};
|
||||
|
||||
// a more efficient subset of TAtomicStack using OSQueue.
|
||||
template <class T>
|
||||
class TAtomicStack2 {
|
||||
public:
|
||||
TAtomicStack2() {
|
||||
/*OSQueueHead h = OS_ATOMIC_QUEUE_INIT; mHead = h;*/
|
||||
mHead.opaque1 = 0; mHead.opaque2 = 0;
|
||||
mNextPtrOffset = -1;
|
||||
}
|
||||
void push_atomic(T *item) {
|
||||
if (mNextPtrOffset < 0) {
|
||||
T **pnext = &item->next(); // hack around offsetof not working with C++
|
||||
mNextPtrOffset = (Byte *)pnext - (Byte *)item;
|
||||
}
|
||||
OSAtomicEnqueue(&mHead, item, mNextPtrOffset);
|
||||
}
|
||||
void push_NA(T *item) { push_atomic(item); }
|
||||
|
||||
T * pop_atomic() { return (T *)OSAtomicDequeue(&mHead, mNextPtrOffset); }
|
||||
T * pop_atomic_single_reader() { return pop_atomic(); }
|
||||
T * pop_NA() { return pop_atomic(); }
|
||||
|
||||
// caution: do not try to implement pop_all_reversed here. the writer could add new elements
|
||||
// while the reader is trying to pop old ones!
|
||||
|
||||
private:
|
||||
OSQueueHead mHead;
|
||||
ssize_t mNextPtrOffset;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#define TAtomicStack2 TAtomicStack
|
||||
|
||||
#endif // MAC_OS_X_VERSION_MAX_ALLOWED && !TARGET_OS_WIN32
|
||||
|
||||
#endif // __CAAtomicStack_h__
|
@ -1,115 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
// Self Include
|
||||
#include "CAAudioChannelLayout.h"
|
||||
#include "CAAutoDisposer.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
//=============================================================================
|
||||
// CAAudioChannelLayout
|
||||
//=============================================================================
|
||||
|
||||
AudioChannelLayout* CAAudioChannelLayout::Create(UInt32 inNumberChannelDescriptions)
|
||||
{
|
||||
UInt32 theSize = CalculateByteSize(inNumberChannelDescriptions);
|
||||
AudioChannelLayout* theAnswer = static_cast<AudioChannelLayout*>(CA_calloc(1, theSize));
|
||||
if(theAnswer != NULL)
|
||||
{
|
||||
SetAllToUnknown(*theAnswer, inNumberChannelDescriptions);
|
||||
}
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
void CAAudioChannelLayout::Destroy(AudioChannelLayout* inChannelLayout)
|
||||
{
|
||||
free(inChannelLayout);
|
||||
}
|
||||
|
||||
void CAAudioChannelLayout::SetAllToUnknown(AudioChannelLayout& outChannelLayout, UInt32 inNumberChannelDescriptions)
|
||||
{
|
||||
outChannelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
|
||||
outChannelLayout.mChannelBitmap = 0;
|
||||
outChannelLayout.mNumberChannelDescriptions = inNumberChannelDescriptions;
|
||||
for(UInt32 theChannelIndex = 0; theChannelIndex < inNumberChannelDescriptions; ++theChannelIndex)
|
||||
{
|
||||
outChannelLayout.mChannelDescriptions[theChannelIndex].mChannelLabel = kAudioChannelLabel_Unknown;
|
||||
outChannelLayout.mChannelDescriptions[theChannelIndex].mChannelFlags = 0;
|
||||
outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[0] = 0;
|
||||
outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[1] = 0;
|
||||
outChannelLayout.mChannelDescriptions[theChannelIndex].mCoordinates[2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator== (const AudioChannelLayout &x, const AudioChannelLayout &y)
|
||||
{
|
||||
// compare based on the number of channel descriptions present
|
||||
// (this may be too strict a comparison if all you care about are matching layout tags)
|
||||
UInt32 theSize1 = CAAudioChannelLayout::CalculateByteSize(x.mNumberChannelDescriptions);
|
||||
UInt32 theSize2 = CAAudioChannelLayout::CalculateByteSize(y.mNumberChannelDescriptions);
|
||||
|
||||
if (theSize1 != theSize2)
|
||||
return false;
|
||||
|
||||
return !memcmp (&x, &y, theSize1);
|
||||
}
|
||||
|
||||
bool operator!= (const AudioChannelLayout &x, const AudioChannelLayout &y)
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
// counting the one bits in a word
|
||||
inline UInt32 CountOnes(UInt32 x)
|
||||
{
|
||||
// secret magic algorithm for counting bits in a word.
|
||||
UInt32 t;
|
||||
x = x - ((x >> 1) & 0x55555555);
|
||||
t = ((x >> 2) & 0x33333333);
|
||||
x = (x & 0x33333333) + t;
|
||||
x = (x + (x >> 4)) & 0x0F0F0F0F;
|
||||
x = x + (x << 8);
|
||||
x = x + (x << 16);
|
||||
return x >> 24;
|
||||
}
|
||||
|
||||
UInt32 CAAudioChannelLayout::NumberChannels (const AudioChannelLayout& inLayout)
|
||||
{
|
||||
if (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions)
|
||||
return inLayout.mNumberChannelDescriptions;
|
||||
|
||||
if (inLayout.mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
|
||||
return CountOnes (inLayout.mChannelBitmap);
|
||||
|
||||
return AudioChannelLayoutTag_GetNumberOfChannels(inLayout.mChannelLayoutTag);
|
||||
}
|
||||
|
||||
void CAShowAudioChannelLayout (FILE* file, const AudioChannelLayout *layout)
|
||||
{
|
||||
if (layout == NULL)
|
||||
{
|
||||
fprintf (file, "\tNULL layout\n");
|
||||
return;
|
||||
}
|
||||
fprintf (file, "\tTag=0x%X, ", (int)layout->mChannelLayoutTag);
|
||||
if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
|
||||
fprintf (file, "Using Bitmap:0x%X\n", (int)layout->mChannelBitmap);
|
||||
else {
|
||||
fprintf (file, "Num Chan Descs=%d\n", (int)layout->mNumberChannelDescriptions);
|
||||
const AudioChannelDescription *desc = layout->mChannelDescriptions;
|
||||
for (unsigned int i = 0; i < layout->mNumberChannelDescriptions; ++i, ++desc) {
|
||||
fprintf (file, "\t\tLabel=%d, Flags=0x%X, ", (int)desc->mChannelLabel, (int)desc->mChannelFlags);
|
||||
fprintf (file, "[az=%f,el=%f,dist=%f]\n", desc->mCoordinates[0], desc->mCoordinates[1], desc->mCoordinates[2]);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,161 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#if !defined(__CAAudioChannelLayout_h__)
|
||||
#define __CAAudioChannelLayout_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
// System Includes
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#include <CoreFoundation.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "CADebugMacros.h"
|
||||
#include "CAAutoDisposer.h"
|
||||
|
||||
#if !HAL_Build
|
||||
#include "CAReferenceCounted.h"
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// CAAudioChannelLayout
|
||||
//=============================================================================
|
||||
|
||||
bool operator== (const AudioChannelLayout &x, const AudioChannelLayout &y);
|
||||
bool operator!= (const AudioChannelLayout &x, const AudioChannelLayout &y);
|
||||
|
||||
extern "C" void CAShowAudioChannelLayout (FILE* file, const AudioChannelLayout *layout);
|
||||
|
||||
class CAAudioChannelLayout
|
||||
{
|
||||
// static Construction/Destruction
|
||||
public:
|
||||
static AudioChannelLayout* Create(UInt32 inNumberChannelDescriptions);
|
||||
static void Destroy(AudioChannelLayout* inChannelLayout);
|
||||
static UInt32 CalculateByteSize(UInt32 inNumberChannelDescriptions) {
|
||||
return SizeOf32(AudioChannelLayout) - SizeOf32(AudioChannelDescription) + (inNumberChannelDescriptions * SizeOf32(AudioChannelDescription));
|
||||
}
|
||||
static void SetAllToUnknown(AudioChannelLayout& outChannelLayout, UInt32 inNumberChannelDescriptions);
|
||||
static UInt32 NumberChannels(const AudioChannelLayout& inLayout);
|
||||
|
||||
#if !HAL_Build
|
||||
// object methods
|
||||
public:
|
||||
CAAudioChannelLayout ();
|
||||
|
||||
CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround);
|
||||
// if inChooseSurround is false, then symmetrical speaker arrangements
|
||||
// are chosen in place of surround layouts if there is a choice
|
||||
// This call chooses layouts based on the expected defaults in
|
||||
// AudioUnit usage
|
||||
CAAudioChannelLayout (AudioChannelLayoutTag inTag);
|
||||
CAAudioChannelLayout (const CAAudioChannelLayout &c);
|
||||
CAAudioChannelLayout (const AudioChannelLayout* inChannelLayout);
|
||||
~CAAudioChannelLayout();
|
||||
|
||||
CAAudioChannelLayout& operator= (const AudioChannelLayout* inChannelLayout);
|
||||
CAAudioChannelLayout& operator= (const CAAudioChannelLayout& c);
|
||||
bool operator== (const CAAudioChannelLayout &c) const;
|
||||
bool operator!= (const CAAudioChannelLayout &c) const;
|
||||
|
||||
void SetWithTag(AudioChannelLayoutTag inTag);
|
||||
|
||||
bool IsValid() const { return NumberChannels() > 0; }
|
||||
UInt32 Size() const { return mLayout ? mLayout->Size() : 0; }
|
||||
|
||||
UInt32 NumberChannels() const { return mLayout ? mLayout->NumberChannels() : 0; }
|
||||
|
||||
AudioChannelLayoutTag Tag() const { return Layout().mChannelLayoutTag; }
|
||||
const AudioChannelLayout& Layout() const { return mLayout->Layout(); }
|
||||
operator const AudioChannelLayout *() const { return &Layout(); }
|
||||
|
||||
void Print () const { Print (stdout); }
|
||||
void Print (FILE* file) const;
|
||||
|
||||
OSStatus Save (CFPropertyListRef *outData) const;
|
||||
OSStatus Restore (CFPropertyListRef &inData);
|
||||
|
||||
private:
|
||||
class RefCountedLayout : public CAReferenceCounted {
|
||||
void * operator new(size_t /* size */, size_t aclSize)
|
||||
{
|
||||
return CA_malloc(sizeof(RefCountedLayout) - sizeof(AudioChannelLayout) + aclSize);
|
||||
}
|
||||
|
||||
void operator delete(void *mem)
|
||||
{
|
||||
free(mem);
|
||||
}
|
||||
|
||||
|
||||
RefCountedLayout(UInt32 inDataSize) :
|
||||
mByteSize(inDataSize)
|
||||
{
|
||||
memset(&mACL, 0, inDataSize);
|
||||
}
|
||||
|
||||
public:
|
||||
static RefCountedLayout *CreateWithNumberChannelDescriptions(unsigned nChannels) {
|
||||
size_t size = CAAudioChannelLayout::CalculateByteSize(nChannels);
|
||||
return new(size) RefCountedLayout((UInt32)size);
|
||||
}
|
||||
|
||||
static RefCountedLayout *CreateWithLayout(const AudioChannelLayout *layout) {
|
||||
size_t size = CAAudioChannelLayout::CalculateByteSize(layout->mNumberChannelDescriptions);
|
||||
RefCountedLayout *acl = new(size) RefCountedLayout((UInt32)size);
|
||||
memcpy(&acl->mACL, layout, size);
|
||||
return acl;
|
||||
}
|
||||
static RefCountedLayout *CreateWithLayoutTag(AudioChannelLayoutTag layoutTag) {
|
||||
RefCountedLayout *acl = CreateWithNumberChannelDescriptions(0);
|
||||
acl->mACL.mChannelLayoutTag = layoutTag;
|
||||
return acl;
|
||||
}
|
||||
|
||||
const AudioChannelLayout & Layout() const { return mACL; }
|
||||
|
||||
UInt32 Size () const { return mByteSize; }
|
||||
|
||||
UInt32 NumberChannels() { return CAAudioChannelLayout::NumberChannels(Layout()); }
|
||||
|
||||
private:
|
||||
const UInt32 mByteSize;
|
||||
AudioChannelLayout mACL;
|
||||
// * * * mACL is variable length and thus must be last * * *
|
||||
|
||||
// only the constructors can change the actual state of the layout
|
||||
friend CAAudioChannelLayout::CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround);
|
||||
friend OSStatus CAAudioChannelLayout::Restore (CFPropertyListRef &inData);
|
||||
friend CAAudioChannelLayout& CAAudioChannelLayout::operator= (const AudioChannelLayout* inChannelLayout);
|
||||
friend void CAAudioChannelLayout::SetWithTag(AudioChannelLayoutTag inTag);
|
||||
|
||||
AudioChannelLayout * GetLayout() { return &mACL; }
|
||||
|
||||
private:
|
||||
// prohibited methods: private and unimplemented.
|
||||
RefCountedLayout();
|
||||
RefCountedLayout(const RefCountedLayout& c);
|
||||
RefCountedLayout& operator=(const RefCountedLayout& c);
|
||||
};
|
||||
|
||||
RefCountedLayout *mLayout;
|
||||
#endif // HAL_Build
|
||||
|
||||
};
|
||||
|
||||
#endif
|
@ -1,172 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#include "CAAudioChannelLayout.h"
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <AudioToolbox/AudioFormat.h>
|
||||
#else
|
||||
#include <AudioFormat.h>
|
||||
#endif
|
||||
|
||||
CAAudioChannelLayout::CAAudioChannelLayout ()
|
||||
{
|
||||
mLayout = RefCountedLayout::CreateWithNumberChannelDescriptions(0);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// CAAudioChannelLayout::CAAudioChannelLayout
|
||||
//=============================================================================
|
||||
CAAudioChannelLayout::CAAudioChannelLayout (UInt32 inNumberChannels, bool inChooseSurround)
|
||||
{
|
||||
// this chooses default layouts based on the number of channels...
|
||||
AudioChannelLayoutTag tag;
|
||||
|
||||
switch (inNumberChannels)
|
||||
{
|
||||
default:
|
||||
// here we have a "broken" layout, in the sense that we haven't any idea how to lay this out
|
||||
mLayout = RefCountedLayout::CreateWithNumberChannelDescriptions(inNumberChannels);
|
||||
SetAllToUnknown(*mLayout->GetLayout(), inNumberChannels);
|
||||
return; // don't fall into the tag case
|
||||
case 1:
|
||||
tag = kAudioChannelLayoutTag_Mono;
|
||||
break;
|
||||
case 2:
|
||||
tag = inChooseSurround ? kAudioChannelLayoutTag_Binaural : kAudioChannelLayoutTag_Stereo;
|
||||
break;
|
||||
case 4:
|
||||
tag = inChooseSurround ? kAudioChannelLayoutTag_Ambisonic_B_Format : kAudioChannelLayoutTag_AudioUnit_4;
|
||||
break;
|
||||
case 5:
|
||||
tag = inChooseSurround ? kAudioChannelLayoutTag_AudioUnit_5_0 : kAudioChannelLayoutTag_AudioUnit_5;
|
||||
break;
|
||||
case 6:
|
||||
tag = inChooseSurround ? kAudioChannelLayoutTag_AudioUnit_6_0 : kAudioChannelLayoutTag_AudioUnit_6;
|
||||
break;
|
||||
case 7:
|
||||
tag = kAudioChannelLayoutTag_AudioUnit_7_0;
|
||||
break;
|
||||
case 8:
|
||||
tag = kAudioChannelLayoutTag_AudioUnit_8;
|
||||
break;
|
||||
}
|
||||
|
||||
mLayout = RefCountedLayout::CreateWithLayoutTag(tag);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// CAAudioChannelLayout::CAAudioChannelLayout
|
||||
//=============================================================================
|
||||
CAAudioChannelLayout::CAAudioChannelLayout (AudioChannelLayoutTag inLayoutTag)
|
||||
: mLayout(NULL)
|
||||
{
|
||||
SetWithTag(inLayoutTag);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// CAAudioChannelLayout::CAAudioChannelLayout
|
||||
//=============================================================================
|
||||
CAAudioChannelLayout::CAAudioChannelLayout (const CAAudioChannelLayout &c)
|
||||
: mLayout(NULL)
|
||||
{
|
||||
*this = c;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// CAAudioChannelLayout::AudioChannelLayout
|
||||
//=============================================================================
|
||||
CAAudioChannelLayout::CAAudioChannelLayout (const AudioChannelLayout* inChannelLayout)
|
||||
: mLayout(NULL)
|
||||
{
|
||||
*this = inChannelLayout;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// CAAudioChannelLayout::~CAAudioChannelLayout
|
||||
//=============================================================================
|
||||
CAAudioChannelLayout::~CAAudioChannelLayout ()
|
||||
{
|
||||
if (mLayout) {
|
||||
mLayout->release();
|
||||
mLayout = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// CAAudioChannelLayout::CAAudioChannelLayout
|
||||
//=============================================================================
|
||||
CAAudioChannelLayout& CAAudioChannelLayout::operator= (const CAAudioChannelLayout &c)
|
||||
{
|
||||
if (mLayout != c.mLayout) {
|
||||
if (mLayout)
|
||||
mLayout->release();
|
||||
|
||||
if ((mLayout = c.mLayout) != NULL)
|
||||
mLayout->retain();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAAudioChannelLayout& CAAudioChannelLayout::operator= (const AudioChannelLayout* inChannelLayout)
|
||||
{
|
||||
if (mLayout && &mLayout->Layout() == inChannelLayout)
|
||||
return *this;
|
||||
|
||||
if (mLayout)
|
||||
mLayout->release();
|
||||
|
||||
if (inChannelLayout == NULL)
|
||||
{
|
||||
mLayout = RefCountedLayout::CreateWithNumberChannelDescriptions(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
mLayout = RefCountedLayout::CreateWithLayout(inChannelLayout);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CAAudioChannelLayout::SetWithTag(AudioChannelLayoutTag inTag)
|
||||
{
|
||||
if (mLayout)
|
||||
mLayout->release();
|
||||
|
||||
mLayout = RefCountedLayout::CreateWithLayoutTag(inTag);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// CAAudioChannelLayout::operator==
|
||||
//=============================================================================
|
||||
bool CAAudioChannelLayout::operator== (const CAAudioChannelLayout &c) const
|
||||
{
|
||||
if (mLayout == c.mLayout)
|
||||
return true;
|
||||
return Layout() == c.Layout();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// CAAudioChannelLayout::operator!=
|
||||
//=============================================================================
|
||||
bool CAAudioChannelLayout::operator!= (const CAAudioChannelLayout &c) const
|
||||
{
|
||||
if (mLayout == c.mLayout)
|
||||
return false;
|
||||
|
||||
return !(Layout() == c.Layout());
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// CAAudioChannelLayout::Print
|
||||
//=============================================================================
|
||||
void CAAudioChannelLayout::Print (FILE* file) const
|
||||
{
|
||||
CAShowAudioChannelLayout (file, &Layout());
|
||||
}
|
||||
|
@ -1,470 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#if !defined(__CAPtr_h__)
|
||||
#define __CAPtr_h__
|
||||
|
||||
#include <stdlib.h> // for malloc
|
||||
#include <new> // for bad_alloc
|
||||
#include <string.h> // for memset
|
||||
|
||||
inline void* CA_malloc(size_t size)
|
||||
{
|
||||
void* p = malloc(size);
|
||||
if (!p && size) throw std::bad_alloc();
|
||||
return p;
|
||||
}
|
||||
|
||||
inline void* CA_realloc(void* old, size_t size)
|
||||
{
|
||||
#if TARGET_OS_WIN32
|
||||
void* p = realloc(old, size);
|
||||
#else
|
||||
void* p = reallocf(old, size); // reallocf ensures the old pointer is freed if memory is full (p is NULL).
|
||||
#endif
|
||||
if (!p && size) throw std::bad_alloc();
|
||||
return p;
|
||||
}
|
||||
|
||||
#ifndef UINTPTR_MAX
|
||||
#if __LP64__
|
||||
#define UINTPTR_MAX 18446744073709551615ULL
|
||||
#else
|
||||
#define UINTPTR_MAX 4294967295U
|
||||
#endif
|
||||
#endif
|
||||
|
||||
inline void* CA_calloc(size_t n, size_t size)
|
||||
{
|
||||
// ensure that multiplication will not overflow
|
||||
if (n && UINTPTR_MAX / n < size) throw std::bad_alloc();
|
||||
|
||||
size_t nsize = n*size;
|
||||
void* p = malloc(nsize);
|
||||
if (!p && nsize) throw std::bad_alloc();
|
||||
|
||||
memset(p, 0, nsize);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
// helper class for automatic conversions
|
||||
template <typename T>
|
||||
struct CAPtrRef
|
||||
{
|
||||
T* ptr_;
|
||||
|
||||
explicit CAPtrRef(T* ptr) : ptr_(ptr) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class CAAutoFree
|
||||
{
|
||||
private:
|
||||
T* ptr_;
|
||||
|
||||
public:
|
||||
|
||||
CAAutoFree() : ptr_(0) {}
|
||||
|
||||
explicit CAAutoFree(T* ptr) : ptr_(ptr) {}
|
||||
|
||||
template<typename U>
|
||||
CAAutoFree(CAAutoFree<U>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
// C++ std says: a template constructor is never a copy constructor
|
||||
CAAutoFree(CAAutoFree<T>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
CAAutoFree(size_t n, bool clear = false)
|
||||
// this becomes an ambiguous call if n == 0
|
||||
: ptr_(0)
|
||||
{
|
||||
size_t maxItems = ~size_t(0) / sizeof(T);
|
||||
if (n > maxItems)
|
||||
throw std::bad_alloc();
|
||||
|
||||
ptr_ = static_cast<T*>(clear ? CA_calloc(n, sizeof(T)) : CA_malloc(n * sizeof(T)));
|
||||
}
|
||||
|
||||
~CAAutoFree() { free(); }
|
||||
|
||||
void alloc(size_t numItems, bool clear = false)
|
||||
{
|
||||
size_t maxItems = ~size_t(0) / sizeof(T);
|
||||
if (numItems > maxItems) throw std::bad_alloc();
|
||||
|
||||
free();
|
||||
ptr_ = static_cast<T*>(clear ? CA_calloc(numItems, sizeof(T)) : CA_malloc(numItems * sizeof(T)));
|
||||
}
|
||||
|
||||
void allocBytes(size_t numBytes, bool clear = false)
|
||||
{
|
||||
free();
|
||||
ptr_ = static_cast<T*>(clear ? CA_calloc(1, numBytes) : CA_malloc(numBytes));
|
||||
}
|
||||
|
||||
void reallocBytes(size_t numBytes)
|
||||
{
|
||||
ptr_ = static_cast<T*>(CA_realloc(ptr_, numBytes));
|
||||
}
|
||||
|
||||
void reallocItems(size_t numItems)
|
||||
{
|
||||
size_t maxItems = ~size_t(0) / sizeof(T);
|
||||
if (numItems > maxItems) throw std::bad_alloc();
|
||||
|
||||
ptr_ = static_cast<T*>(CA_realloc(ptr_, numItems * sizeof(T)));
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
CAAutoFree& operator=(CAAutoFree<U>& that)
|
||||
{
|
||||
set(that.release()); // take ownership
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAAutoFree& operator=(CAAutoFree& that)
|
||||
{
|
||||
set(that.release()); // take ownership
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAAutoFree& operator=(T* ptr)
|
||||
{
|
||||
set(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
CAAutoFree& operator=(U* ptr)
|
||||
{
|
||||
set(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& operator*() const { return *ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
|
||||
T* operator()() const { return ptr_; }
|
||||
T* get() const { return ptr_; }
|
||||
operator T*() const { return ptr_; }
|
||||
|
||||
bool operator==(CAAutoFree const& that) const { return ptr_ == that.ptr_; }
|
||||
bool operator!=(CAAutoFree const& that) const { return ptr_ != that.ptr_; }
|
||||
bool operator==(T* ptr) const { return ptr_ == ptr; }
|
||||
bool operator!=(T* ptr) const { return ptr_ != ptr; }
|
||||
|
||||
T* release()
|
||||
{
|
||||
// release ownership
|
||||
T* result = ptr_;
|
||||
ptr_ = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
void set(T* ptr)
|
||||
{
|
||||
if (ptr != ptr_)
|
||||
{
|
||||
::free(ptr_);
|
||||
ptr_ = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void free()
|
||||
{
|
||||
set(0);
|
||||
}
|
||||
|
||||
|
||||
// automatic conversions to allow assignment from results of functions.
|
||||
// hard to explain. see auto_ptr implementation and/or Josuttis' STL book.
|
||||
CAAutoFree(CAPtrRef<T> ref) : ptr_(ref.ptr_) { }
|
||||
|
||||
CAAutoFree& operator=(CAPtrRef<T> ref)
|
||||
{
|
||||
set(ref.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
operator CAPtrRef<U>()
|
||||
{ return CAPtrRef<U>(release()); }
|
||||
|
||||
template<typename U>
|
||||
operator CAAutoFree<U>()
|
||||
{ return CAAutoFree<U>(release()); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class CAAutoDelete
|
||||
{
|
||||
private:
|
||||
T* ptr_;
|
||||
|
||||
public:
|
||||
CAAutoDelete() : ptr_(0) {}
|
||||
|
||||
explicit CAAutoDelete(T* ptr) : ptr_(ptr) {}
|
||||
|
||||
template<typename U>
|
||||
CAAutoDelete(CAAutoDelete<U>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
// C++ std says: a template constructor is never a copy constructor
|
||||
CAAutoDelete(CAAutoDelete<T>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
~CAAutoDelete() { free(); }
|
||||
|
||||
template <typename U>
|
||||
CAAutoDelete& operator=(CAAutoDelete<U>& that)
|
||||
{
|
||||
set(that.release()); // take ownership
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAAutoDelete& operator=(CAAutoDelete& that)
|
||||
{
|
||||
set(that.release()); // take ownership
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAAutoDelete& operator=(T* ptr)
|
||||
{
|
||||
set(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
CAAutoDelete& operator=(U* ptr)
|
||||
{
|
||||
set(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& operator*() const { return *ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
|
||||
T* operator()() const { return ptr_; }
|
||||
T* get() const { return ptr_; }
|
||||
operator T*() const { return ptr_; }
|
||||
|
||||
bool operator==(CAAutoDelete const& that) const { return ptr_ == that.ptr_; }
|
||||
bool operator!=(CAAutoDelete const& that) const { return ptr_ != that.ptr_; }
|
||||
bool operator==(T* ptr) const { return ptr_ == ptr; }
|
||||
bool operator!=(T* ptr) const { return ptr_ != ptr; }
|
||||
|
||||
T* release()
|
||||
{
|
||||
// release ownership
|
||||
T* result = ptr_;
|
||||
ptr_ = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
void set(T* ptr)
|
||||
{
|
||||
if (ptr != ptr_)
|
||||
{
|
||||
delete ptr_;
|
||||
ptr_ = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void free()
|
||||
{
|
||||
set(0);
|
||||
}
|
||||
|
||||
|
||||
// automatic conversions to allow assignment from results of functions.
|
||||
// hard to explain. see auto_ptr implementation and/or Josuttis' STL book.
|
||||
CAAutoDelete(CAPtrRef<T> ref) : ptr_(ref.ptr_) { }
|
||||
|
||||
CAAutoDelete& operator=(CAPtrRef<T> ref)
|
||||
{
|
||||
set(ref.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
operator CAPtrRef<U>()
|
||||
{ return CAPtrRef<U>(release()); }
|
||||
|
||||
template<typename U>
|
||||
operator CAAutoFree<U>()
|
||||
{ return CAAutoFree<U>(release()); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class CAAutoArrayDelete
|
||||
{
|
||||
private:
|
||||
T* ptr_;
|
||||
|
||||
public:
|
||||
CAAutoArrayDelete() : ptr_(0) {}
|
||||
|
||||
explicit CAAutoArrayDelete(T* ptr) : ptr_(ptr) {}
|
||||
|
||||
template<typename U>
|
||||
CAAutoArrayDelete(CAAutoArrayDelete<U>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
// C++ std says: a template constructor is never a copy constructor
|
||||
CAAutoArrayDelete(CAAutoArrayDelete<T>& that) : ptr_(that.release()) {} // take ownership
|
||||
|
||||
// this becomes an ambiguous call if n == 0
|
||||
CAAutoArrayDelete(size_t n) : ptr_(new T[n]) {}
|
||||
|
||||
~CAAutoArrayDelete() { free(); }
|
||||
|
||||
void alloc(size_t numItems)
|
||||
{
|
||||
free();
|
||||
ptr_ = new T [numItems];
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
CAAutoArrayDelete& operator=(CAAutoArrayDelete<U>& that)
|
||||
{
|
||||
set(that.release()); // take ownership
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAAutoArrayDelete& operator=(CAAutoArrayDelete& that)
|
||||
{
|
||||
set(that.release()); // take ownership
|
||||
return *this;
|
||||
}
|
||||
|
||||
CAAutoArrayDelete& operator=(T* ptr)
|
||||
{
|
||||
set(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
CAAutoArrayDelete& operator=(U* ptr)
|
||||
{
|
||||
set(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& operator*() const { return *ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
|
||||
T* operator()() const { return ptr_; }
|
||||
T* get() const { return ptr_; }
|
||||
operator T*() const { return ptr_; }
|
||||
|
||||
bool operator==(CAAutoArrayDelete const& that) const { return ptr_ == that.ptr_; }
|
||||
bool operator!=(CAAutoArrayDelete const& that) const { return ptr_ != that.ptr_; }
|
||||
bool operator==(T* ptr) const { return ptr_ == ptr; }
|
||||
bool operator!=(T* ptr) const { return ptr_ != ptr; }
|
||||
|
||||
T* release()
|
||||
{
|
||||
// release ownership
|
||||
T* result = ptr_;
|
||||
ptr_ = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
void set(T* ptr)
|
||||
{
|
||||
if (ptr != ptr_)
|
||||
{
|
||||
delete [] ptr_;
|
||||
ptr_ = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void free()
|
||||
{
|
||||
set(0);
|
||||
}
|
||||
|
||||
|
||||
// automatic conversions to allow assignment from results of functions.
|
||||
// hard to explain. see auto_ptr implementation and/or Josuttis' STL book.
|
||||
CAAutoArrayDelete(CAPtrRef<T> ref) : ptr_(ref.ptr_) { }
|
||||
|
||||
CAAutoArrayDelete& operator=(CAPtrRef<T> ref)
|
||||
{
|
||||
set(ref.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
operator CAPtrRef<U>()
|
||||
{ return CAPtrRef<U>(release()); }
|
||||
|
||||
template<typename U>
|
||||
operator CAAutoArrayDelete<U>()
|
||||
{ return CAAutoFree<U>(release()); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// convenience function
|
||||
template <typename T>
|
||||
void free(CAAutoFree<T>& p)
|
||||
{
|
||||
p.free();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if 0
|
||||
// example program showing ownership transfer
|
||||
|
||||
CAAutoFree<char> source()
|
||||
{
|
||||
// source allocates and returns ownership to the caller.
|
||||
const char* str = "this is a test";
|
||||
size_t size = strlen(str) + 1;
|
||||
CAAutoFree<char> captr(size, false);
|
||||
strlcpy(captr(), str, size);
|
||||
printf("source %08X %08X '%s'\n", &captr, captr(), captr());
|
||||
return captr;
|
||||
}
|
||||
|
||||
void user(CAAutoFree<char> const& captr)
|
||||
{
|
||||
// passed by const reference. user can access the pointer but does not take ownership.
|
||||
printf("user: %08X %08X '%s'\n", &captr, captr(), captr());
|
||||
}
|
||||
|
||||
void sink(CAAutoFree<char> captr)
|
||||
{
|
||||
// passed by value. sink takes ownership and frees the pointer on return.
|
||||
printf("sink: %08X %08X '%s'\n", &captr, captr(), captr());
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, char * const argv[])
|
||||
{
|
||||
|
||||
CAAutoFree<char> captr(source());
|
||||
printf("main captr A %08X %08X\n", &captr, captr());
|
||||
user(captr);
|
||||
sink(captr);
|
||||
printf("main captr B %08X %08X\n", &captr, captr());
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,223 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#include "CABufferList.h"
|
||||
#include "CAByteOrder.h"
|
||||
|
||||
void CABufferList::AllocateBuffers(UInt32 nBytes)
|
||||
{
|
||||
if (nBytes <= GetNumBytes()) return;
|
||||
|
||||
if (mABL.mNumberBuffers > 1)
|
||||
// align successive buffers for Altivec and to take alternating
|
||||
// cache line hits by spacing them by odd multiples of 16
|
||||
nBytes = ((nBytes + 15) & ~15) | 16;
|
||||
UInt32 memorySize = nBytes * mABL.mNumberBuffers;
|
||||
Byte *newMemory = new Byte[memorySize], *p = newMemory;
|
||||
memset(newMemory, 0, memorySize); // get page faults now, not later
|
||||
|
||||
AudioBuffer *buf = mABL.mBuffers;
|
||||
for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
|
||||
if (buf->mData != NULL && buf->mDataByteSize > 0)
|
||||
// preserve existing buffer contents
|
||||
memcpy(p, buf->mData, buf->mDataByteSize);
|
||||
buf->mDataByteSize = nBytes;
|
||||
buf->mData = p;
|
||||
p += nBytes;
|
||||
}
|
||||
Byte *oldMemory = mBufferMemory;
|
||||
mBufferMemory = newMemory;
|
||||
mBufferCapacity = nBytes;
|
||||
delete[] oldMemory;
|
||||
}
|
||||
|
||||
void CABufferList::AllocateBuffersAndCopyFrom(UInt32 nBytes, CABufferList *inSrcList, CABufferList *inSetPtrList)
|
||||
{
|
||||
if (mABL.mNumberBuffers != inSrcList->mABL.mNumberBuffers) return;
|
||||
if (mABL.mNumberBuffers != inSetPtrList->mABL.mNumberBuffers) return;
|
||||
if (nBytes <= GetNumBytes()) {
|
||||
CopyAllFrom(inSrcList, inSetPtrList);
|
||||
return;
|
||||
}
|
||||
inSetPtrList->VerifyNotTrashingOwnedBuffer();
|
||||
UInt32 fromByteSize = inSrcList->GetNumBytes();
|
||||
|
||||
if (mABL.mNumberBuffers > 1)
|
||||
// align successive buffers for Altivec and to take alternating
|
||||
// cache line hits by spacing them by odd multiples of 16
|
||||
nBytes = ((nBytes + 15) & ~15) | 16;
|
||||
UInt32 memorySize = nBytes * mABL.mNumberBuffers;
|
||||
Byte *newMemory = new Byte[memorySize], *p = newMemory;
|
||||
memset(newMemory, 0, memorySize); // make buffer "hot"
|
||||
|
||||
AudioBuffer *buf = mABL.mBuffers;
|
||||
AudioBuffer *ptrBuf = inSetPtrList->mABL.mBuffers;
|
||||
AudioBuffer *srcBuf = inSrcList->mABL.mBuffers;
|
||||
for (UInt32 i = mABL.mNumberBuffers; i--; ++buf, ++ptrBuf, ++srcBuf) {
|
||||
if (srcBuf->mData != NULL && srcBuf->mDataByteSize > 0)
|
||||
// preserve existing buffer contents
|
||||
memmove(p, srcBuf->mData, srcBuf->mDataByteSize);
|
||||
buf->mDataByteSize = nBytes;
|
||||
buf->mData = p;
|
||||
ptrBuf->mDataByteSize = srcBuf->mDataByteSize;
|
||||
ptrBuf->mData = p;
|
||||
p += nBytes;
|
||||
}
|
||||
Byte *oldMemory = mBufferMemory;
|
||||
mBufferMemory = newMemory;
|
||||
mBufferCapacity = nBytes;
|
||||
if (inSrcList != inSetPtrList)
|
||||
inSrcList->BytesConsumed(fromByteSize);
|
||||
delete[] oldMemory;
|
||||
}
|
||||
|
||||
void CABufferList::DeallocateBuffers()
|
||||
{
|
||||
AudioBuffer *buf = mABL.mBuffers;
|
||||
for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
|
||||
buf->mData = NULL;
|
||||
buf->mDataByteSize = 0;
|
||||
}
|
||||
if (mBufferMemory != NULL) {
|
||||
delete[] mBufferMemory;
|
||||
mBufferMemory = NULL;
|
||||
mBufferCapacity = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void show(const AudioBufferList &abl, int framesToPrint, int wordSize, const char *label, const char *fmtstr=NULL)
|
||||
{
|
||||
printf("%s %p (%d fr%s):\n", label ? label : "AudioBufferList", &abl, framesToPrint, fmtstr ? fmtstr : "");
|
||||
const AudioBuffer *buf = abl.mBuffers;
|
||||
for (UInt32 i = 0; i < abl.mNumberBuffers; ++i, ++buf) {
|
||||
printf(" [%2d] %5dbytes %dch @ %p", (int)i, (int)buf->mDataByteSize, (int)buf->mNumberChannels, buf->mData);
|
||||
if (framesToPrint && buf->mData != NULL) {
|
||||
printf(":");
|
||||
Byte *p = (Byte *)buf->mData;
|
||||
for (int j = framesToPrint * buf->mNumberChannels; --j >= 0; )
|
||||
switch (wordSize) {
|
||||
case 0: // native float
|
||||
printf(" %6.3f", *(Float32 *)p);
|
||||
p += sizeof(Float32);
|
||||
break;
|
||||
// positive: big endian
|
||||
case 1:
|
||||
case -1:
|
||||
printf(" %02X", *p);
|
||||
p += 1;
|
||||
break;
|
||||
case 2:
|
||||
printf(" %04X", CFSwapInt16BigToHost(*(UInt16 *)p));
|
||||
p += 2;
|
||||
break;
|
||||
case 3:
|
||||
printf(" %06X", (p[0] << 16) | (p[1] << 8) | p[2]);
|
||||
p += 3;
|
||||
break;
|
||||
case 4:
|
||||
printf(" %08X", (unsigned int)CFSwapInt32BigToHost(*(UInt32 *)p));
|
||||
p += 4;
|
||||
break;
|
||||
case 10:
|
||||
printf(" %6.3f", CASwapFloat32BigToHost(*(Float32 *)p));
|
||||
p += sizeof(Float32);
|
||||
break;
|
||||
case -2:
|
||||
printf(" %04X", CFSwapInt16LittleToHost(*(UInt16 *)p));
|
||||
p += 2;
|
||||
break;
|
||||
case -3:
|
||||
printf(" %06X", (p[2] << 16) | (p[1] << 8) | p[0]);
|
||||
p += 3;
|
||||
break;
|
||||
case -4:
|
||||
printf(" %08X", (unsigned int)CFSwapInt32LittleToHost(*(UInt32 *)p));
|
||||
p += 4;
|
||||
break;
|
||||
case -10:
|
||||
printf(" %6.3f", CASwapFloat32LittleToHost(*(Float32 *)p));
|
||||
p += sizeof(Float32);
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void CAShowAudioBufferList(const AudioBufferList &abl, int framesToPrint, const AudioStreamBasicDescription &asbd, const char *label)
|
||||
{
|
||||
CAStreamBasicDescription fmt(asbd);
|
||||
int wordSize = 1;
|
||||
char fmtstr[80] = { 0 };
|
||||
|
||||
if (fmt.mFormatID == kAudioFormatLinearPCM) {
|
||||
if (fmt.mFormatFlags & kLinearPCMFormatFlagIsFloat) {
|
||||
if (fmt.mBitsPerChannel == 32) {
|
||||
if (fmt.mFormatFlags & kLinearPCMFormatFlagIsBigEndian) {
|
||||
wordSize = 10;
|
||||
strlcpy(fmtstr, ", BEF", sizeof(fmtstr));
|
||||
} else {
|
||||
wordSize = -10;
|
||||
strlcpy(fmtstr, ", LEF", sizeof(fmtstr));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wordSize = fmt.SampleWordSize();
|
||||
if (wordSize > 0) {
|
||||
int fracbits = (asbd.mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift;
|
||||
if (fracbits > 0)
|
||||
snprintf(fmtstr, sizeof(fmtstr), ", %d.%d-bit", (int)asbd.mBitsPerChannel - fracbits, fracbits);
|
||||
else
|
||||
snprintf(fmtstr, sizeof(fmtstr), ", %d-bit", (int)asbd.mBitsPerChannel);
|
||||
|
||||
if (!(fmt.mFormatFlags & kLinearPCMFormatFlagIsBigEndian)) {
|
||||
wordSize = -wordSize;
|
||||
strlcat(fmtstr, " LEI", sizeof(fmtstr));
|
||||
} else {
|
||||
strlcat(fmtstr, " BEI", sizeof(fmtstr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
show(abl, framesToPrint, wordSize, label, fmtstr);
|
||||
}
|
||||
|
||||
void CAShowAudioBufferList(const AudioBufferList &abl, int framesToPrint, int wordSize, const char *label)
|
||||
{
|
||||
show(abl, framesToPrint, wordSize, label);
|
||||
}
|
||||
|
||||
extern "C" void CAShowAudioBufferList(const AudioBufferList *abl, int framesToPrint, int wordSize)
|
||||
{
|
||||
show(*abl, framesToPrint, wordSize, NULL);
|
||||
}
|
||||
|
||||
#pragma mark- CrashIfClientProvidedBogusAudioBufferList Diagostic Function
|
||||
// if the return result is odd, there was a null buffer.
|
||||
/*
|
||||
extern "C" int CrashIfClientProvidedBogusAudioBufferList(const AudioBufferList *abl, bool nullok)
|
||||
{
|
||||
const AudioBuffer *buf = abl->mBuffers, *bufend = buf + abl->mNumberBuffers;
|
||||
int sum = 0; // defeat attempts by the compiler to optimize away the code that touches the buffers
|
||||
int anyNull = 0;
|
||||
for ( ; buf < bufend; ++buf) {
|
||||
const int *p = (const int *)buf->mData;
|
||||
if (p == NULL) {
|
||||
anyNull = 1;
|
||||
if (nullok) continue;
|
||||
}
|
||||
unsigned datasize = buf->mDataByteSize;
|
||||
if (datasize >= sizeof(int)) {
|
||||
sum += p[0];
|
||||
sum += p[datasize / sizeof(int) - 1];
|
||||
}
|
||||
}
|
||||
return anyNull | (sum & ~1);
|
||||
}
|
||||
*/
|
@ -1,286 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#ifndef __CABufferList_h__
|
||||
#define __CABufferList_h__
|
||||
|
||||
#include <stddef.h>
|
||||
#include "CAStreamBasicDescription.h"
|
||||
#include "CAXException.h"
|
||||
|
||||
void CAShowAudioBufferList(const AudioBufferList &abl, int framesToPrint, const AudioStreamBasicDescription &fmt, const char *label=NULL);
|
||||
void CAShowAudioBufferList(const AudioBufferList &abl, int framesToPrint, int wordSize, const char *label=NULL);
|
||||
extern "C" void CAShowAudioBufferList(const AudioBufferList *abl, int framesToPrint, int wordSize);
|
||||
extern "C" int CrashIfClientProvidedBogusAudioBufferList(const AudioBufferList *abl, bool nullOK=false);
|
||||
|
||||
/* ____________________________________________________________________________
|
||||
// CABufferList - variable length buffer list
|
||||
|
||||
This class is designed for use in non-simplistic cases. For AudioUnits, AUBufferList
|
||||
is preferred.
|
||||
|
||||
CABufferList can be used in one of two ways:
|
||||
- as mutable pointers into non-owned memory
|
||||
- as an immutable array of buffers (owns its own memory).
|
||||
|
||||
All buffers are assumed to have the same format (number of channels, word size), so that
|
||||
we can assume their mDataByteSizes are all the same.
|
||||
____________________________________________________________________________ */
|
||||
class CABufferList {
|
||||
public:
|
||||
void * operator new(size_t /*size*/, int nBuffers) {
|
||||
return ::operator new(sizeof(CABufferList) + (nBuffers-1) * sizeof(AudioBuffer));
|
||||
}
|
||||
static CABufferList * New(const char *name, const CAStreamBasicDescription &format)
|
||||
{
|
||||
UInt32 numBuffers = format.NumberChannelStreams(), channelsPerBuffer = format.NumberInterleavedChannels();
|
||||
return new(numBuffers) CABufferList(name, numBuffers, channelsPerBuffer);
|
||||
}
|
||||
static CABufferList * New(const CAStreamBasicDescription &format) { return New("", format); }
|
||||
|
||||
static CABufferList * New(UInt32 numBuffers, UInt32 channelsPerBuffer, const char *name="") {
|
||||
return new(numBuffers) CABufferList(name, numBuffers, channelsPerBuffer);
|
||||
}
|
||||
|
||||
protected:
|
||||
CABufferList(const char *name, UInt32 numBuffers, UInt32 channelsPerBuffer) :
|
||||
mName(name),
|
||||
mBufferMemory(NULL),
|
||||
mBufferCapacity(0)
|
||||
{
|
||||
//XAssert(numBuffers > 0 /*&& channelsPerBuffer > 0*/);
|
||||
mABL.mNumberBuffers = numBuffers;
|
||||
AudioBuffer *buf = mABL.mBuffers;
|
||||
for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
|
||||
buf->mNumberChannels = channelsPerBuffer;
|
||||
buf->mDataByteSize = 0;
|
||||
buf->mData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
~CABufferList()
|
||||
{
|
||||
if (mBufferMemory)
|
||||
delete[] mBufferMemory;
|
||||
}
|
||||
|
||||
const char * Name() { return mName; }
|
||||
|
||||
const AudioBufferList & GetBufferList() const { return mABL; }
|
||||
|
||||
AudioBufferList & GetModifiableBufferList() { return _GetBufferList(); }
|
||||
|
||||
UInt32 GetNumberBuffers() const { return mABL.mNumberBuffers; }
|
||||
|
||||
UInt32 GetNumBytes() const
|
||||
{
|
||||
return mABL.mBuffers[0].mDataByteSize;
|
||||
}
|
||||
|
||||
void SetBytes(UInt32 nBytes, void *data)
|
||||
{
|
||||
VerifyNotTrashingOwnedBuffer();
|
||||
XAssert(mABL.mNumberBuffers == 1);
|
||||
mABL.mBuffers[0].mDataByteSize = nBytes;
|
||||
mABL.mBuffers[0].mData = data;
|
||||
}
|
||||
|
||||
void CopyAllFrom(CABufferList *srcbl, CABufferList *ptrbl)
|
||||
// copies bytes from srcbl
|
||||
// make ptrbl reflect the length copied
|
||||
// note that srcbl may be same as ptrbl!
|
||||
{
|
||||
// Note that this buffer *can* own memory and its pointers/lengths are not
|
||||
// altered; only its buffer contents, which are copied from srcbl.
|
||||
// The pointers/lengths in ptrbl are updated to reflect the addresses/lengths
|
||||
// of the copied data, and srcbl's contents are consumed.
|
||||
ptrbl->VerifyNotTrashingOwnedBuffer();
|
||||
UInt32 nBytes = srcbl->GetNumBytes();
|
||||
AudioBuffer *mybuf = mABL.mBuffers, *srcbuf = srcbl->mABL.mBuffers,
|
||||
*ptrbuf = ptrbl->mABL.mBuffers;
|
||||
for (UInt32 i = mABL.mNumberBuffers; i--; ++mybuf, ++srcbuf, ++ptrbuf) {
|
||||
memmove(mybuf->mData, srcbuf->mData, srcbuf->mDataByteSize);
|
||||
ptrbuf->mData = mybuf->mData;
|
||||
ptrbuf->mDataByteSize = srcbuf->mDataByteSize;
|
||||
}
|
||||
if (srcbl != ptrbl)
|
||||
srcbl->BytesConsumed(nBytes);
|
||||
}
|
||||
|
||||
// copies data from another buffer list.
|
||||
void CopyDataFrom(const AudioBufferList &other)
|
||||
{
|
||||
for (unsigned i = 0; i < other.mNumberBuffers; ++i) {
|
||||
XAssert(mBufferCapacity == 0 || other.mBuffers[i].mDataByteSize <= mBufferCapacity);
|
||||
memcpy(mABL.mBuffers[i].mData, other.mBuffers[i].mData,
|
||||
mABL.mBuffers[i].mDataByteSize = other.mBuffers[i].mDataByteSize);
|
||||
}
|
||||
}
|
||||
|
||||
void AppendFrom(CABufferList *blp, UInt32 nBytes)
|
||||
{
|
||||
// this may mutate a buffer that owns memory.
|
||||
AudioBuffer *mybuf = mABL.mBuffers, *srcbuf = blp->mABL.mBuffers;
|
||||
for (UInt32 i = mABL.mNumberBuffers; i--; ++mybuf, ++srcbuf) {
|
||||
XAssert(nBytes <= srcbuf->mDataByteSize);
|
||||
XAssert(mBufferCapacity == 0 || mybuf->mDataByteSize + nBytes <= mBufferCapacity);
|
||||
memcpy((Byte *)mybuf->mData + mybuf->mDataByteSize, srcbuf->mData, nBytes);
|
||||
mybuf->mDataByteSize += nBytes;
|
||||
}
|
||||
blp->BytesConsumed(nBytes);
|
||||
}
|
||||
|
||||
void PadWithZeroes(UInt32 desiredBufferSize)
|
||||
// for cases where an algorithm (e.g. SRC) requires some
|
||||
// padding to create silence following end-of-file
|
||||
{
|
||||
XAssert(mBufferCapacity == 0 || desiredBufferSize <= mBufferCapacity);
|
||||
if (GetNumBytes() > desiredBufferSize) return;
|
||||
AudioBuffer *buf = mABL.mBuffers;
|
||||
for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
|
||||
memset((Byte *)buf->mData + buf->mDataByteSize, 0, desiredBufferSize - buf->mDataByteSize);
|
||||
buf->mDataByteSize = desiredBufferSize;
|
||||
}
|
||||
}
|
||||
|
||||
void SetToZeroes(UInt32 nBytes)
|
||||
{
|
||||
XAssert(mBufferCapacity == 0 || nBytes <= mBufferCapacity);
|
||||
AudioBuffer *buf = mABL.mBuffers;
|
||||
for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
|
||||
memset((Byte *)buf->mData, 0, nBytes);
|
||||
buf->mDataByteSize = nBytes;
|
||||
}
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
DeallocateBuffers();
|
||||
}
|
||||
|
||||
Boolean SameDataAs(const CABufferList* anotherBufferList)
|
||||
{
|
||||
// check to see if two buffer lists point to the same memory.
|
||||
if (mABL.mNumberBuffers != anotherBufferList->mABL.mNumberBuffers) return false;
|
||||
|
||||
for (UInt32 i = 0; i < mABL.mNumberBuffers; ++i) {
|
||||
if (mABL.mBuffers[i].mData != anotherBufferList->mABL.mBuffers[i].mData) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BytesConsumed(UInt32 nBytes)
|
||||
// advance buffer pointers, decrease buffer sizes
|
||||
{
|
||||
VerifyNotTrashingOwnedBuffer();
|
||||
AudioBuffer *buf = mABL.mBuffers;
|
||||
for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
|
||||
XAssert(nBytes <= buf->mDataByteSize);
|
||||
buf->mData = (Byte *)buf->mData + nBytes;
|
||||
buf->mDataByteSize -= nBytes;
|
||||
}
|
||||
}
|
||||
|
||||
void SetFrom(const AudioBufferList *abl)
|
||||
{
|
||||
VerifyNotTrashingOwnedBuffer();
|
||||
memcpy(&_GetBufferList(), abl, (char *)&abl->mBuffers[abl->mNumberBuffers] - (char *)abl);
|
||||
}
|
||||
|
||||
void SetFrom(const CABufferList *blp)
|
||||
{
|
||||
SetFrom(&blp->GetBufferList());
|
||||
}
|
||||
|
||||
void SetFrom(const AudioBufferList *abl, UInt32 nBytes)
|
||||
{
|
||||
VerifyNotTrashingOwnedBuffer();
|
||||
AudioBuffer *mybuf = mABL.mBuffers;
|
||||
const AudioBuffer *srcbuf = abl->mBuffers;
|
||||
for (UInt32 i = mABL.mNumberBuffers; i--; ++mybuf, ++srcbuf) {
|
||||
mybuf->mNumberChannels = srcbuf->mNumberChannels;
|
||||
mybuf->mDataByteSize = nBytes;
|
||||
mybuf->mData = srcbuf->mData;
|
||||
}
|
||||
}
|
||||
|
||||
void SetFrom(const CABufferList *blp, UInt32 nBytes)
|
||||
{
|
||||
SetFrom(&blp->GetBufferList(), nBytes);
|
||||
}
|
||||
|
||||
AudioBufferList * ToAudioBufferList(AudioBufferList *abl) const
|
||||
{
|
||||
memcpy(abl, &GetBufferList(), (char *)&abl->mBuffers[mABL.mNumberBuffers] - (char *)abl);
|
||||
return abl;
|
||||
}
|
||||
|
||||
void AllocateBuffers(UInt32 nBytes);
|
||||
void AllocateBuffersAndCopyFrom(UInt32 nBytes, CABufferList *inCopyFromList, CABufferList *inSetPtrList);
|
||||
|
||||
void DeallocateBuffers();
|
||||
|
||||
void UseExternalBuffer(Byte *ptr, UInt32 nBytes);
|
||||
|
||||
void AdvanceBufferPointers(UInt32 nBytes) // $$$ ReducingSize
|
||||
// this is for bufferlists that function simply as
|
||||
// an array of pointers into another bufferlist, being advanced,
|
||||
// as in RenderOutput implementations
|
||||
{
|
||||
VerifyNotTrashingOwnedBuffer();
|
||||
AudioBuffer *buf = mABL.mBuffers;
|
||||
for (UInt32 i = mABL.mNumberBuffers; i--; ++buf) {
|
||||
buf->mData = (Byte *)buf->mData + nBytes;
|
||||
buf->mDataByteSize -= nBytes;
|
||||
}
|
||||
}
|
||||
|
||||
void SetNumBytes(UInt32 nBytes)
|
||||
{
|
||||
XAssert(mBufferCapacity == 0 || nBytes <= mBufferCapacity);
|
||||
AudioBuffer *buf = mABL.mBuffers;
|
||||
for (UInt32 i = mABL.mNumberBuffers; i--; ++buf)
|
||||
buf->mDataByteSize = nBytes;
|
||||
}
|
||||
|
||||
void Print(const char *label=NULL, int nframes=0, int wordSize=0) const
|
||||
{
|
||||
if (label == NULL)
|
||||
label = mName;
|
||||
printf("%s - ", label);
|
||||
CAShowAudioBufferList(&GetBufferList(), nframes, wordSize);
|
||||
if (mBufferMemory)
|
||||
printf(" owned memory @ 0x%p:\n", mBufferMemory);
|
||||
}
|
||||
|
||||
UInt32 GetCapacityBytes() const { return mBufferCapacity; }
|
||||
|
||||
template <typename T>
|
||||
T* GetData(UInt32 inBuffer) {
|
||||
return static_cast<T*>(mABL.mBuffers[inBuffer].mData);
|
||||
}
|
||||
|
||||
protected:
|
||||
AudioBufferList & _GetBufferList() { return mABL; } // use with care
|
||||
// if we make this public, then we lose ability to call VerifyNotTrashingOwnedBuffer
|
||||
void VerifyNotTrashingOwnedBuffer()
|
||||
{
|
||||
// This needs to be called from places where we are modifying the buffer pointers.
|
||||
// It's an error to modify the buffer pointers or lengths if we own the buffer memory.
|
||||
XAssert(mBufferMemory == NULL);
|
||||
}
|
||||
|
||||
const char * mName; // for debugging
|
||||
Byte * mBufferMemory;
|
||||
UInt32 mBufferCapacity; // max mDataByteSize of each buffer
|
||||
AudioBufferList mABL;
|
||||
// don't add anything here
|
||||
};
|
||||
|
||||
#endif // __CABufferList_h__
|
@ -1,123 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#if !defined(__CAByteOrder_h__)
|
||||
#define __CAByteOrder_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
// System Includes
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#else
|
||||
#include "CoreFoundation.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
CF_INLINE Float32 CASwapFloat32 (Float32 arg) {
|
||||
union {
|
||||
Float32 f;
|
||||
UInt32 i;
|
||||
} flip;
|
||||
|
||||
flip.f = arg;
|
||||
flip.i = CFSwapInt32 (flip.i);
|
||||
|
||||
return flip.f;
|
||||
}
|
||||
|
||||
CF_INLINE Float64 CASwapFloat64 (Float64 arg) {
|
||||
union {
|
||||
Float64 f;
|
||||
UInt64 i;
|
||||
} flip;
|
||||
|
||||
flip.f = arg;
|
||||
flip.i = CFSwapInt64 (flip.i);
|
||||
|
||||
return flip.f;
|
||||
}
|
||||
|
||||
#pragma mark -Flippers
|
||||
|
||||
CF_INLINE Float32 CASwapFloat32BigToHost(Float32 arg) {
|
||||
#if defined(__BIG_ENDIAN__)
|
||||
return arg;
|
||||
#else
|
||||
return CASwapFloat32(arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
CF_INLINE Float64 CASwapFloat64BigToHost(Float64 arg) {
|
||||
#if defined(__BIG_ENDIAN__)
|
||||
return arg;
|
||||
#else
|
||||
return CASwapFloat64(arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
CF_INLINE Float32 CASwapFloat32HostToBig(Float32 arg) {
|
||||
#if defined(__BIG_ENDIAN__)
|
||||
return arg;
|
||||
#else
|
||||
return CASwapFloat32(arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
CF_INLINE Float64 CASwapFloat64HostToBig(Float64 arg) {
|
||||
#if defined(__BIG_ENDIAN__)
|
||||
return arg;
|
||||
#else
|
||||
return CASwapFloat64(arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
CF_INLINE Float32 CASwapFloat32LittleToHost(Float32 arg) {
|
||||
#if defined(__LITTLE_ENDIAN__)
|
||||
return arg;
|
||||
#else
|
||||
return CASwapFloat32(arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
CF_INLINE Float64 CASwapFloat64LittleToHost(Float64 arg) {
|
||||
#if defined(__LITTLE_ENDIAN__)
|
||||
return arg;
|
||||
#else
|
||||
return CASwapFloat64(arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
CF_INLINE Float32 CASwapFloat32HostToLittle(Float32 arg) {
|
||||
#if defined(__LITTLE_ENDIAN__)
|
||||
return arg;
|
||||
#else
|
||||
return CASwapFloat32(arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
CF_INLINE Float64 CASwapFloat64HostToLittle(Float64 arg) {
|
||||
#if defined(__LITTLE_ENDIAN__)
|
||||
return arg;
|
||||
#else
|
||||
return CASwapFloat64(arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#include "CADebugMacros.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#if TARGET_API_MAC_OSX
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
#include <stdio.h>
|
||||
|
||||
void DebugPrint(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
void LogError(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
#if DEBUG
|
||||
vprintf(fmt, args);
|
||||
#endif
|
||||
#if TARGET_API_MAC_OSX
|
||||
vsyslog(LOG_ERR, fmt, args);
|
||||
#endif
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void LogWarning(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
#if DEBUG
|
||||
vprintf(fmt, args);
|
||||
#endif
|
||||
#if TARGET_API_MAC_OSX
|
||||
vsyslog(LOG_WARNING, fmt, args);
|
||||
#endif
|
||||
va_end(args);
|
||||
}
|
@ -1,433 +0,0 @@
|
||||
/* Copyright © 2007 Apple Inc. All Rights Reserved.
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by
|
||||
Apple Inc. ("Apple") in consideration of your agreement to the
|
||||
following terms, and your use, installation, modification or
|
||||
redistribution of this Apple software constitutes acceptance of these
|
||||
terms. If you do not agree with these terms, please do not use,
|
||||
install, modify or redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc.
|
||||
may be used to endorse or promote products derived from the Apple
|
||||
Software without specific prior written permission from Apple. Except
|
||||
as expressly stated in this notice, no other rights or licenses, express
|
||||
or implied, are granted by Apple herein, including but not limited to
|
||||
any patent rights that may be infringed by your derivative works or by
|
||||
other works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*=============================================================================
|
||||
CADebugMacros.h
|
||||
|
||||
=============================================================================*/
|
||||
#if !defined(__CADebugMacros_h__)
|
||||
#define __CADebugMacros_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include "CoreAudioTypes.h"
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// CADebugMacros
|
||||
//=============================================================================
|
||||
|
||||
//#define CoreAudio_StopOnFailure 1
|
||||
//#define CoreAudio_TimeStampMessages 1
|
||||
//#define CoreAudio_ThreadStampMessages 1
|
||||
//#define CoreAudio_FlushDebugMessages 1
|
||||
|
||||
#if TARGET_RT_BIG_ENDIAN
|
||||
#define CA4CCToCString(the4CC) { ((char*)&the4CC)[0], ((char*)&the4CC)[1], ((char*)&the4CC)[2], ((char*)&the4CC)[3], 0 }
|
||||
#define CACopy4CCToCString(theCString, the4CC) { theCString[0] = ((char*)&the4CC)[0]; theCString[1] = ((char*)&the4CC)[1]; theCString[2] = ((char*)&the4CC)[2]; theCString[3] = ((char*)&the4CC)[3]; theCString[4] = 0; }
|
||||
#else
|
||||
#define CA4CCToCString(the4CC) { ((char*)&the4CC)[3], ((char*)&the4CC)[2], ((char*)&the4CC)[1], ((char*)&the4CC)[0], 0 }
|
||||
#define CACopy4CCToCString(theCString, the4CC) { theCString[0] = ((char*)&the4CC)[3]; theCString[1] = ((char*)&the4CC)[2]; theCString[2] = ((char*)&the4CC)[1]; theCString[3] = ((char*)&the4CC)[0]; theCString[4] = 0; }
|
||||
#endif
|
||||
|
||||
#pragma mark Basic Definitions
|
||||
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
|
||||
// can be used to break into debugger immediately, also see CADebugger
|
||||
#define BusError() (*(long *)0 = 0)
|
||||
|
||||
// basic debugging print routines
|
||||
#if TARGET_OS_MAC && !TARGET_API_MAC_CARBON
|
||||
extern pascal void DebugStr(const unsigned char* debuggerMsg);
|
||||
#define DebugMessage(msg) DebugStr("\p"msg)
|
||||
#define DebugMessageN1(msg, N1)
|
||||
#define DebugMessageN2(msg, N1, N2)
|
||||
#define DebugMessageN3(msg, N1, N2, N3)
|
||||
#else
|
||||
#include "CADebugPrintf.h"
|
||||
|
||||
#if (CoreAudio_FlushDebugMessages && !CoreAudio_UseSysLog) || defined(CoreAudio_UseSideFile)
|
||||
#define FlushRtn ;fflush(DebugPrintfFile)
|
||||
#else
|
||||
#define FlushRtn
|
||||
#endif
|
||||
|
||||
#if CoreAudio_ThreadStampMessages
|
||||
#include <pthread.h>
|
||||
#include "CAHostTimeBase.h"
|
||||
#define DebugMessage(msg) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: %s"DebugPrintfLineEnding, pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), msg) FlushRtn
|
||||
#define DebugMessageN1(msg, N1) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1) FlushRtn
|
||||
#define DebugMessageN2(msg, N1, N2) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2) FlushRtn
|
||||
#define DebugMessageN3(msg, N1, N2, N3) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3) FlushRtn
|
||||
#define DebugMessageN4(msg, N1, N2, N3, N4) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4) FlushRtn
|
||||
#define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5) FlushRtn
|
||||
#define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6) FlushRtn
|
||||
#define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7) FlushRtn
|
||||
#define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7, N8) FlushRtn
|
||||
#define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: "msg"\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7, N8, N9) FlushRtn
|
||||
#elif CoreAudio_TimeStampMessages
|
||||
#include "CAHostTimeBase.h"
|
||||
#define DebugMessage(msg) DebugPrintfRtn(DebugPrintfFileComma "%.4f: %s"DebugPrintfLineEnding, pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), msg) FlushRtn
|
||||
#define DebugMessageN1(msg, N1) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1) FlushRtn
|
||||
#define DebugMessageN2(msg, N1, N2) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2) FlushRtn
|
||||
#define DebugMessageN3(msg, N1, N2, N3) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3) FlushRtn
|
||||
#define DebugMessageN4(msg, N1, N2, N3, N4) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4) FlushRtn
|
||||
#define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5) FlushRtn
|
||||
#define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6) FlushRtn
|
||||
#define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7) FlushRtn
|
||||
#define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7, N8) FlushRtn
|
||||
#define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugPrintfRtn(DebugPrintfFileComma "%.4f: "msg DebugPrintfLineEnding, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), N1, N2, N3, N4, N5, N6, N7, N8, N9) FlushRtn
|
||||
#else
|
||||
#define DebugMessage(msg) DebugPrintfRtn(DebugPrintfFileComma "%s"DebugPrintfLineEnding, msg) FlushRtn
|
||||
#define DebugMessageN1(msg, N1) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1) FlushRtn
|
||||
#define DebugMessageN2(msg, N1, N2) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2) FlushRtn
|
||||
#define DebugMessageN3(msg, N1, N2, N3) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3) FlushRtn
|
||||
#define DebugMessageN4(msg, N1, N2, N3, N4) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4) FlushRtn
|
||||
#define DebugMessageN5(msg, N1, N2, N3, N4, N5) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4, N5) FlushRtn
|
||||
#define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6) FlushRtn
|
||||
#define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6, N7) FlushRtn
|
||||
#define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6, N7, N8) FlushRtn
|
||||
#define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9) DebugPrintfRtn(DebugPrintfFileComma msg DebugPrintfLineEnding, N1, N2, N3, N4, N5, N6, N7, N8, N9) FlushRtn
|
||||
#endif
|
||||
#endif
|
||||
void DebugPrint(const char *fmt, ...); // can be used like printf
|
||||
#define DEBUGPRINT(msg) DebugPrint msg // have to double-parenthesize arglist (see Debugging.h)
|
||||
#if VERBOSE
|
||||
#define vprint(msg) DEBUGPRINT(msg)
|
||||
#else
|
||||
#define vprint(msg)
|
||||
#endif
|
||||
|
||||
#if CoreAudio_StopOnFailure
|
||||
#include "CADebugger.h"
|
||||
#define STOP CADebuggerStop()
|
||||
#else
|
||||
#define STOP
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define DebugMessage(msg)
|
||||
#define DebugMessageN1(msg, N1)
|
||||
#define DebugMessageN2(msg, N1, N2)
|
||||
#define DebugMessageN3(msg, N1, N2, N3)
|
||||
#define DebugMessageN4(msg, N1, N2, N3, N4)
|
||||
#define DebugMessageN5(msg, N1, N2, N3, N4, N5)
|
||||
#define DebugMessageN6(msg, N1, N2, N3, N4, N5, N6)
|
||||
#define DebugMessageN7(msg, N1, N2, N3, N4, N5, N6, N7)
|
||||
#define DebugMessageN8(msg, N1, N2, N3, N4, N5, N6, N7, N8)
|
||||
#define DebugMessageN9(msg, N1, N2, N3, N4, N5, N6, N7, N8, N9)
|
||||
#define DEBUGPRINT(msg)
|
||||
#define vprint(msg)
|
||||
#define STOP
|
||||
#endif
|
||||
|
||||
void LogError(const char *fmt, ...); // writes to syslog (and stderr if debugging)
|
||||
void LogWarning(const char *fmt, ...); // writes to syslog (and stderr if debugging)
|
||||
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
|
||||
#pragma mark Debug Macros
|
||||
|
||||
#define Assert(inCondition, inMessage) \
|
||||
if(!(inCondition)) \
|
||||
{ \
|
||||
DebugMessage(inMessage); \
|
||||
STOP; \
|
||||
}
|
||||
|
||||
#define AssertNoError(inError, inMessage) \
|
||||
{ \
|
||||
SInt32 __Err = (inError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
char __4CC[5] = CA4CCToCString(__Err); \
|
||||
DebugMessageN2(inMessage ", Error: %d (%s)", (int)__Err, __4CC); \
|
||||
STOP; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define AssertNoKernelError(inError, inMessage) \
|
||||
{ \
|
||||
unsigned int __Err = (unsigned int)(inError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
DebugMessageN1(inMessage ", Error: 0x%X", __Err); \
|
||||
STOP; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FailIf(inCondition, inHandler, inMessage) \
|
||||
if(inCondition) \
|
||||
{ \
|
||||
DebugMessage(inMessage); \
|
||||
STOP; \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailWithAction(inCondition, inAction, inHandler, inMessage) \
|
||||
if(inCondition) \
|
||||
{ \
|
||||
DebugMessage(inMessage); \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailIfNULL(inPointer, inAction, inHandler, inMessage) \
|
||||
if((inPointer) == NULL) \
|
||||
{ \
|
||||
DebugMessage(inMessage); \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailIfKernelError(inKernelError, inException, inMessage) \
|
||||
{ \
|
||||
kern_return_t __Err = (inKernelError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
DebugMessageN1(inMessage ", Error: 0x%X", __Err); \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FailIfError(inError, inException, inMessage) \
|
||||
{ \
|
||||
SInt32 __Err = (inError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
char __4CC[5] = CA4CCToCString(__Err); \
|
||||
DebugMessageN2(inMessage ", Error: %ld (%s)", __Err, __4CC); \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
} \
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
#define Throw(inException) STOP; throw (inException)
|
||||
|
||||
#define ThrowIf(inCondition, inException, inMessage) \
|
||||
if(inCondition) \
|
||||
{ \
|
||||
DebugMessage(inMessage); \
|
||||
Throw(inException); \
|
||||
}
|
||||
|
||||
#define ThrowIfNULL(inPointer, inException, inMessage) \
|
||||
if((inPointer) == NULL) \
|
||||
{ \
|
||||
DebugMessage(inMessage); \
|
||||
Throw(inException); \
|
||||
}
|
||||
|
||||
#define ThrowIfKernelError(inKernelError, inException, inMessage) \
|
||||
{ \
|
||||
kern_return_t __Err = (inKernelError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
DebugMessageN1(inMessage ", Error: 0x%X", __Err); \
|
||||
Throw(inException); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ThrowIfError(inError, inException, inMessage) \
|
||||
{ \
|
||||
SInt32 __Err = (inError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
char __4CC[5] = CA4CCToCString(__Err); \
|
||||
DebugMessageN2(inMessage ", Error: %d (%s)", (int)__Err, __4CC); \
|
||||
Throw(inException); \
|
||||
} \
|
||||
}
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
#define ThrowIfWinError(inError, inException, inMessage) \
|
||||
{ \
|
||||
HRESULT __Err = (inError); \
|
||||
if(FAILED(__Err)) \
|
||||
{ \
|
||||
DebugMessageN2(inMessage ", Code: %d, Facility: 0x%X", HRESULT_CODE(__Err), HRESULT_FACILITY(__Err)); \
|
||||
Throw(inException); \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SubclassResponsibility(inMethodName, inException) \
|
||||
{ \
|
||||
DebugMessage(inMethodName": Subclasses must implement this method"); \
|
||||
Throw(inException); \
|
||||
}
|
||||
|
||||
#endif // defined(__cplusplus)
|
||||
|
||||
#else
|
||||
|
||||
#pragma mark Release Macros
|
||||
|
||||
#define Assert(inCondition, inMessage) \
|
||||
if(!(inCondition)) \
|
||||
{ \
|
||||
STOP; \
|
||||
}
|
||||
|
||||
#define AssertNoError(inError, inMessage) \
|
||||
{ \
|
||||
SInt32 __Err = (inError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
STOP; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define AssertNoKernelError(inError, inMessage) \
|
||||
{ \
|
||||
unsigned int __Err = (unsigned int)(inError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
STOP; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FailIf(inCondition, inHandler, inMessage) \
|
||||
if(inCondition) \
|
||||
{ \
|
||||
STOP; \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailWithAction(inCondition, inAction, inHandler, inMessage) \
|
||||
if(inCondition) \
|
||||
{ \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailIfNULL(inPointer, inAction, inHandler, inMessage) \
|
||||
if((inPointer) == NULL) \
|
||||
{ \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailIfKernelError(inKernelError, inException, inMessage) \
|
||||
if((inKernelError) != 0) \
|
||||
{ \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#define FailIfError(inError, inException, inMessage) \
|
||||
if((inError) != 0) \
|
||||
{ \
|
||||
STOP; \
|
||||
{ inAction; } \
|
||||
goto inHandler; \
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
#define Throw(inException) STOP; throw (inException)
|
||||
|
||||
#define ThrowIf(inCondition, inException, inMessage) \
|
||||
if(inCondition) \
|
||||
{ \
|
||||
Throw(inException); \
|
||||
}
|
||||
|
||||
#define ThrowIfNULL(inPointer, inException, inMessage) \
|
||||
if((inPointer) == NULL) \
|
||||
{ \
|
||||
Throw(inException); \
|
||||
}
|
||||
|
||||
#define ThrowIfKernelError(inKernelError, inException, inMessage) \
|
||||
{ \
|
||||
kern_return_t __Err = (inKernelError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
Throw(inException); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ThrowIfError(inError, inException, inMessage) \
|
||||
{ \
|
||||
SInt32 __Err = (inError); \
|
||||
if(__Err != 0) \
|
||||
{ \
|
||||
Throw(inException); \
|
||||
} \
|
||||
}
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
#define ThrowIfWinError(inError, inException, inMessage) \
|
||||
{ \
|
||||
HRESULT __Err = (inError); \
|
||||
if(FAILED(__Err)) \
|
||||
{ \
|
||||
Throw(inException); \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SubclassResponsibility(inMethodName, inException) \
|
||||
{ \
|
||||
Throw(inException); \
|
||||
}
|
||||
|
||||
#endif // defined(__cplusplus)
|
||||
|
||||
#endif // DEBUG || CoreAudio_Debug
|
||||
|
||||
#endif
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
//==================================================================================================
|
||||
// Includes
|
||||
//==================================================================================================
|
||||
|
||||
// Self Include
|
||||
#include "CADebugPrintf.h"
|
||||
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <Windows.h>
|
||||
extern "C"
|
||||
int CAWin32DebugPrintf(char* inFormat, ...)
|
||||
{
|
||||
char theMessage[1024];
|
||||
va_list theArguments;
|
||||
va_start(theArguments, inFormat);
|
||||
_vsnprintf(theMessage, 1024, inFormat, theArguments);
|
||||
va_end(theArguments);
|
||||
OutputDebugString(theMessage);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CoreAudio_UseSideFile)
|
||||
#include <unistd.h>
|
||||
FILE* sDebugPrintfSideFile = NULL;
|
||||
extern "C"
|
||||
void OpenDebugPrintfSideFile()
|
||||
{
|
||||
if(sDebugPrintfSideFile == NULL)
|
||||
{
|
||||
char theFileName[1024];
|
||||
snprintf(theFileName, sizeof(theFileName), CoreAudio_UseSideFile, getpid());
|
||||
sDebugPrintfSideFile = fopen(theFileName, "a+");
|
||||
DebugPrintfRtn(DebugPrintfFileComma "\n------------------------------\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,89 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#if !defined(__CADebugPrintf_h__)
|
||||
#define __CADebugPrintf_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include "CoreAudioTypes.h"
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// Macros to redirect debugging output to various logging services
|
||||
//=============================================================================
|
||||
|
||||
//#define CoreAudio_UseSideFile "/CoreAudio-%d.txt"
|
||||
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
#endif
|
||||
extern int CAWin32DebugPrintf(char* inFormat, ...);
|
||||
#define DebugPrintfRtn CAWin32DebugPrintf
|
||||
#define DebugPrintfFile
|
||||
#define DebugPrintfLineEnding "\n"
|
||||
#define DebugPrintfFileComma
|
||||
#define DebugPrintf(inFormat, ...) CAWin32DebugPrintf(informat "\n", ## __VA_ARGS__)
|
||||
#else
|
||||
#if CoreAudio_UseSysLog
|
||||
#include <sys/syslog.h>
|
||||
#define DebugPrintfRtn syslog
|
||||
#define DebugPrintfFile LOG_NOTICE
|
||||
#define DebugPrintfLineEnding ""
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#define DebugPrintf(inFormat, ...) DebugPrintfRtn(DebugPrintfFileComma inFormat DebugPrintfLineEnding, ## __VA_ARGS__)
|
||||
#elif defined(CoreAudio_UseSideFile)
|
||||
#include <stdio.h>
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
#endif
|
||||
void OpenDebugPrintfSideFile();
|
||||
extern FILE* sDebugPrintfSideFile;
|
||||
#define DebugPrintfRtn fprintf
|
||||
#define DebugPrintfFile ((sDebugPrintfSideFile != NULL) ? sDebugPrintfSideFile : stderr)
|
||||
#define DebugPrintfLineEnding "\n"
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#define DebugPrintf(inFormat, ...) DebugPrintfRtn(DebugPrintfFileComma inFormat DebugPrintfLineEnding, ## __VA_ARGS__)
|
||||
#elif CoreAudio_UseCALog
|
||||
#include "CALog.h"
|
||||
/* We cannot use 'LOG' for 'DebugPrintfRtn' because it is a concatenating macro itself. So we have to use syslog here. */
|
||||
#include <sys/syslog.h>
|
||||
#define DebugPrintfRtn syslog
|
||||
#define DebugPrintfFile LOG_NOTICE
|
||||
#define DebugPrintfLineEnding ""
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
/* Direct calls to 'DebugPrintf' use the new CALog system */
|
||||
#define DebugPrintf(inFormat, ...) LOG(kLogPriority_Notice, 0, inFormat, ## __VA_ARGS__)
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#define DebugPrintfRtn fprintf
|
||||
#define DebugPrintfFile stderr
|
||||
#define DebugPrintfLineEnding "\n"
|
||||
#define DebugPrintfFileComma DebugPrintfFile,
|
||||
#define DebugPrintf(inFormat, ...) DebugPrintfRtn(DebugPrintfFileComma inFormat DebugPrintfLineEnding, ## __VA_ARGS__)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define DebugPrintfRtn
|
||||
#define DebugPrintfFile
|
||||
#define DebugPrintfLineEnding
|
||||
#define DebugPrintfFileComma
|
||||
#define DebugPrintf(inFormat, ...)
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#include "CADebugger.h"
|
||||
|
||||
//=============================================================================
|
||||
// CADebugger
|
||||
//=============================================================================
|
||||
|
||||
#if TARGET_API_MAC_OSX
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
bool CAIsDebuggerAttached(void)
|
||||
{
|
||||
int mib[4];
|
||||
struct kinfo_proc info;
|
||||
size_t size;
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PID;
|
||||
mib[3] = getpid();
|
||||
size = sizeof(info);
|
||||
info.kp_proc.p_flag = 0;
|
||||
|
||||
sysctl(mib, 4, &info, &size, NULL, 0);
|
||||
|
||||
return (info.kp_proc.p_flag & P_TRACED) == P_TRACED;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void CADebuggerStop(void)
|
||||
{
|
||||
#if CoreAudio_Debug
|
||||
#if TARGET_API_MAC_OSX
|
||||
if(CAIsDebuggerAttached())
|
||||
{
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
asm("int3");
|
||||
#else
|
||||
__builtin_trap();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
abort();
|
||||
}
|
||||
#else
|
||||
__debugbreak();
|
||||
#endif
|
||||
#endif
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#if !defined(__CADebugger_h__)
|
||||
#define __CADebugger_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// CADebugger
|
||||
//=============================================================================
|
||||
|
||||
#if TARGET_API_MAC_OSX
|
||||
extern bool CAIsDebuggerAttached(void);
|
||||
#endif
|
||||
extern void CADebuggerStop(void);
|
||||
|
||||
#endif
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#if !defined(__CAException_h__)
|
||||
#define __CAException_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include "CoreAudioTypes.h"
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// CAException
|
||||
//=============================================================================
|
||||
|
||||
class CAException
|
||||
{
|
||||
|
||||
public:
|
||||
CAException(OSStatus inError) : mError(inError) {}
|
||||
CAException(const CAException& inException) : mError(inException.mError) {}
|
||||
CAException& operator=(const CAException& inException) { mError = inException.mError; return *this; }
|
||||
~CAException() {}
|
||||
|
||||
OSStatus GetError() const { return mError; }
|
||||
|
||||
protected:
|
||||
OSStatus mError;
|
||||
};
|
||||
|
||||
#define CATry try{
|
||||
#define CACatch } catch(...) {}
|
||||
#define CASwallowException(inExpression) try { inExpression; } catch(...) {}
|
||||
|
||||
#endif
|
@ -1,305 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
//==================================================================================================
|
||||
// Includes
|
||||
//==================================================================================================
|
||||
|
||||
// Self Include
|
||||
#include "CAGuard.h"
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
// PublicUtility Inludes
|
||||
#include "CADebugMacros.h"
|
||||
#include "CAException.h"
|
||||
#include "CAHostTimeBase.h"
|
||||
|
||||
//==================================================================================================
|
||||
// Logging
|
||||
//==================================================================================================
|
||||
|
||||
#if CoreAudio_Debug
|
||||
// #define Log_Ownership 1
|
||||
// #define Log_WaitOwnership 1
|
||||
// #define Log_TimedWaits 1
|
||||
// #define Log_Latency 1
|
||||
// #define Log_Errors 1
|
||||
#endif
|
||||
|
||||
//#warning Need a try-based Locker too
|
||||
//==================================================================================================
|
||||
// CAGuard
|
||||
//==================================================================================================
|
||||
|
||||
CAGuard::CAGuard(const char* inName)
|
||||
:
|
||||
CAMutex(inName)
|
||||
#if Log_Average_Latency
|
||||
,mAverageLatencyAccumulator(0.0),
|
||||
mAverageLatencyCount(0)
|
||||
#endif
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
OSStatus theError = pthread_cond_init(&mCondVar, NULL);
|
||||
ThrowIf(theError != 0, CAException(theError), "CAGuard::CAGuard: Could not init the cond var");
|
||||
#elif TARGET_OS_WIN32
|
||||
mEvent = CreateEvent(NULL, true, false, NULL);
|
||||
ThrowIfNULL(mEvent, CAException(GetLastError()), "CAGuard::CAGuard: Could not create the event");
|
||||
#endif
|
||||
}
|
||||
|
||||
CAGuard::~CAGuard()
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
pthread_cond_destroy(&mCondVar);
|
||||
#elif TARGET_OS_WIN32
|
||||
if(mEvent != NULL)
|
||||
{
|
||||
CloseHandle(mEvent);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CAGuard::Wait()
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
ThrowIf(!pthread_equal(pthread_self(), mOwner), CAException(1), "CAGuard::Wait: A thread has to have locked a guard before it can wait");
|
||||
|
||||
mOwner = 0;
|
||||
|
||||
#if Log_WaitOwnership
|
||||
DebugPrintf("%p %.4f: CAGuard::Wait: thread %p is waiting on %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
OSStatus theError = pthread_cond_wait(&mCondVar, &mMutex);
|
||||
ThrowIf(theError != 0, CAException(theError), "CAGuard::Wait: Could not wait for a signal");
|
||||
mOwner = pthread_self();
|
||||
|
||||
#if Log_WaitOwnership
|
||||
DebugPrintf("%p %.4f: CAGuard::Wait: thread %p waited on %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
|
||||
#endif
|
||||
#elif TARGET_OS_WIN32
|
||||
ThrowIf(GetCurrentThreadId() != mOwner, CAException(1), "CAGuard::Wait: A thread has to have locked a guard before it can wait");
|
||||
|
||||
mOwner = 0;
|
||||
|
||||
#if Log_WaitOwnership
|
||||
DebugPrintf("%lu %.4f: CAGuard::Wait: thread %lu is waiting on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
ReleaseMutex(mMutex);
|
||||
HANDLE theHandles[] = { mMutex, mEvent };
|
||||
OSStatus theError = WaitForMultipleObjects(2, theHandles, true, INFINITE);
|
||||
ThrowIfError(theError, CAException(GetLastError()), "CAGuard::Wait: Could not wait for the signal");
|
||||
mOwner = GetCurrentThreadId();
|
||||
ResetEvent(mEvent);
|
||||
|
||||
#if Log_WaitOwnership
|
||||
DebugPrintf("%lu %.4f: CAGuard::Wait: thread %lu waited on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CAGuard::WaitFor(UInt64 inNanos)
|
||||
{
|
||||
bool theAnswer = false;
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
ThrowIf(!pthread_equal(pthread_self(), mOwner), CAException(1), "CAGuard::WaitFor: A thread has to have locked a guard be for it can wait");
|
||||
|
||||
#if Log_TimedWaits
|
||||
DebugMessageN1("CAGuard::WaitFor: waiting %.0f", (Float64)inNanos);
|
||||
#endif
|
||||
|
||||
struct timespec theTimeSpec;
|
||||
static const UInt64 kNanosPerSecond = 1000000000ULL;
|
||||
if(inNanos >= kNanosPerSecond)
|
||||
{
|
||||
theTimeSpec.tv_sec = static_cast<long>(inNanos / kNanosPerSecond);
|
||||
theTimeSpec.tv_nsec = static_cast<long>(inNanos % kNanosPerSecond);
|
||||
}
|
||||
else
|
||||
{
|
||||
theTimeSpec.tv_sec = 0;
|
||||
theTimeSpec.tv_nsec = static_cast<long>(inNanos);
|
||||
}
|
||||
|
||||
#if Log_TimedWaits || Log_Latency || Log_Average_Latency
|
||||
UInt64 theStartNanos = CAHostTimeBase::GetCurrentTimeInNanos();
|
||||
#endif
|
||||
|
||||
mOwner = 0;
|
||||
|
||||
#if Log_WaitOwnership
|
||||
DebugPrintf("%p %.4f: CAGuard::WaitFor: thread %p is waiting on %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
OSStatus theError = pthread_cond_timedwait_relative_np(&mCondVar, &mMutex, &theTimeSpec);
|
||||
ThrowIf((theError != 0) && (theError != ETIMEDOUT), CAException(theError), "CAGuard::WaitFor: Wait got an error");
|
||||
mOwner = pthread_self();
|
||||
|
||||
#if Log_TimedWaits || Log_Latency || Log_Average_Latency
|
||||
UInt64 theEndNanos = CAHostTimeBase::GetCurrentTimeInNanos();
|
||||
#endif
|
||||
|
||||
#if Log_TimedWaits
|
||||
DebugMessageN1("CAGuard::WaitFor: waited %.0f", (Float64)(theEndNanos - theStartNanos));
|
||||
#endif
|
||||
|
||||
#if Log_Latency
|
||||
DebugMessageN1("CAGuard::WaitFor: latency %.0f", (Float64)((theEndNanos - theStartNanos) - inNanos));
|
||||
#endif
|
||||
|
||||
#if Log_Average_Latency
|
||||
++mAverageLatencyCount;
|
||||
mAverageLatencyAccumulator += (theEndNanos - theStartNanos) - inNanos;
|
||||
if(mAverageLatencyCount >= 50)
|
||||
{
|
||||
DebugMessageN2("CAGuard::WaitFor: average latency %.3f ns over %ld waits", mAverageLatencyAccumulator / mAverageLatencyCount, mAverageLatencyCount);
|
||||
mAverageLatencyCount = 0;
|
||||
mAverageLatencyAccumulator = 0.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if Log_WaitOwnership
|
||||
DebugPrintf("%p %.4f: CAGuard::WaitFor: thread %p waited on %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
theAnswer = theError == ETIMEDOUT;
|
||||
#elif TARGET_OS_WIN32
|
||||
ThrowIf(GetCurrentThreadId() != mOwner, CAException(1), "CAGuard::WaitFor: A thread has to have locked a guard be for it can wait");
|
||||
|
||||
#if Log_TimedWaits
|
||||
DebugMessageN1("CAGuard::WaitFor: waiting %.0f", (Float64)inNanos);
|
||||
#endif
|
||||
|
||||
// the time out is specified in milliseconds(!)
|
||||
UInt32 theWaitTime = static_cast<UInt32>(inNanos / 1000000ULL);
|
||||
|
||||
#if Log_TimedWaits || Log_Latency || Log_Average_Latency
|
||||
UInt64 theStartNanos = CAHostTimeBase::GetCurrentTimeInNanos();
|
||||
#endif
|
||||
|
||||
mOwner = 0;
|
||||
|
||||
#if Log_WaitOwnership
|
||||
DebugPrintf("%lu %.4f: CAGuard::WaitFor: thread %lu is waiting on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
ReleaseMutex(mMutex);
|
||||
HANDLE theHandles[] = { mMutex, mEvent };
|
||||
OSStatus theError = WaitForMultipleObjects(2, theHandles, true, theWaitTime);
|
||||
ThrowIf((theError != WAIT_OBJECT_0) && (theError != WAIT_TIMEOUT), CAException(GetLastError()), "CAGuard::WaitFor: Wait got an error");
|
||||
mOwner = GetCurrentThreadId();
|
||||
ResetEvent(mEvent);
|
||||
// This mutex should be locked again when time out happens.rdar://12270555
|
||||
if(theError == WAIT_TIMEOUT) {
|
||||
DWORD dwError = WaitForSingleObject(mMutex, INFINITE);
|
||||
ThrowIf((dwError != WAIT_OBJECT_0), CAException(GetLastError()), "CAGuard::WaitFor: failed to acquire the mutex back when timeout happened\n");
|
||||
}
|
||||
#if Log_TimedWaits || Log_Latency || Log_Average_Latency
|
||||
UInt64 theEndNanos = CAHostTimeBase::GetCurrentTimeInNanos();
|
||||
#endif
|
||||
|
||||
#if Log_TimedWaits
|
||||
DebugMessageN1("CAGuard::WaitFor: waited %.0f", (Float64)(theEndNanos - theStartNanos));
|
||||
#endif
|
||||
|
||||
#if Log_Latency
|
||||
DebugMessageN1("CAGuard::WaitFor: latency %.0f", (Float64)((theEndNanos - theStartNanos) - inNanos));
|
||||
#endif
|
||||
|
||||
#if Log_Average_Latency
|
||||
++mAverageLatencyCount;
|
||||
mAverageLatencyAccumulator += (theEndNanos - theStartNanos) - inNanos;
|
||||
if(mAverageLatencyCount >= 50)
|
||||
{
|
||||
DebugMessageN2("CAGuard::WaitFor: average latency %.3f ns over %ld waits", mAverageLatencyAccumulator / mAverageLatencyCount, mAverageLatencyCount);
|
||||
mAverageLatencyCount = 0;
|
||||
mAverageLatencyAccumulator = 0.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if Log_WaitOwnership
|
||||
DebugPrintf("%lu %.4f: CAGuard::WaitFor: thread %lu waited on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
theAnswer = theError == WAIT_TIMEOUT;
|
||||
#endif
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
bool CAGuard::WaitUntil(UInt64 inNanos)
|
||||
{
|
||||
bool theAnswer = false;
|
||||
UInt64 theCurrentNanos = CAHostTimeBase::GetCurrentTimeInNanos();
|
||||
|
||||
#if Log_TimedWaits
|
||||
DebugMessageN2("CAGuard::WaitUntil: now: %.0f, requested: %.0f", (double)theCurrentNanos, (double)inNanos);
|
||||
#endif
|
||||
|
||||
if(inNanos > theCurrentNanos)
|
||||
{
|
||||
#if Log_Errors
|
||||
if((inNanos - theCurrentNanos) > 1000000000ULL)
|
||||
{
|
||||
DebugMessage("CAGuard::WaitUntil: about to wait for more than a second");
|
||||
}
|
||||
#endif
|
||||
theAnswer = WaitFor(inNanos - theCurrentNanos);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if Log_Errors
|
||||
DebugMessageN2("CAGuard::WaitUntil: Time has expired before waiting, now: %.0f, requested: %.0f", (double)theCurrentNanos, (double)inNanos);
|
||||
#endif
|
||||
theAnswer = true;
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
void CAGuard::Notify()
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
#if Log_WaitOwnership
|
||||
DebugPrintf("%p %.4f: CAGuard::Notify: thread %p is notifying %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
OSStatus theError = pthread_cond_signal(&mCondVar);
|
||||
ThrowIf(theError != 0, CAException(theError), "CAGuard::Notify: failed");
|
||||
#elif TARGET_OS_WIN32
|
||||
#if Log_WaitOwnership
|
||||
DebugPrintf("%lu %.4f: CAGuard::Notify: thread %lu is notifying %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
SetEvent(mEvent);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CAGuard::NotifyAll()
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
#if Log_WaitOwnership
|
||||
DebugPrintf("%p %.4f: CAGuard::NotifyAll: thread %p is notifying %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
OSStatus theError = pthread_cond_broadcast(&mCondVar);
|
||||
ThrowIf(theError != 0, CAException(theError), "CAGuard::NotifyAll: failed");
|
||||
#elif TARGET_OS_WIN32
|
||||
#if Log_WaitOwnership
|
||||
DebugPrintf("%lu %.4f: CAGuard::NotifyAll: thread %lu is notifying %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
SetEvent(mEvent);
|
||||
#endif
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#if !defined(__CAGuard_h__)
|
||||
#define __CAGuard_h__
|
||||
|
||||
//==================================================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
// Super Class Includes
|
||||
#include "CAMutex.h"
|
||||
|
||||
#if CoreAudio_Debug
|
||||
// #define Log_Average_Latency 1
|
||||
#endif
|
||||
|
||||
//==================================================================================================
|
||||
// CAGuard
|
||||
//
|
||||
// This is your typical mutex with signalling implemented via pthreads.
|
||||
// Lock() will return true if and only if the guard is locked on that call.
|
||||
// A thread that already has the guard will receive 'false' if it locks it
|
||||
// again. Use of the stack-based CAGuard::Locker class is highly recommended
|
||||
// to properly manage the recursive nesting. The Wait calls with timeouts
|
||||
// will return true if and only if the timeout period expired. They will
|
||||
// return false if they receive notification any other way.
|
||||
//==================================================================================================
|
||||
|
||||
class CAGuard : public CAMutex
|
||||
{
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAGuard(const char* inName);
|
||||
virtual ~CAGuard();
|
||||
|
||||
// Actions
|
||||
public:
|
||||
virtual void Wait();
|
||||
virtual bool WaitFor(UInt64 inNanos);
|
||||
virtual bool WaitUntil(UInt64 inNanos);
|
||||
|
||||
virtual void Notify();
|
||||
virtual void NotifyAll();
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
#if TARGET_OS_MAC
|
||||
pthread_cond_t mCondVar;
|
||||
#else
|
||||
HANDLE mEvent;
|
||||
#endif
|
||||
#if Log_Average_Latency
|
||||
Float64 mAverageLatencyAccumulator;
|
||||
UInt32 mAverageLatencyCount;
|
||||
#endif
|
||||
|
||||
// Helper class to manage taking and releasing recursively
|
||||
public:
|
||||
class Locker
|
||||
{
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
Locker(CAGuard& inGuard) : mGuard(inGuard), mNeedsRelease(false) { mNeedsRelease = mGuard.Lock(); }
|
||||
~Locker() { if(mNeedsRelease) { mGuard.Unlock(); } }
|
||||
|
||||
private:
|
||||
Locker(const Locker&);
|
||||
Locker& operator=(const Locker&);
|
||||
|
||||
// Actions
|
||||
public:
|
||||
void Wait() { mGuard.Wait(); }
|
||||
bool WaitFor(UInt64 inNanos) { return mGuard.WaitFor(inNanos); }
|
||||
bool WaitUntil(UInt64 inNanos) { return mGuard.WaitUntil(inNanos); }
|
||||
|
||||
void Notify() { mGuard.Notify(); }
|
||||
void NotifyAll() { mGuard.NotifyAll(); }
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
CAGuard& mGuard;
|
||||
bool mNeedsRelease;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#include "CAHostTimeBase.h"
|
||||
|
||||
Float64 CAHostTimeBase::sFrequency = 0;
|
||||
Float64 CAHostTimeBase::sInverseFrequency = 0;
|
||||
UInt32 CAHostTimeBase::sMinDelta = 0;
|
||||
UInt32 CAHostTimeBase::sToNanosNumerator = 0;
|
||||
UInt32 CAHostTimeBase::sToNanosDenominator = 0;
|
||||
pthread_once_t CAHostTimeBase::sIsInited = PTHREAD_ONCE_INIT;
|
||||
#if Track_Host_TimeBase
|
||||
UInt64 CAHostTimeBase::sLastTime = 0;
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// CAHostTimeBase
|
||||
//
|
||||
// This class provides platform independent access to the host's time base.
|
||||
//=============================================================================
|
||||
|
||||
void CAHostTimeBase::Initialize()
|
||||
{
|
||||
// get the info about Absolute time
|
||||
#if TARGET_OS_MAC
|
||||
struct mach_timebase_info theTimeBaseInfo;
|
||||
mach_timebase_info(&theTimeBaseInfo);
|
||||
sMinDelta = 1;
|
||||
sToNanosNumerator = theTimeBaseInfo.numer;
|
||||
sToNanosDenominator = theTimeBaseInfo.denom;
|
||||
|
||||
// the frequency of that clock is: (sToNanosDenominator / sToNanosNumerator) * 10^9
|
||||
sFrequency = static_cast<Float64>(sToNanosDenominator) / static_cast<Float64>(sToNanosNumerator);
|
||||
sFrequency *= 1000000000.0;
|
||||
#elif TARGET_OS_WIN32
|
||||
LARGE_INTEGER theFrequency;
|
||||
QueryPerformanceFrequency(&theFrequency);
|
||||
sMinDelta = 1;
|
||||
sToNanosNumerator = 1000000000ULL;
|
||||
sToNanosDenominator = *((UInt64*)&theFrequency);
|
||||
sFrequency = static_cast<Float64>(*((UInt64*)&theFrequency));
|
||||
#endif
|
||||
sInverseFrequency = 1.0 / sFrequency;
|
||||
|
||||
#if Log_Host_Time_Base_Parameters
|
||||
DebugPrintf("Host Time Base Parameters");
|
||||
DebugPrintf(" Minimum Delta: %lu", (unsigned long)sMinDelta);
|
||||
DebugPrintf(" Frequency: %f", sFrequency);
|
||||
DebugPrintf(" To Nanos Numerator: %lu", (unsigned long)sToNanosNumerator);
|
||||
DebugPrintf(" To Nanos Denominator: %lu", (unsigned long)sToNanosDenominator);
|
||||
#endif
|
||||
}
|
@ -1,196 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#if !defined(__CAHostTimeBase_h__)
|
||||
#define __CAHostTimeBase_h__
|
||||
|
||||
//=============================================================================
|
||||
// Includes
|
||||
//=============================================================================
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#include <mach/mach_time.h>
|
||||
#include <pthread.h>
|
||||
#elif TARGET_OS_WIN32
|
||||
#include <windows.h>
|
||||
#include "WinPThreadDefs.h"
|
||||
#else
|
||||
#error Unsupported operating system
|
||||
#endif
|
||||
|
||||
#include "CADebugPrintf.h"
|
||||
|
||||
//=============================================================================
|
||||
// CAHostTimeBase
|
||||
//
|
||||
// This class provides platform independent access to the host's time base.
|
||||
//=============================================================================
|
||||
|
||||
#if CoreAudio_Debug
|
||||
// #define Log_Host_Time_Base_Parameters 1
|
||||
// #define Track_Host_TimeBase 1
|
||||
#endif
|
||||
|
||||
class CAHostTimeBase
|
||||
{
|
||||
|
||||
public:
|
||||
static UInt64 ConvertToNanos(UInt64 inHostTime);
|
||||
static UInt64 ConvertFromNanos(UInt64 inNanos);
|
||||
|
||||
static UInt64 GetTheCurrentTime();
|
||||
#if TARGET_OS_MAC
|
||||
static UInt64 GetCurrentTime() { return GetTheCurrentTime(); }
|
||||
#endif
|
||||
static UInt64 GetCurrentTimeInNanos();
|
||||
|
||||
static Float64 GetFrequency() { pthread_once(&sIsInited, Initialize); return sFrequency; }
|
||||
static Float64 GetInverseFrequency() { pthread_once(&sIsInited, Initialize); return sInverseFrequency; }
|
||||
static UInt32 GetMinimumDelta() { pthread_once(&sIsInited, Initialize); return sMinDelta; }
|
||||
|
||||
static UInt64 AbsoluteHostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime);
|
||||
static SInt64 HostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime);
|
||||
|
||||
static UInt64 MultiplyByRatio(UInt64 inMuliplicand, UInt32 inNumerator, UInt32 inDenominator);
|
||||
|
||||
private:
|
||||
static void Initialize();
|
||||
|
||||
static pthread_once_t sIsInited;
|
||||
|
||||
static Float64 sFrequency;
|
||||
static Float64 sInverseFrequency;
|
||||
static UInt32 sMinDelta;
|
||||
static UInt32 sToNanosNumerator;
|
||||
static UInt32 sToNanosDenominator;
|
||||
#if Track_Host_TimeBase
|
||||
static UInt64 sLastTime;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline UInt64 CAHostTimeBase::GetTheCurrentTime()
|
||||
{
|
||||
UInt64 theTime = 0;
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
theTime = mach_absolute_time();
|
||||
#elif TARGET_OS_WIN32
|
||||
LARGE_INTEGER theValue;
|
||||
QueryPerformanceCounter(&theValue);
|
||||
theTime = *((UInt64*)&theValue);
|
||||
#endif
|
||||
|
||||
#if Track_Host_TimeBase
|
||||
if(sLastTime != 0)
|
||||
{
|
||||
if(theTime <= sLastTime)
|
||||
{
|
||||
DebugPrintf("CAHostTimeBase::GetTheCurrentTime: the current time is earlier than the last time, now: %qd, then: %qd", theTime, sLastTime);
|
||||
}
|
||||
sLastTime = theTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
sLastTime = theTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
return theTime;
|
||||
}
|
||||
|
||||
inline UInt64 CAHostTimeBase::ConvertToNanos(UInt64 inHostTime)
|
||||
{
|
||||
pthread_once(&sIsInited, Initialize);
|
||||
|
||||
UInt64 theAnswer = MultiplyByRatio(inHostTime, sToNanosNumerator, sToNanosDenominator);
|
||||
#if CoreAudio_Debug
|
||||
if(((sToNanosNumerator > sToNanosDenominator) && (theAnswer < inHostTime)) || ((sToNanosDenominator > sToNanosNumerator) && (theAnswer > inHostTime)))
|
||||
{
|
||||
DebugPrintf("CAHostTimeBase::ConvertToNanos: The conversion wrapped");
|
||||
}
|
||||
#endif
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
inline UInt64 CAHostTimeBase::ConvertFromNanos(UInt64 inNanos)
|
||||
{
|
||||
pthread_once(&sIsInited, Initialize);
|
||||
|
||||
UInt64 theAnswer = MultiplyByRatio(inNanos, sToNanosDenominator, sToNanosNumerator);
|
||||
#if CoreAudio_Debug
|
||||
if(((sToNanosDenominator > sToNanosNumerator) && (theAnswer < inNanos)) || ((sToNanosNumerator > sToNanosDenominator) && (theAnswer > inNanos)))
|
||||
{
|
||||
DebugPrintf("CAHostTimeBase::ConvertFromNanos: The conversion wrapped");
|
||||
}
|
||||
#endif
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
inline UInt64 CAHostTimeBase::GetCurrentTimeInNanos()
|
||||
{
|
||||
return ConvertToNanos(GetTheCurrentTime());
|
||||
}
|
||||
|
||||
inline UInt64 CAHostTimeBase::AbsoluteHostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime)
|
||||
{
|
||||
UInt64 theAnswer;
|
||||
|
||||
if(inStartTime <= inEndTime)
|
||||
{
|
||||
theAnswer = inEndTime - inStartTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
theAnswer = inStartTime - inEndTime;
|
||||
}
|
||||
|
||||
return ConvertToNanos(theAnswer);
|
||||
}
|
||||
|
||||
inline SInt64 CAHostTimeBase::HostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime)
|
||||
{
|
||||
SInt64 theAnswer;
|
||||
SInt64 theSign = 1;
|
||||
|
||||
if(inStartTime <= inEndTime)
|
||||
{
|
||||
theAnswer = static_cast<SInt64>(inEndTime - inStartTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
theAnswer = static_cast<SInt64>(inStartTime - inEndTime);
|
||||
theSign = -1;
|
||||
}
|
||||
|
||||
return theSign * static_cast<SInt64>(ConvertToNanos(static_cast<UInt64>(theAnswer)));
|
||||
}
|
||||
|
||||
inline UInt64 CAHostTimeBase::MultiplyByRatio(UInt64 inMuliplicand, UInt32 inNumerator, UInt32 inDenominator)
|
||||
{
|
||||
#if TARGET_OS_MAC && TARGET_RT_64_BIT
|
||||
__uint128_t theAnswer = inMuliplicand;
|
||||
#else
|
||||
long double theAnswer = inMuliplicand;
|
||||
#endif
|
||||
if(inNumerator != inDenominator)
|
||||
{
|
||||
theAnswer *= inNumerator;
|
||||
theAnswer /= inDenominator;
|
||||
}
|
||||
return static_cast<UInt64>(theAnswer);
|
||||
}
|
||||
|
||||
#endif
|
@ -1,102 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#if !defined(__CALogMacros_h__)
|
||||
#define __CALogMacros_h__
|
||||
|
||||
//=============================================================================
|
||||
// Log Macros
|
||||
//=============================================================================
|
||||
|
||||
#if CoreAudio_Debug
|
||||
|
||||
#include "CADebugMacros.h"
|
||||
#include "CADebugPrintf.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define PrintLine(msg) DebugPrintfRtn(DebugPrintfFileComma "%s\n", (msg))
|
||||
|
||||
#define PrintBool(msg, b) DebugPrintfRtn(DebugPrintfFileComma "%s%s\n", (msg), (b) ? "true" : "false")
|
||||
#define PrintIndexedBool(msg, i, b) DebugPrintfRtn(DebugPrintfFileComma " %s %ld: %s\n", (msg), (long)(i), (b) ? "true" : "false")
|
||||
|
||||
#define PrintToggle(msg, b) DebugPrintfRtn(DebugPrintfFileComma "%s%s\n", (msg), (b) ? "on" : "off")
|
||||
#define PrintIndexedToggle(msg, i, b) DebugPrintfRtn(DebugPrintfFileComma " %s %ld: %s\n", (msg), (long)(i), (b) ? "on" : "off")
|
||||
|
||||
#define PrintInt(msg, n) DebugPrintfRtn(DebugPrintfFileComma "%s%ld\n", (msg), (long)(n))
|
||||
#define PrintIndexedInt(msg, i, n) DebugPrintfRtn(DebugPrintfFileComma " %s %ld: %ld\n", (msg), (long)(i), (long)(n))
|
||||
|
||||
#define PrintHex(msg, n) DebugPrintfRtn(DebugPrintfFileComma "%s0x%lX\n", (msg), (unsigned long)(n))
|
||||
#define PrintIndexedHex(msg, i, n) DebugPrintfRtn(DebugPrintfFileComma " %s %ld: 0x%lX\n", (msg), (long)(i), (unsigned long)(n))
|
||||
|
||||
#define PrintFloat(msg, f) DebugPrintfRtn(DebugPrintfFileComma "%s%.6f\n", (msg), (f))
|
||||
#define PrintIndexedFloat(msg, i, f) DebugPrintfRtn(DebugPrintfFileComma " %s %ld: %.6f\n", (msg), (long)(i), (f))
|
||||
#define PrintFloatIndexedFloat(msg, i, f) DebugPrintfRtn(DebugPrintfFileComma " %s %.6f: %.6f\n", (msg), (i), (f))
|
||||
|
||||
#define PrintString(msg, s) DebugPrintfRtn(DebugPrintfFileComma "%s%s\n", (msg), (s))
|
||||
#define PrintIndexedString(msg, i, s) DebugPrintfRtn(DebugPrintfFileComma " %s %ld: %s\n", (msg), (long)(i), (s))
|
||||
|
||||
#define PrintPointer(msg, p) DebugPrintfRtn(DebugPrintfFileComma "%s%p\n", (msg), (p))
|
||||
#define PrintIndexedPointer(msg, i, p) DebugPrintfRtn(DebugPrintfFileComma " %s %ld: %p\n", (msg), (long)(i), (p))
|
||||
|
||||
#define Print4CharCode(msg, c) { \
|
||||
UInt32 __4CC_number = (c); \
|
||||
char __4CC_string[5] = CA4CCToCString(__4CC_number); \
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%s'%s'\n", (msg), __4CC_string); \
|
||||
}
|
||||
#define PrintIndexed4CharCode(msg, i, c) { \
|
||||
UInt32 __4CC_number = (c); \
|
||||
char __4CC_string[5] = CA4CCToCString(__4CC_number); \
|
||||
DebugPrintfRtn(DebugPrintfFileComma " %s %ld: '%s'\n", (msg), (long)(i), __4CC_string); \
|
||||
}
|
||||
|
||||
#define ErrorLine(s) DebugPrintfRtn(DebugPrintfFileComma "%s\n", (s))
|
||||
#define OSErrorLine(s, e) { \
|
||||
OSStatus __err_number = (e); \
|
||||
char __err_string[5] = CA4CCToCString(__err_number); \
|
||||
DebugPrintfRtn(DebugPrintfFileComma "%s, OSStatus code: %s\n", (s), __err_string); \
|
||||
}
|
||||
|
||||
#define MessageIfOSError(e, s) if((e) != 0) { OSErrorLine(s, e); }
|
||||
#define MessageIfNULL(p, s) if((p) == 0) { ErrorLine(s); }
|
||||
|
||||
#else
|
||||
|
||||
#define PrintLine(msg)
|
||||
|
||||
#define PrintBool(msg, b) (b)
|
||||
#define PrintIndexedBool(msg, i, b) (b)
|
||||
|
||||
#define PrintInt(msg, n) (n)
|
||||
#define PrintIndexedInt(msg, i, n) (n)
|
||||
|
||||
#define PrintHex(msg, n) (n)
|
||||
#define PrintIndexedHex(msg, i, n) (n)
|
||||
|
||||
#define PrintFloat(msg, f) (f)
|
||||
#define PrintIndexedFloat(msg, i, f) (f)
|
||||
#define PrintFloatIndexedFloat(msg, i, f) (f)
|
||||
|
||||
#define PrintString(msg, s) (s)
|
||||
#define PrintIndexedString(msg, i, s) (s)
|
||||
|
||||
#define PrintPointer(msg, p) (p)
|
||||
#define PrintIndexedPointer(msg, i, p) (p)
|
||||
|
||||
#define Print4CharCode(msg, c) (c)
|
||||
#define PrintIndexed4CharCode(msg, i, c) (c)
|
||||
|
||||
#define ErrorLine(s) (s)
|
||||
#define OSErrorLine(s, e) (e)
|
||||
|
||||
#define MessageIfOSError(e, s) (e)
|
||||
#define MessageIfNULL(p, s) (p)
|
||||
|
||||
#endif // CoreAudio_Debug
|
||||
|
||||
#endif
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
File: CAMath.h
|
||||
Abstract:
|
||||
Version: 1.2
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2010 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __CAMath_h__
|
||||
#define __CAMath_h__
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#endif
|
||||
|
||||
inline bool fiszero(Float64 f) { return (f == 0.); }
|
||||
inline bool fiszero(Float32 f) { return (f == 0.f); }
|
||||
|
||||
inline bool fnonzero(Float64 f) { return !fiszero(f); }
|
||||
inline bool fnonzero(Float32 f) { return !fiszero(f); }
|
||||
|
||||
inline bool fequal(const Float64 &a, const Float64 &b) { return a == b; }
|
||||
inline bool fequal(const Float32 &a, const Float32 &b) { return a == b; }
|
||||
|
||||
inline bool fnotequal(const Float64 &a, const Float64 &b) { return !fequal(a, b); }
|
||||
inline bool fnotequal(const Float32 &a, const Float32 &b) { return !fequal(a, b); }
|
||||
|
||||
#endif // __CAMath_h__
|
@ -1,307 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
//==================================================================================================
|
||||
// Includes
|
||||
//==================================================================================================
|
||||
|
||||
// Self Include
|
||||
#include "CAMutex.h"
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CADebugMacros.h"
|
||||
#include "CAException.h"
|
||||
#include "CAHostTimeBase.h"
|
||||
|
||||
//==================================================================================================
|
||||
// Logging
|
||||
//==================================================================================================
|
||||
|
||||
#if CoreAudio_Debug
|
||||
// #define Log_Ownership 1
|
||||
// #define Log_Errors 1
|
||||
// #define Log_LongLatencies 1
|
||||
// #define LongLatencyThreshholdNS 1000000ULL // nanoseconds
|
||||
#endif
|
||||
|
||||
//==================================================================================================
|
||||
// CAMutex
|
||||
//==================================================================================================
|
||||
|
||||
CAMutex::CAMutex(const char* inName)
|
||||
:
|
||||
mName(inName),
|
||||
mOwner(0)
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
OSStatus theError = pthread_mutex_init(&mMutex, NULL);
|
||||
ThrowIf(theError != 0, CAException(theError), "CAMutex::CAMutex: Could not init the mutex");
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%p %.4f: CAMutex::CAMutex: creating %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner);
|
||||
#endif
|
||||
#elif TARGET_OS_WIN32
|
||||
mMutex = CreateMutex(NULL, false, NULL);
|
||||
ThrowIfNULL(mMutex, CAException(GetLastError()), "CAMutex::CAMutex: could not create the mutex.");
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%lu %.4f: CAMutex::CAMutex: creating %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
CAMutex::~CAMutex()
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%p %.4f: CAMutex::~CAMutex: destroying %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner);
|
||||
#endif
|
||||
pthread_mutex_destroy(&mMutex);
|
||||
#elif TARGET_OS_WIN32
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%lu %.4f: CAMutex::~CAMutex: destroying %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner);
|
||||
#endif
|
||||
if(mMutex != NULL)
|
||||
{
|
||||
CloseHandle(mMutex);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CAMutex::Lock()
|
||||
{
|
||||
bool theAnswer = false;
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
pthread_t theCurrentThread = pthread_self();
|
||||
if(!pthread_equal(theCurrentThread, mOwner))
|
||||
{
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%p %.4f: CAMutex::Lock: thread %p is locking %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner);
|
||||
#endif
|
||||
|
||||
#if Log_LongLatencies
|
||||
UInt64 lockTryTime = CAHostTimeBase::GetCurrentTimeInNanos();
|
||||
#endif
|
||||
|
||||
OSStatus theError = pthread_mutex_lock(&mMutex);
|
||||
ThrowIf(theError != 0, CAException(theError), "CAMutex::Lock: Could not lock the mutex");
|
||||
mOwner = theCurrentThread;
|
||||
theAnswer = true;
|
||||
|
||||
#if Log_LongLatencies
|
||||
UInt64 lockAcquireTime = CAHostTimeBase::GetCurrentTimeInNanos();
|
||||
if (lockAcquireTime - lockTryTime >= LongLatencyThresholdNS)
|
||||
DebugPrintf("Thread %p took %.6fs to acquire the lock %s\n", theCurrentThread, (lockAcquireTime - lockTryTime) * 1.0e-9 /* nanos to seconds */, mName);
|
||||
#endif
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%p %.4f: CAMutex::Lock: thread %p has locked %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
|
||||
#endif
|
||||
}
|
||||
#elif TARGET_OS_WIN32
|
||||
if(mOwner != GetCurrentThreadId())
|
||||
{
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%lu %.4f: CAMutex::Lock: thread %lu is locking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
OSStatus theError = WaitForSingleObject(mMutex, INFINITE);
|
||||
ThrowIfError(theError, CAException(theError), "CAMutex::Lock: could not lock the mutex");
|
||||
mOwner = GetCurrentThreadId();
|
||||
theAnswer = true;
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%lu %.4f: CAMutex::Lock: thread %lu has locked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
void CAMutex::Unlock()
|
||||
{
|
||||
#if TARGET_OS_MAC
|
||||
if(pthread_equal(pthread_self(), mOwner))
|
||||
{
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%p %.4f: CAMutex::Unlock: thread %p is unlocking %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
mOwner = 0;
|
||||
OSStatus theError = pthread_mutex_unlock(&mMutex);
|
||||
ThrowIf(theError != 0, CAException(theError), "CAMutex::Unlock: Could not unlock the mutex");
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%p %.4f: CAMutex::Unlock: thread %p has unlocked %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugMessage("CAMutex::Unlock: A thread is attempting to unlock a Mutex it doesn't own");
|
||||
}
|
||||
#elif TARGET_OS_WIN32
|
||||
if(mOwner == GetCurrentThreadId())
|
||||
{
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%lu %.4f: CAMutex::Unlock: thread %lu is unlocking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
mOwner = 0;
|
||||
bool wasReleased = ReleaseMutex(mMutex);
|
||||
ThrowIf(!wasReleased, CAException(GetLastError()), "CAMutex::Unlock: Could not unlock the mutex");
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%lu %.4f: CAMutex::Unlock: thread %lu has unlocked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugMessage("CAMutex::Unlock: A thread is attempting to unlock a Mutex it doesn't own");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CAMutex::Try(bool& outWasLocked)
|
||||
{
|
||||
bool theAnswer = false;
|
||||
outWasLocked = false;
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
pthread_t theCurrentThread = pthread_self();
|
||||
if(!pthread_equal(theCurrentThread, mOwner))
|
||||
{
|
||||
// this means the current thread doesn't already own the lock
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%p %.4f: CAMutex::Try: thread %p is try-locking %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner);
|
||||
#endif
|
||||
|
||||
// go ahead and call trylock to see if we can lock it.
|
||||
int theError = pthread_mutex_trylock(&mMutex);
|
||||
if(theError == 0)
|
||||
{
|
||||
// return value of 0 means we successfully locked the lock
|
||||
mOwner = theCurrentThread;
|
||||
theAnswer = true;
|
||||
outWasLocked = true;
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%p %.4f: CAMutex::Try: thread %p has locked %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner);
|
||||
#endif
|
||||
}
|
||||
else if(theError == EBUSY)
|
||||
{
|
||||
// return value of EBUSY means that the lock was already locked by another thread
|
||||
theAnswer = false;
|
||||
outWasLocked = false;
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%p %.4f: CAMutex::Try: thread %p failed to lock %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// any other return value means something really bad happenned
|
||||
ThrowIfError(theError, CAException(theError), "CAMutex::Try: call to pthread_mutex_trylock failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// this means the current thread already owns the lock
|
||||
theAnswer = true;
|
||||
outWasLocked = false;
|
||||
}
|
||||
#elif TARGET_OS_WIN32
|
||||
if(mOwner != GetCurrentThreadId())
|
||||
{
|
||||
// this means the current thread doesn't own the lock
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%lu %.4f: CAMutex::Try: thread %lu is try-locking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
|
||||
// try to acquire the mutex
|
||||
OSStatus theError = WaitForSingleObject(mMutex, 0);
|
||||
if(theError == WAIT_OBJECT_0)
|
||||
{
|
||||
// this means we successfully locked the lock
|
||||
mOwner = GetCurrentThreadId();
|
||||
theAnswer = true;
|
||||
outWasLocked = true;
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%lu %.4f: CAMutex::Try: thread %lu has locked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
}
|
||||
else if(theError == WAIT_TIMEOUT)
|
||||
{
|
||||
// this means that the lock was already locked by another thread
|
||||
theAnswer = false;
|
||||
outWasLocked = false;
|
||||
|
||||
#if Log_Ownership
|
||||
DebugPrintf("%lu %.4f: CAMutex::Try: thread %lu failed to lock %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// any other return value means something really bad happenned
|
||||
ThrowIfError(theError, CAException(GetLastError()), "CAMutex::Try: call to lock the mutex failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// this means the current thread already owns the lock
|
||||
theAnswer = true;
|
||||
outWasLocked = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
bool CAMutex::IsFree() const
|
||||
{
|
||||
return mOwner == 0;
|
||||
}
|
||||
|
||||
bool CAMutex::IsOwnedByCurrentThread() const
|
||||
{
|
||||
bool theAnswer = true;
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
theAnswer = pthread_equal(pthread_self(), mOwner);
|
||||
#elif TARGET_OS_WIN32
|
||||
theAnswer = (mOwner == GetCurrentThreadId());
|
||||
#endif
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
|
||||
CAMutex::Unlocker::Unlocker(CAMutex& inMutex)
|
||||
: mMutex(inMutex),
|
||||
mNeedsLock(false)
|
||||
{
|
||||
Assert(mMutex.IsOwnedByCurrentThread(), "Major problem: Unlocker attempted to unlock a mutex not owned by the current thread!");
|
||||
|
||||
mMutex.Unlock();
|
||||
mNeedsLock = true;
|
||||
}
|
||||
|
||||
CAMutex::Unlocker::~Unlocker()
|
||||
{
|
||||
if(mNeedsLock)
|
||||
{
|
||||
mMutex.Lock();
|
||||
}
|
||||
}
|
125
extra/CAMutex.h
125
extra/CAMutex.h
@ -1,125 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#ifndef __CAMutex_h__
|
||||
#define __CAMutex_h__
|
||||
|
||||
//==================================================================================================
|
||||
// Includes
|
||||
//==================================================================================================
|
||||
|
||||
// System Includes
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#else
|
||||
#include <CoreAudioTypes.h>
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#include <pthread.h>
|
||||
#elif TARGET_OS_WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#error Unsupported operating system
|
||||
#endif
|
||||
|
||||
//==================================================================================================
|
||||
// A recursive mutex.
|
||||
//==================================================================================================
|
||||
|
||||
class CAMutex
|
||||
{
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAMutex(const char* inName);
|
||||
virtual ~CAMutex();
|
||||
|
||||
// Actions
|
||||
public:
|
||||
virtual bool Lock();
|
||||
virtual void Unlock();
|
||||
virtual bool Try(bool& outWasLocked); // returns true if lock is free, false if not
|
||||
|
||||
virtual bool IsFree() const;
|
||||
virtual bool IsOwnedByCurrentThread() const;
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
const char* mName;
|
||||
#if TARGET_OS_MAC
|
||||
pthread_t mOwner;
|
||||
pthread_mutex_t mMutex;
|
||||
#elif TARGET_OS_WIN32
|
||||
UInt32 mOwner;
|
||||
HANDLE mMutex;
|
||||
#endif
|
||||
|
||||
// Helper class to manage taking and releasing recursively
|
||||
public:
|
||||
class Locker
|
||||
{
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
Locker(CAMutex& inMutex) : mMutex(&inMutex), mNeedsRelease(false) { mNeedsRelease = mMutex->Lock(); }
|
||||
Locker(CAMutex* inMutex) : mMutex(inMutex), mNeedsRelease(false) { mNeedsRelease = (mMutex != NULL && mMutex->Lock()); }
|
||||
// in this case the mutex can be null
|
||||
~Locker() { if(mNeedsRelease) { mMutex->Unlock(); } }
|
||||
|
||||
|
||||
private:
|
||||
Locker(const Locker&);
|
||||
Locker& operator=(const Locker&);
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
CAMutex* mMutex;
|
||||
bool mNeedsRelease;
|
||||
|
||||
};
|
||||
|
||||
// Unlocker
|
||||
class Unlocker
|
||||
{
|
||||
public:
|
||||
Unlocker(CAMutex& inMutex);
|
||||
~Unlocker();
|
||||
|
||||
private:
|
||||
CAMutex& mMutex;
|
||||
bool mNeedsLock;
|
||||
|
||||
// Hidden definitions of copy ctor, assignment operator
|
||||
Unlocker(const Unlocker& copy); // Not implemented
|
||||
Unlocker& operator=(const Unlocker& copy); // Not implemented
|
||||
};
|
||||
|
||||
// you can use this with Try - if you take the lock in try, pass in the outWasLocked var
|
||||
class Tryer {
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
Tryer (CAMutex &mutex) : mMutex(mutex), mNeedsRelease(false), mHasLock(false) { mHasLock = mMutex.Try (mNeedsRelease); }
|
||||
~Tryer () { if (mNeedsRelease) mMutex.Unlock(); }
|
||||
|
||||
bool HasLock () const { return mHasLock; }
|
||||
|
||||
private:
|
||||
Tryer(const Tryer&);
|
||||
Tryer& operator=(const Tryer&);
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
CAMutex & mMutex;
|
||||
bool mNeedsRelease;
|
||||
bool mHasLock;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#endif // __CAMutex_h__
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#ifndef __CAReferenceCounted_h__
|
||||
#define __CAReferenceCounted_h__
|
||||
|
||||
#include "CAAtomic.h"
|
||||
|
||||
// base class for reference-counted objects
|
||||
class CAReferenceCounted {
|
||||
public:
|
||||
CAReferenceCounted() : mRefCount(1) {}
|
||||
|
||||
void retain() { CAAtomicIncrement32(&mRefCount); }
|
||||
|
||||
void release()
|
||||
{
|
||||
SInt32 rc = CAAtomicDecrement32(&mRefCount);
|
||||
if (rc == 0) {
|
||||
releaseObject();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Retainer {
|
||||
public:
|
||||
Retainer(CAReferenceCounted *obj) : mObject(obj) { mObject->retain(); }
|
||||
~Retainer() { mObject->release(); }
|
||||
|
||||
private:
|
||||
CAReferenceCounted * mObject;
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual ~CAReferenceCounted() { }
|
||||
|
||||
virtual void releaseObject ()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
public:
|
||||
#endif
|
||||
SInt32 GetReferenceCount() const { return mRefCount; }
|
||||
private:
|
||||
SInt32 mRefCount;
|
||||
|
||||
CAReferenceCounted(const CAReferenceCounted &a);
|
||||
CAReferenceCounted &operator=(const CAReferenceCounted &a);
|
||||
};
|
||||
|
||||
|
||||
#endif // __CAReferenceCounted_h__
|
@ -1,887 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#include "CAStreamBasicDescription.h"
|
||||
#include "CAMath.h"
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreFoundation/CFByteOrder.h>
|
||||
#else
|
||||
#include <CFByteOrder.h>
|
||||
#endif
|
||||
|
||||
#pragma mark This file needs to compile on earlier versions of the OS, so please keep that in mind when editing it
|
||||
|
||||
char *CAStringForOSType (OSType t, char *writeLocation, size_t bufsize)
|
||||
{
|
||||
if (bufsize > 0) {
|
||||
char *p = writeLocation, *pend = writeLocation + bufsize;
|
||||
union { UInt32 i; unsigned char str[4]; } u;
|
||||
unsigned char *q = u.str;
|
||||
u.i = CFSwapInt32HostToBig(t);
|
||||
|
||||
bool hasNonPrint = false;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (!(isprint(*q) && *q != '\\')) {
|
||||
hasNonPrint = true;
|
||||
break;
|
||||
}
|
||||
q++;
|
||||
}
|
||||
q = u.str;
|
||||
|
||||
if (hasNonPrint)
|
||||
p += snprintf (p, pend - p, "0x");
|
||||
else if (p < pend)
|
||||
*p++ = '\'';
|
||||
|
||||
for (int i = 0; i < 4 && p < pend; ++i) {
|
||||
if (hasNonPrint) {
|
||||
p += snprintf(p, pend - p, "%02X", *q++);
|
||||
} else {
|
||||
*p++ = *q++;
|
||||
}
|
||||
}
|
||||
if (!hasNonPrint && p < pend)
|
||||
*p++ = '\'';
|
||||
if (p >= pend) p -= 1;
|
||||
*p = '\0';
|
||||
}
|
||||
return writeLocation;
|
||||
}
|
||||
|
||||
|
||||
const AudioStreamBasicDescription CAStreamBasicDescription::sEmpty = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
CAStreamBasicDescription::CAStreamBasicDescription()
|
||||
{
|
||||
memset (this, 0, sizeof(AudioStreamBasicDescription));
|
||||
}
|
||||
|
||||
CAStreamBasicDescription::CAStreamBasicDescription(const AudioStreamBasicDescription &desc)
|
||||
{
|
||||
SetFrom(desc);
|
||||
}
|
||||
|
||||
|
||||
CAStreamBasicDescription::CAStreamBasicDescription(double inSampleRate, UInt32 inFormatID,
|
||||
UInt32 inBytesPerPacket, UInt32 inFramesPerPacket,
|
||||
UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame,
|
||||
UInt32 inBitsPerChannel, UInt32 inFormatFlags)
|
||||
{
|
||||
mSampleRate = inSampleRate;
|
||||
mFormatID = inFormatID;
|
||||
mBytesPerPacket = inBytesPerPacket;
|
||||
mFramesPerPacket = inFramesPerPacket;
|
||||
mBytesPerFrame = inBytesPerFrame;
|
||||
mChannelsPerFrame = inChannelsPerFrame;
|
||||
mBitsPerChannel = inBitsPerChannel;
|
||||
mFormatFlags = inFormatFlags;
|
||||
mReserved = 0;
|
||||
}
|
||||
|
||||
char *CAStreamBasicDescription::AsString(char *buf, size_t _bufsize, bool brief /*=false*/) const
|
||||
{
|
||||
int bufsize = (int)_bufsize; // must be signed to protect against overflow
|
||||
char *theBuffer = buf;
|
||||
int nc;
|
||||
char formatID[24];
|
||||
CAStringForOSType(mFormatID, formatID, sizeof(formatID));
|
||||
if (brief) {
|
||||
CommonPCMFormat com;
|
||||
bool interleaved;
|
||||
if (IdentifyCommonPCMFormat(com, &interleaved) && com != kPCMFormatOther) {
|
||||
const char *desc;
|
||||
switch (com) {
|
||||
case kPCMFormatInt16:
|
||||
desc = "Int16";
|
||||
break;
|
||||
case kPCMFormatInt32:
|
||||
desc = "Int32";
|
||||
break;
|
||||
case kPCMFormatFixed824:
|
||||
desc = "Int8.24";
|
||||
break;
|
||||
case kPCMFormatFloat32:
|
||||
desc = "Float32";
|
||||
break;
|
||||
case kPCMFormatFloat64:
|
||||
desc = "Float64";
|
||||
break;
|
||||
default:
|
||||
desc = NULL;
|
||||
break;
|
||||
}
|
||||
if (desc) {
|
||||
const char *inter ="";
|
||||
if (mChannelsPerFrame > 1)
|
||||
inter = !interleaved ? ", non-inter" : ", inter";
|
||||
snprintf(buf, static_cast<size_t>(bufsize), "%2d ch, %6.0f Hz, %s%s", (int)mChannelsPerFrame, mSampleRate, desc, inter);
|
||||
return theBuffer;
|
||||
}
|
||||
}
|
||||
if (mChannelsPerFrame == 0 && mSampleRate == 0.0 && mFormatID == 0) {
|
||||
snprintf(buf, static_cast<size_t>(bufsize), "%2d ch, %6.0f Hz", (int)mChannelsPerFrame, mSampleRate);
|
||||
return theBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
nc = snprintf(buf, static_cast<size_t>(bufsize), "%2d ch, %6.0f Hz, %s (0x%08X) ", (int)NumberChannels(), mSampleRate, formatID, (int)mFormatFlags);
|
||||
buf += nc; if ((bufsize -= nc) <= 0) goto exit;
|
||||
if (mFormatID == kAudioFormatLinearPCM) {
|
||||
bool isInt = !(mFormatFlags & kLinearPCMFormatFlagIsFloat);
|
||||
int wordSize = static_cast<int>(SampleWordSize());
|
||||
const char *endian = (wordSize > 1) ?
|
||||
((mFormatFlags & kLinearPCMFormatFlagIsBigEndian) ? " big-endian" : " little-endian" ) : "";
|
||||
const char *sign = isInt ?
|
||||
((mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) ? " signed" : " unsigned") : "";
|
||||
const char *floatInt = isInt ? "integer" : "float";
|
||||
char packed[32];
|
||||
if (wordSize > 0 && PackednessIsSignificant()) {
|
||||
if (mFormatFlags & kLinearPCMFormatFlagIsPacked)
|
||||
snprintf(packed, sizeof(packed), "packed in %d bytes", wordSize);
|
||||
else
|
||||
snprintf(packed, sizeof(packed), "unpacked in %d bytes", wordSize);
|
||||
} else
|
||||
packed[0] = '\0';
|
||||
const char *align = (wordSize > 0 && AlignmentIsSignificant()) ?
|
||||
((mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) ? " high-aligned" : " low-aligned") : "";
|
||||
const char *deinter = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) ? ", deinterleaved" : "";
|
||||
const char *commaSpace = (packed[0]!='\0') || (align[0]!='\0') ? ", " : "";
|
||||
char bitdepth[20];
|
||||
|
||||
int fracbits = (mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift;
|
||||
if (fracbits > 0)
|
||||
snprintf(bitdepth, sizeof(bitdepth), "%d.%d", (int)mBitsPerChannel - fracbits, fracbits);
|
||||
else
|
||||
snprintf(bitdepth, sizeof(bitdepth), "%d", (int)mBitsPerChannel);
|
||||
|
||||
/*nc =*/ snprintf(buf, static_cast<size_t>(bufsize), "%s-bit%s%s %s%s%s%s%s",
|
||||
bitdepth, endian, sign, floatInt,
|
||||
commaSpace, packed, align, deinter);
|
||||
// buf += nc; if ((bufsize -= nc) <= 0) goto exit;
|
||||
} else if (mFormatID == kAudioFormatAppleLossless) {
|
||||
int sourceBits = 0;
|
||||
switch (mFormatFlags)
|
||||
{
|
||||
case 1: // kAppleLosslessFormatFlag_16BitSourceData
|
||||
sourceBits = 16;
|
||||
break;
|
||||
case 2: // kAppleLosslessFormatFlag_20BitSourceData
|
||||
sourceBits = 20;
|
||||
break;
|
||||
case 3: // kAppleLosslessFormatFlag_24BitSourceData
|
||||
sourceBits = 24;
|
||||
break;
|
||||
case 4: // kAppleLosslessFormatFlag_32BitSourceData
|
||||
sourceBits = 32;
|
||||
break;
|
||||
}
|
||||
if (sourceBits)
|
||||
nc = snprintf(buf, static_cast<size_t>(bufsize), "from %d-bit source, ", sourceBits);
|
||||
else
|
||||
nc = snprintf(buf, static_cast<size_t>(bufsize), "from UNKNOWN source bit depth, ");
|
||||
buf += nc; if ((bufsize -= nc) <= 0) goto exit;
|
||||
/*nc =*/ snprintf(buf, static_cast<size_t>(bufsize), "%d frames/packet", (int)mFramesPerPacket);
|
||||
// buf += nc; if ((bufsize -= nc) <= 0) goto exit;
|
||||
}
|
||||
else
|
||||
/*nc =*/ snprintf(buf, static_cast<size_t>(bufsize), "%d bits/channel, %d bytes/packet, %d frames/packet, %d bytes/frame",
|
||||
(int)mBitsPerChannel, (int)mBytesPerPacket, (int)mFramesPerPacket, (int)mBytesPerFrame);
|
||||
exit:
|
||||
return theBuffer;
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription)
|
||||
{
|
||||
// the only thing that changes is to make mixable linear PCM into the canonical linear PCM format
|
||||
if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0))
|
||||
{
|
||||
// the canonical linear PCM format
|
||||
ioDescription.mFormatFlags = kAudioFormatFlagsCanonical;
|
||||
ioDescription.mBytesPerPacket = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame;
|
||||
ioDescription.mFramesPerPacket = 1;
|
||||
ioDescription.mBytesPerFrame = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame;
|
||||
ioDescription.mBitsPerChannel = 8 * SizeOf32(AudioSampleType);
|
||||
}
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::NormalizeLinearPCMFormat(bool inNativeEndian, AudioStreamBasicDescription& ioDescription)
|
||||
{
|
||||
// the only thing that changes is to make mixable linear PCM into the canonical linear PCM format
|
||||
if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0))
|
||||
{
|
||||
// the canonical linear PCM format
|
||||
ioDescription.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
|
||||
if(inNativeEndian)
|
||||
{
|
||||
#if TARGET_RT_BIG_ENDIAN
|
||||
ioDescription.mFormatFlags |= kAudioFormatFlagIsBigEndian;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if TARGET_RT_LITTLE_ENDIAN
|
||||
ioDescription.mFormatFlags |= kAudioFormatFlagIsBigEndian;
|
||||
#endif
|
||||
}
|
||||
ioDescription.mBytesPerPacket = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame;
|
||||
ioDescription.mFramesPerPacket = 1;
|
||||
ioDescription.mBytesPerFrame = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame;
|
||||
ioDescription.mBitsPerChannel = 8 * SizeOf32(AudioSampleType);
|
||||
}
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::VirtualizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription)
|
||||
{
|
||||
// the only thing that changes is to make mixable linear PCM into the HAL's virtual linear PCM format, which is Float32 currently
|
||||
if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0))
|
||||
{
|
||||
// the virtual linear PCM format
|
||||
ioDescription.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
|
||||
ioDescription.mBytesPerPacket = SizeOf32(Float32) * ioDescription.mChannelsPerFrame;
|
||||
ioDescription.mFramesPerPacket = 1;
|
||||
ioDescription.mBytesPerFrame = SizeOf32(Float32) * ioDescription.mChannelsPerFrame;
|
||||
ioDescription.mBitsPerChannel = 8 * SizeOf32(Float32);
|
||||
}
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::VirtualizeLinearPCMFormat(bool inNativeEndian, AudioStreamBasicDescription& ioDescription)
|
||||
{
|
||||
// the only thing that changes is to make mixable linear PCM into the HAL's virtual linear PCM format, which is Float32 currently
|
||||
if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0))
|
||||
{
|
||||
// the virtual linear PCM format
|
||||
ioDescription.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
|
||||
if(inNativeEndian)
|
||||
{
|
||||
#if TARGET_RT_BIG_ENDIAN
|
||||
ioDescription.mFormatFlags |= kAudioFormatFlagIsBigEndian;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if TARGET_RT_LITTLE_ENDIAN
|
||||
ioDescription.mFormatFlags |= kAudioFormatFlagIsBigEndian;
|
||||
#endif
|
||||
}
|
||||
ioDescription.mBytesPerPacket = SizeOf32(Float32) * ioDescription.mChannelsPerFrame;
|
||||
ioDescription.mFramesPerPacket = 1;
|
||||
ioDescription.mBytesPerFrame = SizeOf32(Float32) * ioDescription.mChannelsPerFrame;
|
||||
ioDescription.mBitsPerChannel = 8 * SizeOf32(Float32);
|
||||
}
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::ResetFormat(AudioStreamBasicDescription& ioDescription)
|
||||
{
|
||||
ioDescription.mSampleRate = 0;
|
||||
ioDescription.mFormatID = 0;
|
||||
ioDescription.mBytesPerPacket = 0;
|
||||
ioDescription.mFramesPerPacket = 0;
|
||||
ioDescription.mBytesPerFrame = 0;
|
||||
ioDescription.mChannelsPerFrame = 0;
|
||||
ioDescription.mBitsPerChannel = 0;
|
||||
ioDescription.mFormatFlags = 0;
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription)
|
||||
{
|
||||
if(fiszero(ioDescription.mSampleRate))
|
||||
{
|
||||
ioDescription.mSampleRate = inTemplateDescription.mSampleRate;
|
||||
}
|
||||
if(ioDescription.mFormatID == 0)
|
||||
{
|
||||
ioDescription.mFormatID = inTemplateDescription.mFormatID;
|
||||
}
|
||||
if(ioDescription.mFormatFlags == 0)
|
||||
{
|
||||
ioDescription.mFormatFlags = inTemplateDescription.mFormatFlags;
|
||||
}
|
||||
if(ioDescription.mBytesPerPacket == 0)
|
||||
{
|
||||
ioDescription.mBytesPerPacket = inTemplateDescription.mBytesPerPacket;
|
||||
}
|
||||
if(ioDescription.mFramesPerPacket == 0)
|
||||
{
|
||||
ioDescription.mFramesPerPacket = inTemplateDescription.mFramesPerPacket;
|
||||
}
|
||||
if(ioDescription.mBytesPerFrame == 0)
|
||||
{
|
||||
ioDescription.mBytesPerFrame = inTemplateDescription.mBytesPerFrame;
|
||||
}
|
||||
if(ioDescription.mChannelsPerFrame == 0)
|
||||
{
|
||||
ioDescription.mChannelsPerFrame = inTemplateDescription.mChannelsPerFrame;
|
||||
}
|
||||
if(ioDescription.mBitsPerChannel == 0)
|
||||
{
|
||||
ioDescription.mBitsPerChannel = inTemplateDescription.mBitsPerChannel;
|
||||
}
|
||||
}
|
||||
|
||||
void CAStreamBasicDescription::GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, UInt32 inMaxNameLength, bool inAbbreviate, bool inIncludeSampleRate)
|
||||
{
|
||||
if(inIncludeSampleRate)
|
||||
{
|
||||
int theCharactersWritten = snprintf(outName, inMaxNameLength, "%.0f ", inDescription.mSampleRate);
|
||||
outName += theCharactersWritten;
|
||||
inMaxNameLength -= static_cast<UInt32>(theCharactersWritten);
|
||||
}
|
||||
|
||||
switch(inDescription.mFormatID)
|
||||
{
|
||||
case kAudioFormatLinearPCM:
|
||||
{
|
||||
const char* theEndianString = NULL;
|
||||
if((inDescription.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0)
|
||||
{
|
||||
#if TARGET_RT_LITTLE_ENDIAN
|
||||
theEndianString = "Big Endian";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if TARGET_RT_BIG_ENDIAN
|
||||
theEndianString = "Little Endian";
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* theKindString = NULL;
|
||||
if((inDescription.mFormatFlags & kAudioFormatFlagIsFloat) != 0)
|
||||
{
|
||||
theKindString = (inAbbreviate ? "Float" : "Floating Point");
|
||||
}
|
||||
else if((inDescription.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
|
||||
{
|
||||
theKindString = (inAbbreviate ? "SInt" : "Signed Integer");
|
||||
}
|
||||
else
|
||||
{
|
||||
theKindString = (inAbbreviate ? "UInt" : "Unsigned Integer");
|
||||
}
|
||||
|
||||
const char* thePackingString = NULL;
|
||||
if((inDescription.mFormatFlags & kAudioFormatFlagIsPacked) == 0)
|
||||
{
|
||||
if((inDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0)
|
||||
{
|
||||
thePackingString = "High";
|
||||
}
|
||||
else
|
||||
{
|
||||
thePackingString = "Low";
|
||||
}
|
||||
}
|
||||
|
||||
const char* theMixabilityString = NULL;
|
||||
if((inDescription.mFormatFlags & kIsNonMixableFlag) == 0)
|
||||
{
|
||||
theMixabilityString = "Mixable";
|
||||
}
|
||||
else
|
||||
{
|
||||
theMixabilityString = "Unmixable";
|
||||
}
|
||||
|
||||
if(inAbbreviate)
|
||||
{
|
||||
if(theEndianString != NULL)
|
||||
{
|
||||
if(thePackingString != NULL)
|
||||
{
|
||||
snprintf(outName, inMaxNameLength, "%s %d Ch %s %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(outName, inMaxNameLength, "%s %d Ch %s %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, theKindString, (int)inDescription.mBitsPerChannel);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(thePackingString != NULL)
|
||||
{
|
||||
snprintf(outName, inMaxNameLength, "%s %d Ch %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)((inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(outName, inMaxNameLength, "%s %d Ch %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theKindString, (int)inDescription.mBitsPerChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(theEndianString != NULL)
|
||||
{
|
||||
if(thePackingString != NULL)
|
||||
{
|
||||
snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s %s Aligned %s in %d Bits", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(thePackingString != NULL)
|
||||
{
|
||||
snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s Aligned %s in %d Bits", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString, thePackingString, (int)(inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case kAudioFormatAC3:
|
||||
strlcpy(outName, "AC-3", sizeof(outName));
|
||||
break;
|
||||
|
||||
case kAudioFormat60958AC3:
|
||||
strlcpy(outName, "AC-3 for SPDIF", sizeof(outName));
|
||||
break;
|
||||
|
||||
default:
|
||||
CACopy4CCToCString(outName, inDescription.mFormatID);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
#if CoreAudio_Debug
|
||||
#include "CALogMacros.h"
|
||||
|
||||
void CAStreamBasicDescription::PrintToLog(const AudioStreamBasicDescription& inDesc)
|
||||
{
|
||||
PrintFloat (" Sample Rate: ", inDesc.mSampleRate);
|
||||
Print4CharCode (" Format ID: ", inDesc.mFormatID);
|
||||
PrintHex (" Format Flags: ", inDesc.mFormatFlags);
|
||||
PrintInt (" Bytes per Packet: ", inDesc.mBytesPerPacket);
|
||||
PrintInt (" Frames per Packet: ", inDesc.mFramesPerPacket);
|
||||
PrintInt (" Bytes per Frame: ", inDesc.mBytesPerFrame);
|
||||
PrintInt (" Channels per Frame: ", inDesc.mChannelsPerFrame);
|
||||
PrintInt (" Bits per Channel: ", inDesc.mBitsPerChannel);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
|
||||
{
|
||||
bool theAnswer = false;
|
||||
bool isDone = false;
|
||||
|
||||
// note that if either side is 0, that field is skipped
|
||||
|
||||
// format ID is the first order sort
|
||||
if((!isDone) && ((x.mFormatID != 0) && (y.mFormatID != 0)))
|
||||
{
|
||||
if(x.mFormatID != y.mFormatID)
|
||||
{
|
||||
// formats are sorted numerically except that linear
|
||||
// PCM is always first
|
||||
if(x.mFormatID == kAudioFormatLinearPCM)
|
||||
{
|
||||
theAnswer = true;
|
||||
}
|
||||
else if(y.mFormatID == kAudioFormatLinearPCM)
|
||||
{
|
||||
theAnswer = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
theAnswer = x.mFormatID < y.mFormatID;
|
||||
}
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// mixable is always better than non-mixable for linear PCM and should be the second order sort item
|
||||
if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM)))
|
||||
{
|
||||
if(((x.mFormatFlags & kIsNonMixableFlag) == 0) && ((y.mFormatFlags & kIsNonMixableFlag) != 0))
|
||||
{
|
||||
theAnswer = true;
|
||||
isDone = true;
|
||||
}
|
||||
else if(((x.mFormatFlags & kIsNonMixableFlag) != 0) && ((y.mFormatFlags & kIsNonMixableFlag) == 0))
|
||||
{
|
||||
theAnswer = false;
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
// floating point vs integer for linear PCM only
|
||||
if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM)))
|
||||
{
|
||||
if((x.mFormatFlags & kAudioFormatFlagIsFloat) != (y.mFormatFlags & kAudioFormatFlagIsFloat))
|
||||
{
|
||||
// floating point is better than integer
|
||||
theAnswer = y.mFormatFlags & kAudioFormatFlagIsFloat;
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
// bit depth
|
||||
if((!isDone) && ((x.mBitsPerChannel != 0) && (y.mBitsPerChannel != 0)))
|
||||
{
|
||||
if(x.mBitsPerChannel != y.mBitsPerChannel)
|
||||
{
|
||||
// deeper bit depths are higher quality
|
||||
theAnswer = x.mBitsPerChannel < y.mBitsPerChannel;
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
// sample rate
|
||||
if((!isDone) && fnonzero(x.mSampleRate) && fnonzero(y.mSampleRate))
|
||||
{
|
||||
if(fnotequal(x.mSampleRate, y.mSampleRate))
|
||||
{
|
||||
// higher sample rates are higher quality
|
||||
theAnswer = x.mSampleRate < y.mSampleRate;
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
// number of channels
|
||||
if((!isDone) && ((x.mChannelsPerFrame != 0) && (y.mChannelsPerFrame != 0)))
|
||||
{
|
||||
if(x.mChannelsPerFrame != y.mChannelsPerFrame)
|
||||
{
|
||||
// more channels is higher quality
|
||||
theAnswer = x.mChannelsPerFrame < y.mChannelsPerFrame;
|
||||
//isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
UInt32 CAStreamBasicDescription::GetRegularizedFormatFlags(bool forHardware) const
|
||||
{
|
||||
UInt32 result = mFormatFlags;
|
||||
|
||||
if (IsPCM()) {
|
||||
// First, if there are bits other than AllClear set, clear it because it's lying.
|
||||
if (result & ~kAudioFormatFlagsAreAllClear)
|
||||
result &= ~kAudioFormatFlagsAreAllClear;
|
||||
|
||||
// If not forHardware, remove the mixability flag.
|
||||
if (!forHardware)
|
||||
result &= ~kLinearPCMFormatFlagIsNonMixable;
|
||||
|
||||
// If the format has no extra bits, then it is packed.
|
||||
if (!PackednessIsSignificant())
|
||||
result |= kLinearPCMFormatFlagIsPacked;
|
||||
|
||||
// Remove the high-aligned flag if alignment is irrelevant.
|
||||
if (!AlignmentIsSignificant())
|
||||
result &= ~kLinearPCMFormatFlagIsAlignedHigh;
|
||||
|
||||
// Remove the signed integer bit if it's float
|
||||
if (result & kLinearPCMFormatFlagIsFloat)
|
||||
result &= ~kLinearPCMFormatFlagIsSignedInteger;
|
||||
|
||||
// If the bit depth is 8 bits or less and the format is packed, we don't care about endianness
|
||||
if (mBitsPerChannel <= 8 && (result & kLinearPCMFormatFlagIsPacked))
|
||||
result &= kAudioFormatFlagIsBigEndian;
|
||||
|
||||
// If there is 1 channel, we don't care about non-interleavedness.
|
||||
if (mChannelsPerFrame == 1)
|
||||
result &= ~kLinearPCMFormatFlagIsNonInterleaved;
|
||||
|
||||
// Finally, if the bits really are all 0, set the AllClear flag.
|
||||
if (result == 0)
|
||||
result = kAudioFormatFlagsAreAllClear;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// private
|
||||
bool CAStreamBasicDescription::EquivalentFormatFlags(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y, bool forHardware, bool usingWildcards)
|
||||
{
|
||||
if (usingWildcards)
|
||||
{
|
||||
// if either of the formats is a wildcard, we don't care about the flags
|
||||
// if either of the flags is a wildcard, we have matched
|
||||
if (x.mFormatID == 0 || y.mFormatID == 0 || x.mFormatFlags == 0 || y.mFormatFlags == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (x.mFormatID != kAudioFormatLinearPCM) // we already know the formatID's match and have taken wildcards out of the picture.
|
||||
return x.mFormatFlags == y.mFormatFlags;
|
||||
|
||||
// It is safe to down-cast from AudioStreamBasicDescription to its C++ wrapper.
|
||||
// The cast could be avoided with a copy, but here, efficiency matters.
|
||||
const CAStreamBasicDescription &a = *static_cast<const CAStreamBasicDescription *>(&x);
|
||||
const CAStreamBasicDescription &b = *static_cast<const CAStreamBasicDescription *>(&y);
|
||||
|
||||
return a.GetRegularizedFormatFlags(forHardware) == b.GetRegularizedFormatFlags(forHardware);
|
||||
}
|
||||
|
||||
bool CAStreamBasicDescription::IsExactlyEqual(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y)
|
||||
{
|
||||
// mReserved didn't exist in early versions of OS X; we want to ignore differences there.
|
||||
// The structure is properly packed up until that point, so the shortcut of using memcmp()
|
||||
// instead of individual field comparisons is safe.
|
||||
return memcmp(&x, &y, offsetof(AudioStreamBasicDescription, mReserved)) == 0;
|
||||
}
|
||||
|
||||
#define MATCH_WITH_WILDCARD(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name))
|
||||
|
||||
bool CAStreamBasicDescription::IsEquivalent(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y, ComparisonOptions options)
|
||||
{
|
||||
if (options & kCompareUsingWildcards) {
|
||||
return
|
||||
// check the sample rate
|
||||
(fiszero(x.mSampleRate) || fiszero(y.mSampleRate) || fequal(x.mSampleRate, y.mSampleRate))
|
||||
|
||||
// check the format ids
|
||||
&& MATCH_WITH_WILDCARD(mFormatID)
|
||||
|
||||
// check the bytes per packet
|
||||
&& MATCH_WITH_WILDCARD(mBytesPerPacket)
|
||||
|
||||
// check the frames per packet
|
||||
&& MATCH_WITH_WILDCARD(mFramesPerPacket)
|
||||
|
||||
// check the bytes per frame
|
||||
&& MATCH_WITH_WILDCARD(mBytesPerFrame)
|
||||
|
||||
// check the channels per frame
|
||||
&& MATCH_WITH_WILDCARD(mChannelsPerFrame)
|
||||
|
||||
// check the bits per channel
|
||||
&& MATCH_WITH_WILDCARD(mBitsPerChannel)
|
||||
|
||||
// Only if we get this far, do the work of matching the format flags
|
||||
&& EquivalentFormatFlags(x, y, options & kCompareForHardware, /*usingWildcards=*/true);
|
||||
} else {
|
||||
return x.mSampleRate == y.mSampleRate
|
||||
&& x.mFormatID == y.mFormatID
|
||||
&& x.mBytesPerPacket == y.mBytesPerPacket
|
||||
&& x.mFramesPerPacket == y.mFramesPerPacket
|
||||
&& x.mChannelsPerFrame == y.mChannelsPerFrame
|
||||
&& x.mBitsPerChannel == y.mBitsPerChannel
|
||||
&& EquivalentFormatFlags(x, y, options & kCompareForHardware, /*usingWildcards=*/false);
|
||||
}
|
||||
}
|
||||
|
||||
// DEPRECATED.
|
||||
bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
|
||||
{
|
||||
return CAStreamBasicDescription::IsEquivalent(x, y, CAStreamBasicDescription::kCompareUsingWildcards | CAStreamBasicDescription::kCompareForHardware);
|
||||
}
|
||||
|
||||
// To be deprecated.
|
||||
bool CAStreamBasicDescription::IsEqual(const AudioStreamBasicDescription &other, bool interpretingWildcards) const
|
||||
{
|
||||
if (interpretingWildcards)
|
||||
return CAStreamBasicDescription::IsEquivalent(*this, other, CAStreamBasicDescription::kCompareUsingWildcards | CAStreamBasicDescription::kCompareForHardware);
|
||||
return IsExactlyEqual(*this, other);
|
||||
}
|
||||
|
||||
// DEPRECATED.
|
||||
bool CAStreamBasicDescription::IsEqual(const AudioStreamBasicDescription &other) const
|
||||
{
|
||||
return CAStreamBasicDescription::IsEquivalent(*this, other, CAStreamBasicDescription::kCompareUsingWildcards | CAStreamBasicDescription::kCompareForHardware);
|
||||
}
|
||||
|
||||
bool SanityCheck(const AudioStreamBasicDescription& x)
|
||||
{
|
||||
// This function returns false if there are sufficiently insane values in any field.
|
||||
// It is very conservative so even some very unlikely values will pass.
|
||||
// This is just meant to catch the case where the data from a file is corrupted.
|
||||
|
||||
return
|
||||
(x.mSampleRate >= 0.)
|
||||
&& (x.mSampleRate < 3e6) // SACD sample rate is 2.8224 MHz
|
||||
&& (x.mBytesPerPacket < 1000000)
|
||||
&& (x.mFramesPerPacket < 1000000)
|
||||
&& (x.mBytesPerFrame < 1000000)
|
||||
&& (x.mChannelsPerFrame > 0)
|
||||
&& (x.mChannelsPerFrame <= 1024)
|
||||
&& (x.mBitsPerChannel <= 1024)
|
||||
&& (x.mFormatID != 0)
|
||||
&& !(x.mFormatID == kAudioFormatLinearPCM && (x.mFramesPerPacket != 1 || x.mBytesPerPacket != x.mBytesPerFrame));
|
||||
}
|
||||
|
||||
bool CAStreamBasicDescription::FromText(const char *inTextDesc, AudioStreamBasicDescription &fmt)
|
||||
{
|
||||
const char *p = inTextDesc;
|
||||
|
||||
memset(&fmt, 0, sizeof(fmt));
|
||||
|
||||
bool isPCM = true; // until proven otherwise
|
||||
UInt32 pcmFlags = kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
|
||||
|
||||
if (p[0] == '-') // previously we required a leading dash on PCM formats
|
||||
++p;
|
||||
|
||||
if (p[0] == 'B' && p[1] == 'E') {
|
||||
pcmFlags |= kLinearPCMFormatFlagIsBigEndian;
|
||||
p += 2;
|
||||
} else if (p[0] == 'L' && p[1] == 'E') {
|
||||
p += 2;
|
||||
} else {
|
||||
// default is native-endian
|
||||
#if TARGET_RT_BIG_ENDIAN
|
||||
pcmFlags |= kLinearPCMFormatFlagIsBigEndian;
|
||||
#endif
|
||||
}
|
||||
if (p[0] == 'F') {
|
||||
pcmFlags = (pcmFlags & ~static_cast<UInt32>(kAudioFormatFlagIsSignedInteger)) | kAudioFormatFlagIsFloat;
|
||||
++p;
|
||||
} else {
|
||||
if (p[0] == 'U') {
|
||||
pcmFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsSignedInteger);
|
||||
++p;
|
||||
}
|
||||
if (p[0] == 'I')
|
||||
++p;
|
||||
else {
|
||||
// it's not PCM; presumably some other format (NOT VALIDATED; use AudioFormat for that)
|
||||
isPCM = false;
|
||||
p = inTextDesc; // go back to the beginning
|
||||
char buf[4] = { ' ',' ',' ',' ' };
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (*p != '\\') {
|
||||
if ((buf[i] = *p++) == '\0') {
|
||||
// special-case for 'aac'
|
||||
if (i != 3) return false;
|
||||
--p; // keep pointing at the terminating null
|
||||
buf[i] = ' ';
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// "\xNN" is a hex byte
|
||||
if (*++p != 'x') return false;
|
||||
int x;
|
||||
if (sscanf(++p, "%02X", &x) != 1) return false;
|
||||
buf[i] = static_cast<char>(x);
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (strchr("-@/#", buf[3])) {
|
||||
// further special-casing for 'aac'
|
||||
buf[3] = ' ';
|
||||
--p;
|
||||
}
|
||||
|
||||
memcpy(&fmt.mFormatID, buf, 4);
|
||||
fmt.mFormatID = CFSwapInt32BigToHost(fmt.mFormatID);
|
||||
}
|
||||
}
|
||||
|
||||
if (isPCM) {
|
||||
fmt.mFormatID = kAudioFormatLinearPCM;
|
||||
fmt.mFormatFlags = pcmFlags;
|
||||
fmt.mFramesPerPacket = 1;
|
||||
fmt.mChannelsPerFrame = 1;
|
||||
UInt32 bitdepth = 0, fracbits = 0;
|
||||
while (isdigit(*p))
|
||||
bitdepth = 10 * bitdepth + static_cast<UInt32>(*p++ - '0');
|
||||
if (*p == '.') {
|
||||
++p;
|
||||
if (!isdigit(*p)) {
|
||||
fprintf(stderr, "Expected fractional bits following '.'\n");
|
||||
goto Bail;
|
||||
}
|
||||
while (isdigit(*p))
|
||||
fracbits = 10 * fracbits + static_cast<UInt32>(*p++ - '0');
|
||||
bitdepth += fracbits;
|
||||
fmt.mFormatFlags |= (fracbits << kLinearPCMFormatFlagsSampleFractionShift);
|
||||
}
|
||||
fmt.mBitsPerChannel = bitdepth;
|
||||
fmt.mBytesPerPacket = fmt.mBytesPerFrame = (bitdepth + 7) / 8;
|
||||
if (bitdepth & 7) {
|
||||
// assume unpacked. (packed odd bit depths are describable but not supported in AudioConverter.)
|
||||
fmt.mFormatFlags &= ~static_cast<UInt32>(kLinearPCMFormatFlagIsPacked);
|
||||
// alignment matters; default to high-aligned. use ':L_' for low.
|
||||
fmt.mFormatFlags |= kLinearPCMFormatFlagIsAlignedHigh;
|
||||
}
|
||||
}
|
||||
if (*p == '@') {
|
||||
++p;
|
||||
while (isdigit(*p))
|
||||
fmt.mSampleRate = 10 * fmt.mSampleRate + (*p++ - '0');
|
||||
}
|
||||
if (*p == '/') {
|
||||
UInt32 flags = 0;
|
||||
while (true) {
|
||||
char c = *++p;
|
||||
if (c >= '0' && c <= '9')
|
||||
flags = (flags << 4) | static_cast<UInt32>(c - '0');
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
flags = (flags << 4) | static_cast<UInt32>(c - 'A' + 10);
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
flags = (flags << 4) | static_cast<UInt32>(c - 'a' + 10);
|
||||
else break;
|
||||
}
|
||||
fmt.mFormatFlags = flags;
|
||||
}
|
||||
if (*p == '#') {
|
||||
++p;
|
||||
while (isdigit(*p))
|
||||
fmt.mFramesPerPacket = 10 * fmt.mFramesPerPacket + static_cast<UInt32>(*p++ - '0');
|
||||
}
|
||||
if (*p == ':') {
|
||||
++p;
|
||||
fmt.mFormatFlags &= ~static_cast<UInt32>(kLinearPCMFormatFlagIsPacked);
|
||||
if (*p == 'L')
|
||||
fmt.mFormatFlags &= ~static_cast<UInt32>(kLinearPCMFormatFlagIsAlignedHigh);
|
||||
else if (*p == 'H')
|
||||
fmt.mFormatFlags |= kLinearPCMFormatFlagIsAlignedHigh;
|
||||
else
|
||||
goto Bail;
|
||||
++p;
|
||||
UInt32 bytesPerFrame = 0;
|
||||
while (isdigit(*p))
|
||||
bytesPerFrame = 10 * bytesPerFrame + static_cast<UInt32>(*p++ - '0');
|
||||
fmt.mBytesPerFrame = fmt.mBytesPerPacket = bytesPerFrame;
|
||||
}
|
||||
if (*p == ',') {
|
||||
++p;
|
||||
int ch = 0;
|
||||
while (isdigit(*p))
|
||||
ch = 10 * ch + (*p++ - '0');
|
||||
fmt.mChannelsPerFrame = static_cast<UInt32>(ch);
|
||||
if (*p == 'D') {
|
||||
++p;
|
||||
if (fmt.mFormatID != kAudioFormatLinearPCM) {
|
||||
fprintf(stderr, "non-interleaved flag invalid for non-PCM formats\n");
|
||||
goto Bail;
|
||||
}
|
||||
fmt.mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
|
||||
} else {
|
||||
if (*p == 'I') ++p; // default
|
||||
if (fmt.mFormatID == kAudioFormatLinearPCM)
|
||||
fmt.mBytesPerPacket = fmt.mBytesPerFrame *= static_cast<UInt32>(ch);
|
||||
}
|
||||
}
|
||||
if (*p != '\0') {
|
||||
fprintf(stderr, "extra characters at end of format string: %s\n", p);
|
||||
goto Bail;
|
||||
}
|
||||
return true;
|
||||
|
||||
Bail:
|
||||
fprintf(stderr, "Invalid format string: %s\n", inTextDesc);
|
||||
fprintf(stderr, "Syntax of format strings is: \n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *CAStreamBasicDescription::sTextParsingUsageString =
|
||||
"format[@sample_rate_hz][/format_flags][#frames_per_packet][:LHbytesPerFrame][,channelsDI].\n"
|
||||
"Format for PCM is [-][BE|LE]{F|I|UI}{bitdepth}; else a 4-char format code (e.g. aac, alac).\n";
|
@ -1,448 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#ifndef __CAStreamBasicDescription_h__
|
||||
#define __CAStreamBasicDescription_h__
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreAudio/CoreAudioTypes.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#else
|
||||
#include "CoreAudioTypes.h"
|
||||
#include "CoreFoundation.h"
|
||||
#endif
|
||||
|
||||
#include "CADebugMacros.h"
|
||||
#include <string.h> // for memset, memcpy
|
||||
#include <stdio.h> // for FILE *
|
||||
|
||||
#pragma mark This file needs to compile on more earlier versions of the OS, so please keep that in mind when editing it
|
||||
|
||||
#ifndef ASBD_STRICT_EQUALITY
|
||||
#define ASBD_STRICT_EQUALITY 0
|
||||
#endif
|
||||
|
||||
#if __GNUC__ && ASBD_STRICT_EQUALITY
|
||||
// not turning on the deprecation just yet
|
||||
#define ASBD_EQUALITY_DEPRECATED __attribute__((deprecated("This method uses a possibly surprising wildcard comparison (i.e. 0 channels == 1 channel)")))
|
||||
#else
|
||||
#define ASBD_EQUALITY_DEPRECATED
|
||||
#endif
|
||||
|
||||
#ifndef CA_CANONICAL_DEPRECATED
|
||||
#define CA_CANONICAL_DEPRECATED
|
||||
#endif
|
||||
|
||||
extern char *CAStringForOSType (OSType t, char *writeLocation, size_t bufsize);
|
||||
|
||||
// define Leopard specific symbols for backward compatibility if applicable
|
||||
#if COREAUDIOTYPES_VERSION < 1050
|
||||
typedef Float32 AudioSampleType;
|
||||
enum { kAudioFormatFlagsCanonical = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked };
|
||||
#endif
|
||||
#if COREAUDIOTYPES_VERSION < 1051
|
||||
typedef Float32 AudioUnitSampleType;
|
||||
enum {
|
||||
kLinearPCMFormatFlagsSampleFractionShift = 7,
|
||||
kLinearPCMFormatFlagsSampleFractionMask = (0x3F << kLinearPCMFormatFlagsSampleFractionShift),
|
||||
};
|
||||
#endif
|
||||
|
||||
// define the IsMixable format flag for all versions of the system
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3)
|
||||
enum { kIsNonMixableFlag = kAudioFormatFlagIsNonMixable };
|
||||
#else
|
||||
enum { kIsNonMixableFlag = (1L << 6) };
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// CAStreamBasicDescription
|
||||
//
|
||||
// This is a wrapper class for the AudioStreamBasicDescription struct.
|
||||
// It adds a number of convenience routines, but otherwise adds nothing
|
||||
// to the footprint of the original struct.
|
||||
//=============================================================================
|
||||
class CAStreamBasicDescription :
|
||||
public AudioStreamBasicDescription
|
||||
{
|
||||
|
||||
// Constants
|
||||
public:
|
||||
static const AudioStreamBasicDescription sEmpty;
|
||||
|
||||
enum CommonPCMFormat {
|
||||
kPCMFormatOther = 0,
|
||||
kPCMFormatFloat32 = 1,
|
||||
kPCMFormatInt16 = 2,
|
||||
kPCMFormatFixed824 = 3,
|
||||
kPCMFormatFloat64 = 4,
|
||||
kPCMFormatInt32 = 5
|
||||
};
|
||||
|
||||
// options for IsEquivalent
|
||||
enum {
|
||||
kCompareDefault = 0,
|
||||
kCompareUsingWildcards = 1 << 0, // treats fields with values of 0 as wildcards.
|
||||
// too liberal if you need to represent 0 channels.
|
||||
kCompareForHardware = 1 << 1, // formats are hardware formats (IsNonMixable flag is significant).
|
||||
|
||||
kCompareForHardwareUsingWildcards = kCompareForHardware + kCompareUsingWildcards // for convenience
|
||||
};
|
||||
typedef UInt32 ComparisonOptions;
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAStreamBasicDescription();
|
||||
|
||||
CAStreamBasicDescription(const AudioStreamBasicDescription &desc);
|
||||
|
||||
CAStreamBasicDescription( double inSampleRate, UInt32 inFormatID,
|
||||
UInt32 inBytesPerPacket, UInt32 inFramesPerPacket,
|
||||
UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame,
|
||||
UInt32 inBitsPerChannel, UInt32 inFormatFlags);
|
||||
|
||||
CAStreamBasicDescription( double inSampleRate, UInt32 inNumChannels, CommonPCMFormat pcmf, bool inIsInterleaved) {
|
||||
unsigned wordsize;
|
||||
|
||||
mSampleRate = inSampleRate;
|
||||
mFormatID = kAudioFormatLinearPCM;
|
||||
mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
|
||||
mFramesPerPacket = 1;
|
||||
mChannelsPerFrame = inNumChannels;
|
||||
mBytesPerFrame = mBytesPerPacket = 0;
|
||||
mReserved = 0;
|
||||
|
||||
switch (pcmf) {
|
||||
default:
|
||||
return;
|
||||
case kPCMFormatFloat32:
|
||||
wordsize = 4;
|
||||
mFormatFlags |= kAudioFormatFlagIsFloat;
|
||||
break;
|
||||
case kPCMFormatFloat64:
|
||||
wordsize = 8;
|
||||
mFormatFlags |= kAudioFormatFlagIsFloat;
|
||||
break;
|
||||
case kPCMFormatInt16:
|
||||
wordsize = 2;
|
||||
mFormatFlags |= kAudioFormatFlagIsSignedInteger;
|
||||
break;
|
||||
case kPCMFormatInt32:
|
||||
wordsize = 4;
|
||||
mFormatFlags |= kAudioFormatFlagIsSignedInteger;
|
||||
break;
|
||||
case kPCMFormatFixed824:
|
||||
wordsize = 4;
|
||||
mFormatFlags |= kAudioFormatFlagIsSignedInteger | (24 << kLinearPCMFormatFlagsSampleFractionShift);
|
||||
break;
|
||||
}
|
||||
mBitsPerChannel = wordsize * 8;
|
||||
if (inIsInterleaved)
|
||||
mBytesPerFrame = mBytesPerPacket = wordsize * inNumChannels;
|
||||
else {
|
||||
mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
|
||||
mBytesPerFrame = mBytesPerPacket = wordsize;
|
||||
}
|
||||
}
|
||||
|
||||
// Assignment
|
||||
CAStreamBasicDescription& operator=(const AudioStreamBasicDescription& v) { SetFrom(v); return *this; }
|
||||
|
||||
void SetFrom(const AudioStreamBasicDescription &desc)
|
||||
{
|
||||
memcpy(this, &desc, sizeof(AudioStreamBasicDescription));
|
||||
}
|
||||
|
||||
bool FromText(const char *inTextDesc) { return FromText(inTextDesc, *this); }
|
||||
static bool FromText(const char *inTextDesc, AudioStreamBasicDescription &outDesc);
|
||||
// return true if parsing was successful
|
||||
|
||||
static const char *sTextParsingUsageString;
|
||||
|
||||
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
//
|
||||
// interrogation
|
||||
|
||||
bool IsPCM() const { return mFormatID == kAudioFormatLinearPCM; }
|
||||
|
||||
bool PackednessIsSignificant() const
|
||||
{
|
||||
Assert(IsPCM(), "PackednessIsSignificant only applies for PCM");
|
||||
return (SampleWordSize() << 3) != mBitsPerChannel;
|
||||
}
|
||||
|
||||
bool AlignmentIsSignificant() const
|
||||
{
|
||||
return PackednessIsSignificant() || (mBitsPerChannel & 7) != 0;
|
||||
}
|
||||
|
||||
bool IsInterleaved() const
|
||||
{
|
||||
return !(mFormatFlags & kAudioFormatFlagIsNonInterleaved);
|
||||
}
|
||||
|
||||
bool IsSignedInteger() const
|
||||
{
|
||||
return IsPCM() && (mFormatFlags & kAudioFormatFlagIsSignedInteger);
|
||||
}
|
||||
|
||||
bool IsFloat() const
|
||||
{
|
||||
return IsPCM() && (mFormatFlags & kAudioFormatFlagIsFloat);
|
||||
}
|
||||
|
||||
bool IsNativeEndian() const
|
||||
{
|
||||
return (mFormatFlags & kAudioFormatFlagIsBigEndian) == kAudioFormatFlagsNativeEndian;
|
||||
}
|
||||
|
||||
// for sanity with interleaved/deinterleaved possibilities, never access mChannelsPerFrame, use these:
|
||||
UInt32 NumberInterleavedChannels() const { return IsInterleaved() ? mChannelsPerFrame : 1; }
|
||||
UInt32 NumberChannelStreams() const { return IsInterleaved() ? 1 : mChannelsPerFrame; }
|
||||
UInt32 NumberChannels() const { return mChannelsPerFrame; }
|
||||
UInt32 SampleWordSize() const {
|
||||
return (mBytesPerFrame > 0 && NumberInterleavedChannels()) ? mBytesPerFrame / NumberInterleavedChannels() : 0;
|
||||
}
|
||||
|
||||
UInt32 FramesToBytes(UInt32 nframes) const { return nframes * mBytesPerFrame; }
|
||||
UInt32 BytesToFrames(UInt32 nbytes) const {
|
||||
Assert(mBytesPerFrame > 0, "bytesPerFrame must be > 0 in BytesToFrames");
|
||||
return nbytes / mBytesPerFrame;
|
||||
}
|
||||
|
||||
bool SameChannelsAndInterleaving(const CAStreamBasicDescription &a) const
|
||||
{
|
||||
return this->NumberChannels() == a.NumberChannels() && this->IsInterleaved() == a.IsInterleaved();
|
||||
}
|
||||
|
||||
bool IdentifyCommonPCMFormat(CommonPCMFormat &outFormat, bool *outIsInterleaved=NULL) const
|
||||
{ // return true if it's a valid PCM format.
|
||||
|
||||
outFormat = kPCMFormatOther;
|
||||
// trap out patently invalid formats.
|
||||
if (mFormatID != kAudioFormatLinearPCM || mFramesPerPacket != 1 || mBytesPerFrame != mBytesPerPacket || mBitsPerChannel/8 > mBytesPerFrame || mChannelsPerFrame == 0)
|
||||
return false;
|
||||
bool interleaved = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
|
||||
if (outIsInterleaved != NULL) *outIsInterleaved = interleaved;
|
||||
unsigned wordsize = mBytesPerFrame;
|
||||
if (interleaved) {
|
||||
if (wordsize % mChannelsPerFrame != 0) return false;
|
||||
wordsize /= mChannelsPerFrame;
|
||||
}
|
||||
|
||||
if ((mFormatFlags & kAudioFormatFlagIsBigEndian) == kAudioFormatFlagsNativeEndian
|
||||
&& wordsize * 8 == mBitsPerChannel) {
|
||||
// packed and native endian, good
|
||||
if (mFormatFlags & kLinearPCMFormatFlagIsFloat) {
|
||||
// float: reject nonsense bits
|
||||
if (mFormatFlags & (kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagsSampleFractionMask))
|
||||
return false;
|
||||
if (wordsize == 4)
|
||||
outFormat = kPCMFormatFloat32;
|
||||
if (wordsize == 8)
|
||||
outFormat = kPCMFormatFloat64;
|
||||
} else if (mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) {
|
||||
// signed int
|
||||
unsigned fracbits = (mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift;
|
||||
if (wordsize == 4 && fracbits == 24)
|
||||
outFormat = kPCMFormatFixed824;
|
||||
else if (wordsize == 4 && fracbits == 0)
|
||||
outFormat = kPCMFormatInt32;
|
||||
else if (wordsize == 2 && fracbits == 0)
|
||||
outFormat = kPCMFormatInt16;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsCommonFloat32(bool *outIsInterleaved=NULL) const {
|
||||
CommonPCMFormat fmt;
|
||||
return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatFloat32;
|
||||
}
|
||||
bool IsCommonFloat64(bool *outIsInterleaved=NULL) const {
|
||||
CommonPCMFormat fmt;
|
||||
return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatFloat64;
|
||||
}
|
||||
bool IsCommonFixed824(bool *outIsInterleaved=NULL) const {
|
||||
CommonPCMFormat fmt;
|
||||
return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatFixed824;
|
||||
}
|
||||
bool IsCommonInt16(bool *outIsInterleaved=NULL) const {
|
||||
CommonPCMFormat fmt;
|
||||
return IdentifyCommonPCMFormat(fmt, outIsInterleaved) && fmt == kPCMFormatInt16;
|
||||
}
|
||||
|
||||
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
//
|
||||
// manipulation
|
||||
|
||||
CA_CANONICAL_DEPRECATED
|
||||
void SetCanonical(UInt32 nChannels, bool interleaved)
|
||||
// note: leaves sample rate untouched
|
||||
{
|
||||
mFormatID = kAudioFormatLinearPCM;
|
||||
UInt32 sampleSize = SizeOf32(AudioSampleType);
|
||||
mFormatFlags = kAudioFormatFlagsCanonical;
|
||||
mBitsPerChannel = 8 * sampleSize;
|
||||
mChannelsPerFrame = nChannels;
|
||||
mFramesPerPacket = 1;
|
||||
if (interleaved)
|
||||
mBytesPerPacket = mBytesPerFrame = nChannels * sampleSize;
|
||||
else {
|
||||
mBytesPerPacket = mBytesPerFrame = sampleSize;
|
||||
mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
|
||||
}
|
||||
}
|
||||
|
||||
CA_CANONICAL_DEPRECATED
|
||||
bool IsCanonical() const
|
||||
{
|
||||
if (mFormatID != kAudioFormatLinearPCM) return false;
|
||||
UInt32 reqFormatFlags;
|
||||
UInt32 flagsMask = (kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsBigEndian | kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagsSampleFractionMask);
|
||||
bool interleaved = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
|
||||
unsigned sampleSize = SizeOf32(AudioSampleType);
|
||||
reqFormatFlags = kAudioFormatFlagsCanonical;
|
||||
UInt32 reqFrameSize = interleaved ? (mChannelsPerFrame * sampleSize) : sampleSize;
|
||||
|
||||
return ((mFormatFlags & flagsMask) == reqFormatFlags
|
||||
&& mBitsPerChannel == 8 * sampleSize
|
||||
&& mFramesPerPacket == 1
|
||||
&& mBytesPerFrame == reqFrameSize
|
||||
&& mBytesPerPacket == reqFrameSize);
|
||||
}
|
||||
|
||||
CA_CANONICAL_DEPRECATED
|
||||
void SetAUCanonical(UInt32 nChannels, bool interleaved)
|
||||
{
|
||||
mFormatID = kAudioFormatLinearPCM;
|
||||
#if CA_PREFER_FIXED_POINT
|
||||
mFormatFlags = kAudioFormatFlagsCanonical | (kAudioUnitSampleFractionBits << kLinearPCMFormatFlagsSampleFractionShift);
|
||||
#else
|
||||
mFormatFlags = kAudioFormatFlagsCanonical;
|
||||
#endif
|
||||
mChannelsPerFrame = nChannels;
|
||||
mFramesPerPacket = 1;
|
||||
mBitsPerChannel = 8 * SizeOf32(AudioUnitSampleType);
|
||||
if (interleaved)
|
||||
mBytesPerPacket = mBytesPerFrame = nChannels * SizeOf32(AudioUnitSampleType);
|
||||
else {
|
||||
mBytesPerPacket = mBytesPerFrame = SizeOf32(AudioUnitSampleType);
|
||||
mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
|
||||
}
|
||||
}
|
||||
|
||||
void ChangeNumberChannels(UInt32 nChannels, bool interleaved)
|
||||
// alter an existing format
|
||||
{
|
||||
Assert(IsPCM(), "ChangeNumberChannels only works for PCM formats");
|
||||
UInt32 wordSize = SampleWordSize(); // get this before changing ANYTHING
|
||||
if (wordSize == 0)
|
||||
wordSize = (mBitsPerChannel + 7) / 8;
|
||||
mChannelsPerFrame = nChannels;
|
||||
mFramesPerPacket = 1;
|
||||
if (interleaved) {
|
||||
mBytesPerPacket = mBytesPerFrame = nChannels * wordSize;
|
||||
mFormatFlags &= ~static_cast<UInt32>(kAudioFormatFlagIsNonInterleaved);
|
||||
} else {
|
||||
mBytesPerPacket = mBytesPerFrame = wordSize;
|
||||
mFormatFlags |= kAudioFormatFlagIsNonInterleaved;
|
||||
}
|
||||
}
|
||||
|
||||
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
//
|
||||
// other
|
||||
|
||||
// IsEqual: Deprecated because of widespread errors due to the default wildcarding behavior.
|
||||
ASBD_EQUALITY_DEPRECATED
|
||||
bool IsEqual(const AudioStreamBasicDescription &other) const;
|
||||
bool IsEqual(const AudioStreamBasicDescription &other, bool interpretingWildcards) const;
|
||||
|
||||
// IsExactlyEqual: bit-for-bit. usually unnecessarily strict.
|
||||
static bool IsExactlyEqual(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y);
|
||||
|
||||
// IsEquivalent: Returns whether the two formats are functionally the same, i.e. if one could
|
||||
// be correctly passed as the other without an AudioConverter.
|
||||
static bool IsEquivalent(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y) { return IsEquivalent(x, y, kCompareDefault); }
|
||||
static bool IsEquivalent(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y, ComparisonOptions comparisonOptions);
|
||||
|
||||
// Member versions of IsExactlyEqual and IsEquivalent.
|
||||
bool IsExactlyEqual(const AudioStreamBasicDescription &other) const { return IsExactlyEqual(*this, other); }
|
||||
bool IsEquivalent(const AudioStreamBasicDescription &other) const { return IsEquivalent(*this, other); }
|
||||
bool IsEquivalent(const AudioStreamBasicDescription &other, ComparisonOptions comparisonOptions) const { return IsEquivalent(*this, other, comparisonOptions); }
|
||||
|
||||
void Print() const {
|
||||
Print (stdout);
|
||||
}
|
||||
|
||||
void Print(FILE* file) const {
|
||||
PrintFormat (file, "", "AudioStreamBasicDescription:");
|
||||
}
|
||||
|
||||
void PrintFormat(FILE *f, const char *indent, const char *name) const {
|
||||
char buf[256];
|
||||
fprintf(f, "%s%s %s\n", indent, name, AsString(buf, sizeof(buf)));
|
||||
}
|
||||
|
||||
void PrintFormat2(FILE *f, const char *indent, const char *name) const { // no trailing newline
|
||||
char buf[256];
|
||||
fprintf(f, "%s%s %s", indent, name, AsString(buf, sizeof(buf)));
|
||||
}
|
||||
|
||||
char * AsString(char *buf, size_t bufsize, bool brief=false) const;
|
||||
|
||||
static void Print (const AudioStreamBasicDescription &inDesc)
|
||||
{
|
||||
CAStreamBasicDescription desc(inDesc);
|
||||
desc.Print ();
|
||||
}
|
||||
|
||||
OSStatus Save(CFPropertyListRef *outData) const;
|
||||
|
||||
OSStatus Restore(CFPropertyListRef &inData);
|
||||
|
||||
// Operations
|
||||
static bool IsMixable(const AudioStreamBasicDescription& inDescription) { return (inDescription.mFormatID == kAudioFormatLinearPCM) && ((inDescription.mFormatFlags & kIsNonMixableFlag) == 0); }
|
||||
CA_CANONICAL_DEPRECATED
|
||||
static void NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription);
|
||||
CA_CANONICAL_DEPRECATED
|
||||
static void NormalizeLinearPCMFormat(bool inNativeEndian, AudioStreamBasicDescription& ioDescription);
|
||||
static void VirtualizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription);
|
||||
static void VirtualizeLinearPCMFormat(bool inNativeEndian, AudioStreamBasicDescription& ioDescription);
|
||||
static void ResetFormat(AudioStreamBasicDescription& ioDescription);
|
||||
static void FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription);
|
||||
static void GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, UInt32 inMaxNameLength, bool inAbbreviate, bool inIncludeSampleRate = false);
|
||||
|
||||
#if CoreAudio_Debug
|
||||
static void PrintToLog(const AudioStreamBasicDescription& inDesc);
|
||||
#endif
|
||||
|
||||
UInt32 GetRegularizedFormatFlags(bool forHardware) const;
|
||||
|
||||
private:
|
||||
static bool EquivalentFormatFlags(const AudioStreamBasicDescription &x, const AudioStreamBasicDescription &y, bool forHardware, bool usingWildcards);
|
||||
};
|
||||
|
||||
#define CAStreamBasicDescription_EmptyInit 0.0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
#define CAStreamBasicDescription_Empty { CAStreamBasicDescription_EmptyInit }
|
||||
|
||||
// operator== is deprecated because it uses the deprecated IsEqual(other, true).
|
||||
bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y);
|
||||
ASBD_EQUALITY_DEPRECATED bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y);
|
||||
#if TARGET_OS_MAC || (TARGET_OS_WIN32 && (_MSC_VER > 600))
|
||||
ASBD_EQUALITY_DEPRECATED inline bool operator!=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x == y); }
|
||||
ASBD_EQUALITY_DEPRECATED inline bool operator<=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return (x < y) || (x == y); }
|
||||
ASBD_EQUALITY_DEPRECATED inline bool operator>=(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !(x < y); }
|
||||
ASBD_EQUALITY_DEPRECATED inline bool operator>(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y) { return !((x < y) || (x == y)); }
|
||||
#endif
|
||||
|
||||
bool SanityCheck(const AudioStreamBasicDescription& x);
|
||||
|
||||
|
||||
#endif // __CAStreamBasicDescription_h__
|
@ -1,195 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#ifndef __CAThreadSafeList_h__
|
||||
#define __CAThreadSafeList_h__
|
||||
|
||||
#include "CAAtomicStack.h"
|
||||
|
||||
// linked list of T's
|
||||
// T must define operator ==
|
||||
template <class T>
|
||||
class TThreadSafeList {
|
||||
private:
|
||||
enum EEventType { kAdd, kRemove, kClear };
|
||||
class Node {
|
||||
public:
|
||||
Node * mNext;
|
||||
EEventType mEventType;
|
||||
T mObject;
|
||||
|
||||
Node *& next() { return mNext; }
|
||||
};
|
||||
|
||||
public:
|
||||
class iterator {
|
||||
public:
|
||||
iterator() { }
|
||||
iterator(Node *n) : mNode(n) { }
|
||||
|
||||
bool operator == (const iterator &other) const { return this->mNode == other.mNode; }
|
||||
bool operator != (const iterator &other) const { return this->mNode != other.mNode; }
|
||||
|
||||
T & operator * () const { return mNode->mObject; }
|
||||
|
||||
iterator & operator ++ () { mNode = mNode->next(); return *this; } // preincrement
|
||||
iterator operator ++ (int) { iterator tmp = *this; mNode = mNode->next(); return tmp; } // postincrement
|
||||
|
||||
private:
|
||||
Node * mNode;
|
||||
};
|
||||
|
||||
TThreadSafeList() { }
|
||||
~TThreadSafeList()
|
||||
{
|
||||
mActiveList.free_all();
|
||||
mPendingList.free_all();
|
||||
mFreeList.free_all();
|
||||
}
|
||||
|
||||
// These may be called on any thread
|
||||
|
||||
void deferred_add(const T &obj) // can be called on any thread
|
||||
{
|
||||
Node *node = AllocNode();
|
||||
node->mEventType = kAdd;
|
||||
node->mObject = obj;
|
||||
mPendingList.push_atomic(node);
|
||||
//mPendingList.dump("pending after add");
|
||||
}
|
||||
|
||||
void deferred_remove(const T &obj) // can be called on any thread
|
||||
{
|
||||
Node *node = AllocNode();
|
||||
node->mEventType = kRemove;
|
||||
node->mObject = obj;
|
||||
mPendingList.push_atomic(node);
|
||||
//mPendingList.dump("pending after remove");
|
||||
}
|
||||
|
||||
void deferred_clear() // can be called on any thread
|
||||
{
|
||||
Node *node = AllocNode();
|
||||
node->mEventType = kClear;
|
||||
mPendingList.push_atomic(node);
|
||||
}
|
||||
|
||||
// These must be called from only one thread
|
||||
|
||||
void update() // must only be called from one thread
|
||||
{
|
||||
NodeStack reversed;
|
||||
Node *event, *node, *next;
|
||||
bool workDone = false;
|
||||
|
||||
// reverse the events so they are in order
|
||||
event = mPendingList.pop_all();
|
||||
while (event != NULL) {
|
||||
next = event->mNext;
|
||||
reversed.push_NA(event);
|
||||
event = next;
|
||||
workDone = true;
|
||||
}
|
||||
if (workDone) {
|
||||
//reversed.dump("pending popped");
|
||||
//mActiveList.dump("active before update");
|
||||
|
||||
// now process them
|
||||
while ((event = reversed.pop_NA()) != NULL) {
|
||||
switch (event->mEventType) {
|
||||
case kAdd:
|
||||
{
|
||||
Node **pnode;
|
||||
bool needToInsert = true;
|
||||
for (pnode = mActiveList.phead(); *pnode != NULL; pnode = &node->mNext) {
|
||||
node = *pnode;
|
||||
if (node->mObject == event->mObject) {
|
||||
//printf("already active!!!\n");
|
||||
FreeNode(event);
|
||||
needToInsert = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (needToInsert) {
|
||||
// link the new event in at the end of the active list
|
||||
*pnode = event;
|
||||
event->mNext = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kRemove:
|
||||
// find matching node in the active list, remove it
|
||||
for (Node **pnode = mActiveList.phead(); *pnode != NULL; ) {
|
||||
node = *pnode;
|
||||
if (node->mObject == event->mObject) {
|
||||
*pnode = node->mNext; // remove from linked list
|
||||
FreeNode(node);
|
||||
break;
|
||||
}
|
||||
pnode = &node->mNext;
|
||||
}
|
||||
// dispose the request node
|
||||
FreeNode(event);
|
||||
break;
|
||||
case kClear:
|
||||
for (node = mActiveList.head(); node != NULL; ) {
|
||||
next = node->mNext;
|
||||
FreeNode(node);
|
||||
node = next;
|
||||
}
|
||||
FreeNode(event);
|
||||
break;
|
||||
default:
|
||||
//printf("invalid node type %d!\n", event->mEventType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//mActiveList.dump("active after update");
|
||||
}
|
||||
}
|
||||
|
||||
iterator begin() const {
|
||||
//mActiveList.dump("active at begin");
|
||||
return iterator(mActiveList.head());
|
||||
}
|
||||
iterator end() const { return iterator(NULL); }
|
||||
|
||||
|
||||
private:
|
||||
Node * AllocNode()
|
||||
{
|
||||
Node *node = mFreeList.pop_atomic();
|
||||
if (node == NULL)
|
||||
node = (Node *)CA_malloc(sizeof(Node));
|
||||
return node;
|
||||
}
|
||||
|
||||
void FreeNode(Node *node)
|
||||
{
|
||||
mFreeList.push_atomic(node);
|
||||
}
|
||||
|
||||
private:
|
||||
class NodeStack : public TAtomicStack<Node> {
|
||||
public:
|
||||
void free_all() {
|
||||
Node *node;
|
||||
while ((node = this->pop_NA()) != NULL)
|
||||
free(node);
|
||||
}
|
||||
|
||||
Node ** phead() { return &this->mHead; }
|
||||
Node * head() const { return this->mHead; }
|
||||
};
|
||||
|
||||
NodeStack mActiveList; // what's actually in the container - only accessed on one thread
|
||||
NodeStack mPendingList; // add or remove requests - threadsafe
|
||||
NodeStack mFreeList; // free nodes for reuse - threadsafe
|
||||
};
|
||||
|
||||
#endif // __CAThreadSafeList_h__
|
@ -1,157 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#include "CAVectorUnit.h"
|
||||
|
||||
#if !TARGET_OS_WIN32
|
||||
#include <sys/sysctl.h>
|
||||
#elif HAS_IPP
|
||||
#include "ippdefs.h"
|
||||
#include "ippcore.h"
|
||||
#endif
|
||||
|
||||
int gCAVectorUnitType = kVecUninitialized;
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
// Use cpuid to check if SSE2 is available.
|
||||
// Before calling this function make sure cpuid is available
|
||||
static SInt32 IsSSE2Available()
|
||||
{
|
||||
int return_value;
|
||||
|
||||
{
|
||||
int r_edx;
|
||||
_asm
|
||||
{
|
||||
mov eax, 0x01
|
||||
cpuid
|
||||
mov r_edx, edx
|
||||
}
|
||||
return_value = (r_edx >> 26) & 0x1;
|
||||
}
|
||||
return return_value;
|
||||
}
|
||||
|
||||
// Use cpuid to check if SSE3 is available.
|
||||
// Before calling this function make sure cpuid is available
|
||||
static SInt32 IsSSE3Available()
|
||||
{
|
||||
SInt32 return_value;
|
||||
|
||||
{
|
||||
SInt32 r_ecx;
|
||||
_asm
|
||||
{
|
||||
mov eax, 0x01
|
||||
cpuid
|
||||
mov r_ecx, ecx
|
||||
}
|
||||
return_value = r_ecx & 0x1;
|
||||
}
|
||||
return return_value;
|
||||
}
|
||||
|
||||
// Return true if the cpuid instruction is available.
|
||||
// The cpuid instruction is available if bit 21 in the EFLAGS register can be changed
|
||||
// This function may not work on Intel CPUs prior to Pentium (didn't test)
|
||||
static bool IsCpuidAvailable()
|
||||
{
|
||||
SInt32 return_value = 0x0;
|
||||
_asm{
|
||||
pushfd ; //push original EFLAGS
|
||||
pop eax ; //get original EFLAGS
|
||||
mov ecx, eax ; //save original EFLAGS
|
||||
xor eax, 200000h ; //flip ID bit in EFLAGS
|
||||
push eax ; //save new EFLAGS value on stack
|
||||
popfd ; //replace current EFLAGS value
|
||||
pushfd ; //get new EFLAGS
|
||||
pop eax ; //store new EFLAGS in EAX
|
||||
xor eax, ecx ;
|
||||
je end_cpuid_identify ; //can't toggle ID bit
|
||||
mov return_value, 0x1;
|
||||
end_cpuid_identify:
|
||||
nop;
|
||||
}
|
||||
return return_value;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
SInt32 CAVectorUnit_Examine()
|
||||
{
|
||||
int result = kVecNone;
|
||||
|
||||
#if TARGET_OS_WIN32
|
||||
#if HAS_IPP
|
||||
// Initialize the static IPP library! This needs to be done before
|
||||
// any IPP function calls, otherwise we may have a performance penalty
|
||||
int status = ippStaticInit();
|
||||
if ( status == ippStsNonIntelCpu )
|
||||
{
|
||||
IppCpuType cpuType = ippGetCpuType();
|
||||
if ( cpuType >= ippCpuSSE || cpuType <= ippCpuSSE42 )
|
||||
ippStaticInitCpu( cpuType );
|
||||
}
|
||||
#endif
|
||||
{
|
||||
// On Windows we use cpuid to detect the vector unit because it works on Intel and AMD.
|
||||
// The IPP library does not detect SSE on AMD processors.
|
||||
if (IsCpuidAvailable())
|
||||
{
|
||||
if(IsSSE3Available())
|
||||
{
|
||||
result = kVecSSE3;
|
||||
}
|
||||
else if(IsSSE2Available())
|
||||
{
|
||||
result = kVecSSE2;
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif TARGET_OS_MAC
|
||||
#if DEBUG
|
||||
if (getenv("CA_NoVector")) {
|
||||
fprintf(stderr, "CA_NoVector set; Vector unit optimized routines will be bypassed\n");
|
||||
return result;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if (TARGET_CPU_PPC || TARGET_CPU_PPC64)
|
||||
int sels[2] = { CTL_HW, HW_VECTORUNIT };
|
||||
int vType = 0; //0 == scalar only
|
||||
size_t length = sizeof(vType);
|
||||
int error = sysctl(sels, 2, &vType, &length, NULL, 0);
|
||||
if (!error && vType > 0)
|
||||
result = kVecAltivec;
|
||||
#elif (TARGET_CPU_X86 || TARGET_CPU_X86_64)
|
||||
static const struct { const char* kName; const int kVectype; } kStringVectypes[] = {
|
||||
{ "hw.optional.avx1_0", kVecAVX1 }, { "hw.optional.sse3", kVecSSE3 }, { "hw.optional.sse2", kVecSSE2 }
|
||||
};
|
||||
static const size_t kNumStringVectypes = sizeof(kStringVectypes)/sizeof(kStringVectypes[0]);
|
||||
int i = 0, answer = 0;
|
||||
while(i != kNumStringVectypes)
|
||||
{
|
||||
size_t length = sizeof(answer);
|
||||
int error = sysctlbyname(kStringVectypes[i].kName, &answer, &length, NULL, 0);
|
||||
if (!error && answer)
|
||||
{
|
||||
result = kStringVectypes[i].kVectype;
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
};
|
||||
#elif CA_ARM_NEON
|
||||
result = kVecNeon;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
gCAVectorUnitType = result;
|
||||
return result;
|
||||
}
|
||||
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#ifndef __CAVectorUnit_h__
|
||||
#define __CAVectorUnit_h__
|
||||
|
||||
#include <TargetConditionals.h>
|
||||
#include "CAVectorUnitTypes.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreFoundation/CFBase.h>
|
||||
#else
|
||||
#include "CFBase.h"
|
||||
#endif
|
||||
|
||||
// Unify checks for vector units.
|
||||
// Allow setting an environment variable "CA_NoVector" to turn off vectorized code at runtime (very useful for performance testing).
|
||||
|
||||
extern int gCAVectorUnitType;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern SInt32 CAVectorUnit_Examine(); // expensive. use GetType() for lazy initialization and caching.
|
||||
|
||||
static inline SInt32 CAVectorUnit_GetType()
|
||||
{
|
||||
int x = gCAVectorUnitType;
|
||||
return (x != kVecUninitialized) ? x : CAVectorUnit_Examine();
|
||||
}
|
||||
|
||||
static inline Boolean CAVectorUnit_HasVectorUnit()
|
||||
{
|
||||
return CAVectorUnit_GetType() > kVecNone;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
class CAVectorUnit {
|
||||
public:
|
||||
static SInt32 GetVectorUnitType() { return CAVectorUnit_GetType(); }
|
||||
static bool HasVectorUnit() { return GetVectorUnitType() > kVecNone; }
|
||||
static bool HasAltivec() { return GetVectorUnitType() == kVecAltivec; }
|
||||
static bool HasSSE2() { return GetVectorUnitType() >= kVecSSE2; }
|
||||
static bool HasSSE3() { return GetVectorUnitType() >= kVecSSE3; }
|
||||
static bool HasAVX1() { return GetVectorUnitType() >= kVecAVX1; }
|
||||
static bool HasNeon() { return GetVectorUnitType() == kVecNeon; }
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // __CAVectorUnit_h__
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#ifndef __CAVectorUnitTypes_h__
|
||||
#define __CAVectorUnitTypes_h__
|
||||
|
||||
enum {
|
||||
kVecUninitialized = -1,
|
||||
kVecNone = 0,
|
||||
kVecAltivec = 1,
|
||||
kVecSSE2 = 100,
|
||||
kVecSSE3 = 101,
|
||||
kVecAVX1 = 110,
|
||||
kVecNeon = 200
|
||||
};
|
||||
|
||||
#endif
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
File: CAXException.cpp
|
||||
Abstract:
|
||||
Version: 1.2
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
||||
Inc. ("Apple") in consideration of your agreement to the following
|
||||
terms, and your use, installation, modification or redistribution of
|
||||
this Apple software constitutes acceptance of these terms. If you do
|
||||
not agree with these terms, please do not use, install, modify or
|
||||
redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, Apple grants you a personal, non-exclusive
|
||||
license, under Apple's copyrights in this original Apple software (the
|
||||
"Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||||
Software, with or without modifications, in source and/or binary forms;
|
||||
provided that if you redistribute the Apple Software in its entirety and
|
||||
without modifications, you must retain this notice and the following
|
||||
text and disclaimers in all such redistributions of the Apple Software.
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may
|
||||
be used to endorse or promote products derived from the Apple Software
|
||||
without specific prior written permission from Apple. Except as
|
||||
expressly stated in this notice, no other rights or licenses, express or
|
||||
implied, are granted by Apple herein, including but not limited to any
|
||||
patent rights that may be infringed by your derivative works or by other
|
||||
works in which the Apple Software may be incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
||||
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
||||
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
||||
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
||||
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
||||
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
||||
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2010 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
|
||||
#include "CAXException.h"
|
||||
|
||||
CAXException::WarningHandler CAXException::sWarningHandler = NULL;
|
@ -1,323 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Apple Inc. All Rights Reserved.
|
||||
See LICENSE.txt for this sample’s licensing information
|
||||
|
||||
Abstract:
|
||||
Part of Core Audio Public Utility Classes
|
||||
*/
|
||||
|
||||
#ifndef __CAXException_h__
|
||||
#define __CAXException_h__
|
||||
|
||||
#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#else
|
||||
#include <ConditionalMacros.h>
|
||||
#include <CoreFoundation.h>
|
||||
#endif
|
||||
#include "CADebugMacros.h"
|
||||
#include <ctype.h>
|
||||
//#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
class CAX4CCString {
|
||||
public:
|
||||
CAX4CCString(OSStatus error) {
|
||||
// see if it appears to be a 4-char-code
|
||||
UInt32 beErr = CFSwapInt32HostToBig(error);
|
||||
char *str = mStr;
|
||||
memcpy(str + 1, &beErr, 4);
|
||||
if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) {
|
||||
str[0] = str[5] = '\'';
|
||||
str[6] = '\0';
|
||||
} else if (error > -200000 && error < 200000)
|
||||
// no, format it as an integer
|
||||
snprintf(str, sizeof(mStr), "%d", (int)error);
|
||||
else
|
||||
snprintf(str, sizeof(mStr), "0x%x", (int)error);
|
||||
}
|
||||
const char *get() const { return mStr; }
|
||||
operator const char *() const { return mStr; }
|
||||
private:
|
||||
char mStr[16];
|
||||
};
|
||||
|
||||
class CAX4CCStringNoQuote {
|
||||
public:
|
||||
CAX4CCStringNoQuote(OSStatus error) {
|
||||
// see if it appears to be a 4-char-code
|
||||
UInt32 beErr = CFSwapInt32HostToBig(error);
|
||||
char *str = mStr;
|
||||
memcpy(str, &beErr, 4);
|
||||
if (isprint(str[0]) && isprint(str[1]) && isprint(str[2]) && isprint(str[3])) {
|
||||
str[4] = '\0';
|
||||
} else if (error > -200000 && error < 200000)
|
||||
// no, format it as an integer
|
||||
snprintf(str, sizeof(mStr), "%d", (int)error);
|
||||
else
|
||||
snprintf(str, sizeof(mStr), "0x%x", (int)error);
|
||||
}
|
||||
const char *get() const { return mStr; }
|
||||
operator const char *() const { return mStr; }
|
||||
private:
|
||||
char mStr[16];
|
||||
};
|
||||
|
||||
|
||||
// An extended exception class that includes the name of the failed operation
|
||||
class CAXException {
|
||||
public:
|
||||
CAXException(const char *operation, OSStatus err) :
|
||||
mError(err)
|
||||
{
|
||||
if (operation == NULL)
|
||||
mOperation[0] = '\0';
|
||||
else if (strlen(operation) >= sizeof(mOperation)) {
|
||||
memcpy(mOperation, operation, sizeof(mOperation) - 1);
|
||||
mOperation[sizeof(mOperation) - 1] = '\0';
|
||||
} else
|
||||
|
||||
strlcpy(mOperation, operation, sizeof(mOperation));
|
||||
}
|
||||
|
||||
char *FormatError(char *str, size_t strsize) const
|
||||
{
|
||||
return FormatError(str, strsize, mError);
|
||||
}
|
||||
|
||||
char mOperation[256];
|
||||
const OSStatus mError;
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
typedef void (*WarningHandler)(const char *msg, OSStatus err);
|
||||
|
||||
static char *FormatError(char *str, size_t strsize, OSStatus error)
|
||||
{
|
||||
strlcpy(str, CAX4CCString(error), strsize);
|
||||
return str;
|
||||
}
|
||||
|
||||
static void Warning(const char *s, OSStatus error)
|
||||
{
|
||||
if (sWarningHandler)
|
||||
(*sWarningHandler)(s, error);
|
||||
}
|
||||
|
||||
static void SetWarningHandler(WarningHandler f) { sWarningHandler = f; }
|
||||
private:
|
||||
static WarningHandler sWarningHandler;
|
||||
};
|
||||
|
||||
#if DEBUG || CoreAudio_Debug
|
||||
#define XThrowIfError(error, operation) \
|
||||
do { \
|
||||
OSStatus __err = error; \
|
||||
if (__err) { \
|
||||
DebugMessageN4("%s:%d: about to throw %s: %s", __FILE__, __LINE__, CAX4CCString(__err).get(), operation);\
|
||||
__THROW_STOP; \
|
||||
throw CAXException(operation, __err); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XThrowIf(condition, error, operation) \
|
||||
do { \
|
||||
if (condition) { \
|
||||
OSStatus __err = error; \
|
||||
DebugMessageN4("%s:%d: about to throw %s: %s", __FILE__, __LINE__, CAX4CCString(__err).get(), operation);\
|
||||
__THROW_STOP; \
|
||||
throw CAXException(operation, __err); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XRequireNoError(error, label) \
|
||||
do { \
|
||||
OSStatus __err = error; \
|
||||
if (__err) { \
|
||||
DebugMessageN4("%s:%d: about to throw %s: %s", __FILE__, __LINE__, CAX4CCString(__err).get(), #error);\
|
||||
STOP; \
|
||||
goto label; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XAssert(assertion) \
|
||||
do { \
|
||||
if (!(assertion)) { \
|
||||
DebugMessageN3("%s:%d: error: failed assertion: %s", __FILE__, __LINE__, #assertion); \
|
||||
__ASSERT_STOP; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XAssertNoError(error) \
|
||||
do { \
|
||||
OSStatus __err = error; \
|
||||
if (__err) { \
|
||||
DebugMessageN4("%s:%d: error %s: %s", __FILE__, __LINE__, CAX4CCString(__err).get(), #error);\
|
||||
__ASSERT_STOP; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ca_require_noerr(errorCode, exceptionLabel) \
|
||||
do \
|
||||
{ \
|
||||
int evalOnceErrorCode = (errorCode); \
|
||||
if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \
|
||||
{ \
|
||||
DebugMessageN5("ca_require_noerr: [%s, %d] (goto %s;) %s:%d", \
|
||||
#errorCode, evalOnceErrorCode, \
|
||||
#exceptionLabel, \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
goto exceptionLabel; \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define ca_verify_noerr(errorCode) \
|
||||
do \
|
||||
{ \
|
||||
int evalOnceErrorCode = (errorCode); \
|
||||
if ( __builtin_expect(0 != evalOnceErrorCode, 0) ) \
|
||||
{ \
|
||||
DebugMessageN4("ca_verify_noerr: [%s, %d] %s:%d", \
|
||||
#errorCode, evalOnceErrorCode, \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define ca_debug_string(message) \
|
||||
do \
|
||||
{ \
|
||||
DebugMessageN3("ca_debug_string: %s %s:%d", \
|
||||
message, \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
} while ( 0 )
|
||||
|
||||
|
||||
#define ca_verify(assertion) \
|
||||
do \
|
||||
{ \
|
||||
if ( __builtin_expect(!(assertion), 0) ) \
|
||||
{ \
|
||||
DebugMessageN3("ca_verify: %s %s:%d", \
|
||||
#assertion, \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define ca_require(assertion, exceptionLabel) \
|
||||
do \
|
||||
{ \
|
||||
if ( __builtin_expect(!(assertion), 0) ) \
|
||||
{ \
|
||||
DebugMessageN4("ca_require: %s %s %s:%d", \
|
||||
#assertion, \
|
||||
#exceptionLabel, \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
goto exceptionLabel; \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define ca_check(assertion) \
|
||||
do \
|
||||
{ \
|
||||
if ( __builtin_expect(!(assertion), 0) ) \
|
||||
{ \
|
||||
DebugMessageN3("ca_check: %s %s:%d", \
|
||||
#assertion, \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#else
|
||||
#define XThrowIfError(error, operation) \
|
||||
do { \
|
||||
OSStatus __err = error; \
|
||||
if (__err) { \
|
||||
throw CAXException(operation, __err); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XThrowIf(condition, error, operation) \
|
||||
do { \
|
||||
if (condition) { \
|
||||
OSStatus __err = error; \
|
||||
throw CAXException(operation, __err); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XRequireNoError(error, label) \
|
||||
do { \
|
||||
OSStatus __err = error; \
|
||||
if (__err) { \
|
||||
goto label; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XAssert(assertion) \
|
||||
do { \
|
||||
if (!(assertion)) { \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XAssertNoError(error) \
|
||||
do { \
|
||||
/*OSStatus __err =*/ error; \
|
||||
} while (0)
|
||||
|
||||
#define ca_require_noerr(errorCode, exceptionLabel) \
|
||||
do \
|
||||
{ \
|
||||
if ( __builtin_expect(0 != (errorCode), 0) ) \
|
||||
{ \
|
||||
goto exceptionLabel; \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define ca_verify_noerr(errorCode) \
|
||||
do \
|
||||
{ \
|
||||
if ( 0 != (errorCode) ) \
|
||||
{ \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define ca_debug_string(message)
|
||||
|
||||
#define ca_verify(assertion) \
|
||||
do \
|
||||
{ \
|
||||
if ( !(assertion) ) \
|
||||
{ \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define ca_require(assertion, exceptionLabel) \
|
||||
do \
|
||||
{ \
|
||||
if ( __builtin_expect(!(assertion), 0) ) \
|
||||
{ \
|
||||
goto exceptionLabel; \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define ca_check(assertion) \
|
||||
do \
|
||||
{ \
|
||||
if ( !(assertion) ) \
|
||||
{ \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#define XThrow(error, operation) XThrowIf(true, error, operation)
|
||||
#define XThrowIfErr(error) XThrowIfError(error, #error)
|
||||
|
||||
#endif // __CAXException_h__
|
Loading…
Reference in New Issue
Block a user