📄 pa_mac.c
字号:
return NULL;
}
#endif
return addr;
}
/*************************************************************************
* Free memory that could be accessed in real-time.
* This call MUST be balanced with a call to PaHost_AllocateFastMemory().
*/
void PaHost_FreeFastMemory( void *addr, long numBytes )
{
if( addr == NULL ) return;
#if TARGET_API_MAC_CARBON
(void) numBytes;
#else
UnholdMemory( addr, numBytes );
#endif
DisposePtr( (Ptr) addr );
}
/*************************************************************************/
PaTimestamp Pa_StreamTime( PortAudioStream *stream )
{
PaTimestamp framesDone1;
PaTimestamp framesDone2;
UInt64 whenIncremented;
UnsignedWide now;
UInt64 now64;
long microsElapsed;
long framesElapsed;
PaHostSoundControl *pahsc;
internalPortAudioStream *past = (internalPortAudioStream *) stream;
if( past == NULL ) return paBadStreamPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
/* Capture information from audio thread.
* We have to be careful that we don't get interrupted in the middle.
* So we grab the pahsc_NumFramesDone twice and make sure it didn't change.
*/
do
{
framesDone1 = pahsc->pahsc_NumFramesDone;
whenIncremented = pahsc->pahsc_WhenFramesDoneIncremented;
framesDone2 = pahsc->pahsc_NumFramesDone;
} while( framesDone1 != framesDone2 );
/* Calculate how many microseconds have elapsed and convert to frames. */
Microseconds( &now );
now64 = UnsignedWideToUInt64( now );
microsElapsed = U64Subtract( now64, whenIncremented );
framesElapsed = microsElapsed * past->past_SampleRate * 0.000001;
return framesDone1 + framesElapsed;
}
/**************************************************************************
** Callback for Input, SPBRecord()
*/
int gRecordCounter = 0;
int gPlayCounter = 0;
pascal void PaMac_InputCompletionProc(SPBPtr recParams)
{
PaError result = paNoError;
int finished = 1;
internalPortAudioStream *past;
PaHostSoundControl *pahsc;
gRecordCounter += 1; /* debug hack to see if engine running */
/* Get our PA data from Mac structure. */
past = (internalPortAudioStream *) recParams->userLong;
if( past == NULL ) return;
if( past->past_Magic != PA_MAGIC )
{
AddTraceMessage("PaMac_InputCompletionProc: bad MAGIC, past", (long) past );
AddTraceMessage("PaMac_InputCompletionProc: bad MAGIC, magic", (long) past->past_Magic );
goto error;
}
pahsc = (PaHostSoundControl *) past->past_DeviceData;
past->past_NumCallbacks += 1;
/* Have we been asked to stop recording? */
if( (recParams->error == abortErr) || pahsc->pahsc_StopRecording ) goto error;
/* If there are no output channels, then we need to call the user callback function from here.
* Otherwise we will call the user code during the output completion routine.
*/
if(past->past_NumOutputChannels == 0)
{
SetFramesDone( pahsc,
pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer );
result = PaMac_CallUserLoop( past, NULL );
}
/* Did user code ask us to stop? If not, issue another recording request. */
if( (result == paNoError) && (pahsc->pahsc_StopRecording == 0) )
{
result = PaMac_RecordNext( past );
if( result != paNoError ) pahsc->pahsc_IsRecording = 0;
}
else goto error;
return;
error:
pahsc->pahsc_IsRecording = 0;
pahsc->pahsc_StopRecording = 0;
return;
}
/***********************************************************************
** Called by either input or output completion proc.
** Grabs input data if any present, and calls PA conversion code,
** that in turn calls user code.
*/
static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPtr )
{
PaError result = paNoError;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
int16 *inPtr = NULL;
int i;
/* Advance read index for sound input FIFO here, independantly of record/write process. */
if(past->past_NumInputChannels > 0)
{
if( MultiBuffer_IsReadable( &pahsc->pahsc_InputMultiBuffer ) )
{
inPtr = (int16 *) MultiBuffer_GetNextReadBuffer( &pahsc->pahsc_InputMultiBuffer );
MultiBuffer_AdvanceReadIndex( &pahsc->pahsc_InputMultiBuffer );
}
}
/* Call user code enough times to fill buffer. */
if( (inPtr != NULL) || (outPtr != NULL) )
{
PaMac_StartLoadCalculation( past ); /* CPU usage */
#ifdef PA_MAX_USAGE_ALLOWED
/* If CPU usage exceeds limit, skip user callback to prevent hanging CPU. */
if( past->past_Usage > PA_MAX_USAGE_ALLOWED )
{
past->past_FrameCount += (PaTimestamp) pahsc->pahsc_FramesPerHostBuffer;
}
else
#endif
{
for( i=0; i<pahsc->pahsc_UserBuffersPerHostBuffer; i++ )
{
result = (PaError) Pa_CallConvertInt16( past, inPtr, outPtr );
if( result != 0)
{
/* Recording might be in another process, so tell it to stop with a flag. */
pahsc->pahsc_StopRecording = pahsc->pahsc_IsRecording;
break;
}
/* Advance sample pointers. */
if(inPtr != NULL) inPtr += past->past_FramesPerUserBuffer * past->past_NumInputChannels;
if(outPtr != NULL) outPtr += past->past_FramesPerUserBuffer * past->past_NumOutputChannels;
}
}
PaMac_EndLoadCalculation( past );
}
return result;
}
/***********************************************************************
** Setup next recording buffer in FIFO and issue recording request to Snd Input Manager.
*/
static PaError PaMac_RecordNext( internalPortAudioStream *past )
{
PaError result = paNoError;
OSErr err;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
/* Get pointer to next buffer to record into. */
pahsc->pahsc_InputParams.bufferPtr = MultiBuffer_GetNextWriteBuffer( &pahsc->pahsc_InputMultiBuffer );
/* Advance write index if there is room. Otherwise keep writing same buffer. */
if( MultiBuffer_IsWriteable( &pahsc->pahsc_InputMultiBuffer ) )
{
MultiBuffer_AdvanceWriteIndex( &pahsc->pahsc_InputMultiBuffer );
}
AddTraceMessage("PaMac_RecordNext: bufferPtr", (long) pahsc->pahsc_InputParams.bufferPtr );
AddTraceMessage("PaMac_RecordNext: nextWrite", pahsc->pahsc_InputMultiBuffer.nextWrite );
/* Setup parameters and issue an asynchronous recording request. */
pahsc->pahsc_InputParams.bufferLength = pahsc->pahsc_BytesPerInputHostBuffer;
pahsc->pahsc_InputParams.count = pahsc->pahsc_BytesPerInputHostBuffer;
err = SPBRecord(&pahsc->pahsc_InputParams, true);
if( err )
{
AddTraceMessage("PaMac_RecordNext: SPBRecord error ", err );
sPaHostError = err;
result = paHostError;
}
else
{
pahsc->pahsc_IsRecording = 1;
}
return result;
}
/**************************************************************************
** Callback for Output Playback()
** Return negative error, 0 to continue, 1 to stop.
*/
long PaMac_FillNextOutputBuffer( internalPortAudioStream *past, int index )
{
PaHostSoundControl *pahsc;
long result = 0;
int finished = 1;
char *outPtr;
gPlayCounter += 1; /* debug hack */
past->past_NumCallbacks += 1;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return -1;
/* Are we nested?! */
if( pahsc->pahsc_IfInsideCallback ) return 0;
pahsc->pahsc_IfInsideCallback = 1;
/* Get pointer to buffer to fill. */
outPtr = pahsc->pahsc_SoundHeaders[index].samplePtr;
/* Combine with any sound input, and call user callback. */
result = PaMac_CallUserLoop( past, (int16 *) outPtr );
pahsc->pahsc_IfInsideCallback = 0;
return result;
}
/*************************************************************************************
** Called by SoundManager when ready for another buffer.
*/
static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndCommand * theCallBackCmd)
{
internalPortAudioStream *past;
PaHostSoundControl *pahsc;
(void) theChannel;
(void) theCallBackCmd;
/* Get our data from Mac structure. */
past = (internalPortAudioStream *) theCallBackCmd->param2;
if( past == NULL ) return;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
pahsc->pahsc_NumOutsPlayed += 1;
SetFramesDone( pahsc,
pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer );
PaMac_BackgroundManager( past, theCallBackCmd->param1 );
}
/*******************************************************************/
static PaError PaMac_BackgroundManager( internalPortAudioStream *past, int index )
{
PaError result = paNoError;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
/* Has someone asked us to abort by calling Pa_AbortStream()? */
if( past->past_StopNow )
{
SndCommand command;
/* Clear the queue of any pending commands. */
command.cmd = flushCmd;
command.param1 = command.param2 = 0;
SndDoImmediate( pahsc->pahsc_Channel, &command );
/* Then stop currently playing buffer, if any. */
command.cmd = quietCmd;
SndDoImmediate( pahsc->pahsc_Channel, &command );
past->past_IsActive = 0;
}
/* Has someone asked us to stop by calling Pa_StopStream()
* OR has a user callback returned '1' to indicate finished.
*/
else if( past->past_StopSoon )
{
if( (pahsc->pahsc_NumOutsQueued - pahsc->pahsc_NumOutsPlayed) <= 0 )
{
past->past_IsActive = 0; /* We're finally done. */
}
}
else
{
PaMac_PlayNext( past, index );
}
return result;
}
/*************************************************************************************
** Fill next buffer with sound and queue it for playback.
*/
static void PaMac_PlayNext ( internalPortAudioStream *past, int index )
{
OSErr error;
long result;
SndCommand playCmd;
SndCommand callbackCmd;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
/* If this was the last buffer, or abort requested, then just be done. */
if ( past->past_StopSoon ) goto done;
/* Load buffer with sound. */
result = PaMac_FillNextOutputBuffer ( past, index );
if( result > 0 ) past->past_StopSoon = 1; /* Stop generating audio but wait until buffers play. */
else if( result < 0 ) goto done;
/* Play the next buffer. */
playCmd.cmd = bufferCmd;
playCmd.param1 = 0;
playCmd.param2 = (long) &pahsc->pahsc_SoundHeaders[ index ];
error = SndDoCommand (pahsc->pahsc_Channel, &playCmd, true );
if( error != noErr ) goto gotError;
/* Ask for a callback when it is done. */
callbackCmd.cmd = callBackCmd;
callbackCmd.param1 = index;
callbackCmd.param2 = (long)past;
error = SndDoCommand (pahsc->pahsc_Channel, &callbackCmd, true );
if( error != noErr ) goto gotError;
pahsc->pahsc_NumOutsQueued += 1;
return;
gotError:
sPaHostError = error;
done:
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -