📄 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 + -