📄 pa_mac.c
字号:
static double * PaMac_GetSampleRatesFromHandle ( int numRates, Handle h )
{
OSErr err = noErr;
SInt8 hState;
int i;
UnsignedFixed *fixedRates;
double *rates = (double *) malloc( numRates * sizeof(double) ); /* MEM_011 */
if( rates == NULL ) return NULL;
/* Save and restore handle state as suggested by TechNote at:
http://developer.apple.com/technotes/tn/tn1122.html
*/
hState = HGetState (h);
if (!(err = MemError ()))
{
HLock (h);
if (!(err = MemError ( )))
{
fixedRates = (UInt32 *) *h;
for( i=0; i<numRates; i++ )
{
rates[i] = UnsignedFixedToDouble(fixedRates[i]);
}
HSetState (h,hState);
err = MemError ( );
}
}
if( err )
{
free( rates );
ERR_RPT(("Error in PaMac_GetSampleRatesFromHandle = %d\n", err ));
}
return rates;
}
/*************************************************************************/
int Pa_CountDevices()
{
PaError err;
DBUG(("Pa_CountDevices()\n"));
/* If no devices, go find some. */
if( sNumDevices <= 0 )
{
err = PaMac_ScanOutputDevices();
if( err != paNoError ) goto error;
err = PaMac_ScanInputDevices();
if( err != paNoError ) goto error;
}
return sNumDevices;
error:
PaHost_Term();
DBUG(("Pa_CountDevices: returns %d\n", err ));
return err;
}
/*************************************************************************/
const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
{
if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL;
return &sDevices[id].pad_Info;
}
/*************************************************************************/
PaDeviceID Pa_GetDefaultInputDeviceID( void )
{
return sDefaultInputDeviceID;
}
/*************************************************************************/
PaDeviceID Pa_GetDefaultOutputDeviceID( void )
{
return sDefaultOutputDeviceID;
}
/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
static void PaMac_StartLoadCalculation( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
UnsignedWide widePad;
if( pahsc == NULL ) return;
/* Query system timer for usage analysis and to prevent overuse of CPU. */
Microseconds( &widePad );
pahsc->pahsc_EntryCount = UnsignedWideToUInt64( widePad );
}
/******************************************************************************
** Measure fractional CPU load based on real-time it took to calculate
** buffers worth of output.
*/
/**************************************************************************/
static void PaMac_EndLoadCalculation( internalPortAudioStream *past )
{
UnsignedWide widePad;
UInt64 currentCount;
long usecsElapsed;
double newUsage;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return;
/* Measure CPU utilization during this callback. Note that this calculation
** assumes that we had the processor the whole time.
*/
#define LOWPASS_COEFFICIENT_0 (0.95)
#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
Microseconds( &widePad );
currentCount = UnsignedWideToUInt64( widePad );
usecsElapsed = (long) U64Subtract(currentCount, pahsc->pahsc_EntryCount);
/* Use inverse because it is faster than the divide. */
newUsage = usecsElapsed * pahsc->pahsc_InverseMicrosPerHostBuffer;
past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) +
(LOWPASS_COEFFICIENT_1 * newUsage);
}
/***********************************************************************
** Called by Pa_StartStream()
*/
PaError PaHost_StartInput( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
pahsc->pahsc_IsRecording = 0;
pahsc->pahsc_StopRecording = 0;
pahsc->pahsc_InputMultiBuffer.nextWrite = 0;
pahsc->pahsc_InputMultiBuffer.nextRead = 0;
return PaMac_RecordNext( past );
}
/***********************************************************************
** Called by Pa_StopStream().
** May be called during error recovery or cleanup code
** so protect against NULL pointers.
*/
PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
{
int32 timeOutMsec;
PaError result = paNoError;
OSErr err = 0;
long mRefNum;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paNoError;
(void) abort;
mRefNum = pahsc->pahsc_InputRefNum;
DBUG(("PaHost_StopInput: mRefNum = %d\n", mRefNum ));
if( mRefNum )
{
DBUG(("PaHost_StopInput: pahsc_IsRecording = %d\n", pahsc->pahsc_IsRecording ));
if( pahsc->pahsc_IsRecording )
{
/* PLB20010420 - Fix TIMEOUT in record mode. */
pahsc->pahsc_StopRecording = 1; /* Request that we stop recording. */
err = SPBStopRecording(mRefNum);
DBUG(("PaHost_StopInput: then pahsc_IsRecording = %d\n", pahsc->pahsc_IsRecording ));
/* Calculate timeOut longer than longest time it could take to play one buffer. */
timeOutMsec = (int32) ((1500.0 * pahsc->pahsc_FramesPerHostBuffer) / past->past_SampleRate);
/* Keep querying sound channel until it is no longer busy playing. */
while( !err && pahsc->pahsc_IsRecording && (timeOutMsec > 0))
{
Pa_Sleep(20);
timeOutMsec -= 20;
}
if( timeOutMsec <= 0 )
{
ERR_RPT(("PaHost_StopInput: timed out!\n"));
return paTimedOut;
}
}
}
if( err )
{
sPaHostError = err;
result = paHostError;
}
DBUG(("PaHost_StopInput: finished.\n", mRefNum ));
return result;
}
/***********************************************************************/
static void PaMac_InitSoundHeader( internalPortAudioStream *past, CmpSoundHeader *sndHeader )
{
sndHeader->numChannels = past->past_NumOutputChannels;
sndHeader->sampleRate = DoubleToUnsignedFixed(past->past_SampleRate);
sndHeader->loopStart = 0;
sndHeader->loopEnd = 0;
sndHeader->encode = cmpSH;
sndHeader->baseFrequency = kMiddleC;
sndHeader->markerChunk = nil;
sndHeader->futureUse2 = nil;
sndHeader->stateVars = nil;
sndHeader->leftOverSamples = nil;
sndHeader->compressionID = 0;
sndHeader->packetSize = 0;
sndHeader->snthID = 0;
sndHeader->sampleSize = 8 * sizeof(int16); // FIXME - might be 24 or 32 bits some day;
sndHeader->sampleArea[0] = 0;
sndHeader->format = kSoundNotCompressed;
}
static void SetFramesDone( PaHostSoundControl *pahsc, PaTimestamp framesDone )
{
UnsignedWide now;
Microseconds( &now );
pahsc->pahsc_NumFramesDone = framesDone;
pahsc->pahsc_WhenFramesDoneIncremented = UnsignedWideToUInt64( now );
}
/***********************************************************************/
PaError PaHost_StartOutput( internalPortAudioStream *past )
{
SndCommand pauseCommand;
SndCommand resumeCommand;
int i;
OSErr error;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paInternalError;
if( pahsc->pahsc_Channel == NULL ) return paInternalError;
past->past_StopSoon = 0;
past->past_IsActive = 1;
pahsc->pahsc_NumOutsQueued = 0;
pahsc->pahsc_NumOutsPlayed = 0;
SetFramesDone( pahsc, 0.0 );
/* Pause channel so it does not do back ground processing while we are still filling the queue. */
pauseCommand.cmd = pauseCmd;
pauseCommand.param1 = pauseCommand.param2 = 0;
error = SndDoCommand (pahsc->pahsc_Channel, &pauseCommand, true);
if (noErr != error) goto exit;
/* Queue all of the buffers so we start off full. */
for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
{
PaMac_PlayNext( past, i );
}
/* Resume channel now that the queue is full. */
resumeCommand.cmd = resumeCmd;
resumeCommand.param1 = resumeCommand.param2 = 0;
error = SndDoImmediate( pahsc->pahsc_Channel, &resumeCommand );
if (noErr != error) goto exit;
return paNoError;
exit:
past->past_IsActive = 0;
sPaHostError = error;
ERR_RPT(("Error in PaHost_StartOutput: SndDoCommand returned %d\n", error ));
return paHostError;
}
/*******************************************************************/
long PaHost_GetTotalBufferFrames( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
return (long) (pahsc->pahsc_NumHostBuffers * pahsc->pahsc_FramesPerHostBuffer);
}
/***********************************************************************
** Called by Pa_StopStream().
** May be called during error recovery or cleanup code
** so protect against NULL pointers.
*/
PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
{
int32 timeOutMsec;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paNoError;
if( pahsc->pahsc_Channel == NULL ) return paNoError;
DBUG(("PaHost_StopOutput()\n"));
if( past->past_IsActive == 0 ) return paNoError;
/* Set flags for callback function to see. */
if( abort ) past->past_StopNow = 1;
past->past_StopSoon = 1;
/* Calculate timeOut longer than longest time it could take to play all buffers. */
timeOutMsec = (int32) ((1500.0 * PaHost_GetTotalBufferFrames( past )) / past->past_SampleRate);
/* Keep querying sound channel until it is no longer busy playing. */
while( past->past_IsActive && (timeOutMsec > 0))
{
Pa_Sleep(20);
timeOutMsec -= 20;
}
if( timeOutMsec <= 0 )
{
ERR_RPT(("PaHost_StopOutput: timed out!\n"));
return paTimedOut;
}
else return paNoError;
}
/***********************************************************************/
PaError PaHost_StartEngine( internalPortAudioStream *past )
{
(void) past; /* Prevent unused variable warnings. */
return paNoError;
}
/***********************************************************************/
PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
{
(void) past; /* Prevent unused variable warnings. */
(void) abort; /* Prevent unused variable warnings. */
return paNoError;
}
/***********************************************************************/
PaError PaHost_StreamActive( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
return (PaError) ( past->past_IsActive + pahsc->pahsc_IsRecording );
}
int Mac_IsVirtualMemoryOn( void )
{
long attr;
OSErr result = Gestalt( gestaltVMAttr, &attr );
DBUG(("gestaltVMAttr : 0x%x\n", attr ));
return ((attr >> gestaltVMHasPagingControl ) & 1);
}
/*******************************************************************
* Determine number of host Buffers
* and how many User Buffers we can put into each host buffer.
*/
static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
int32 minNumBuffers;
int32 minFramesPerHostBuffer;
int32 minTotalFrames;
int32 userBuffersPerHostBuffer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -