📄 pa_mac.c
字号:
int32 framesPerHostBuffer;
int32 numHostBuffers;
minFramesPerHostBuffer = pahsc->pahsc_MinFramesPerHostBuffer;
minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7;
DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer ));
/* Determine number of user buffers based on minimum latency. */
/* PLB20020417 I used to call Pa_GetMinNumBuffers() which doesn't take into account the
** variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will
** gove lower latency when virtual memory is turned off. */
/* minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); WRONG */
minNumBuffers = PaMac_GetMinNumBuffers( minFramesPerHostBuffer, past->past_FramesPerUserBuffer, past->past_SampleRate );
past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers;
DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers ));
minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer;
/* We cannot make the buffers too small because they may not get serviced quickly enough. */
if( (int32) past->past_FramesPerUserBuffer < minFramesPerHostBuffer )
{
userBuffersPerHostBuffer =
(minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) /
past->past_FramesPerUserBuffer;
}
else
{
userBuffersPerHostBuffer = 1;
}
framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
/* Calculate number of host buffers needed. Round up to cover minTotalFrames. */
numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
/* Make sure we have enough host buffers. */
if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS)
{
numHostBuffers = PA_MIN_NUM_HOST_BUFFERS;
}
else
{
/* If we have too many host buffers, try to put more user buffers in a host buffer. */
while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS)
{
userBuffersPerHostBuffer += 1;
framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
}
}
pahsc->pahsc_UserBuffersPerHostBuffer = userBuffersPerHostBuffer;
pahsc->pahsc_FramesPerHostBuffer = framesPerHostBuffer;
pahsc->pahsc_NumHostBuffers = numHostBuffers;
DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer ));
DBUG(("PaHost_CalcNumHostBuffers: pahsc_NumHostBuffers = %d\n", pahsc->pahsc_NumHostBuffers ));
DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer ));
DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", past->past_NumUserBuffers ));
}
/*******************************************************************/
PaError PaHost_OpenStream( internalPortAudioStream *past )
{
OSErr err;
PaError result = paHostError;
PaHostSoundControl *pahsc;
int i;
/* Allocate and initialize host data. */
pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl));
if( pahsc == NULL )
{
return paInsufficientMemory;
}
past->past_DeviceData = (void *) pahsc;
/* If recording, and virtual memory is turned on, then use bigger buffers to prevent glitches. */
if( (past->past_NumInputChannels > 0) && Mac_IsVirtualMemoryOn() )
{
pahsc->pahsc_MinFramesPerHostBuffer = MAC_VIRTUAL_FRAMES_PER_BUFFER;
}
else
{
pahsc->pahsc_MinFramesPerHostBuffer = MAC_PHYSICAL_FRAMES_PER_BUFFER;
}
PaHost_CalcNumHostBuffers( past );
/* Setup constants for CPU load measurement. */
pahsc->pahsc_InverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * pahsc->pahsc_FramesPerHostBuffer);
/* ------------------ OUTPUT */
if( past->past_NumOutputChannels > 0 )
{
/* Create sound channel to which we can send commands. */
pahsc->pahsc_Channel = 0L;
err = SndNewChannel(&pahsc->pahsc_Channel, sampledSynth, 0, nil); /* FIXME - use kUseOptionalOutputDevice if not default. */
if(err != 0)
{
ERR_RPT(("Error in PaHost_OpenStream: SndNewChannel returned 0x%x\n", err ));
goto error;
}
/* Install our callback function pointer straight into the sound channel structure */
/* Use new CARBON name for callback procedure. */
#if TARGET_API_MAC_CARBON
pahsc->pahsc_OutputCompletionProc = NewSndCallBackUPP(PaMac_OutputCompletionProc);
#else
pahsc->pahsc_OutputCompletionProc = NewSndCallBackProc(PaMac_OutputCompletionProc);
#endif
pahsc->pahsc_Channel->callBack = pahsc->pahsc_OutputCompletionProc;
pahsc->pahsc_BytesPerOutputHostBuffer = pahsc->pahsc_FramesPerHostBuffer * past->past_NumOutputChannels * sizeof(int16);
for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
{
char *buf = (char *)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputHostBuffer);
if (buf == NULL)
{
ERR_RPT(("Error in PaHost_OpenStream: could not allocate output buffer. Size = \n", pahsc->pahsc_BytesPerOutputHostBuffer ));
goto memerror;
}
PaMac_InitSoundHeader( past, &pahsc->pahsc_SoundHeaders[i] );
pahsc->pahsc_SoundHeaders[i].samplePtr = buf;
pahsc->pahsc_SoundHeaders[i].numFrames = (unsigned long) pahsc->pahsc_FramesPerHostBuffer;
}
}
#ifdef SUPPORT_AUDIO_CAPTURE
/* ------------------ INPUT */
/* Use double buffer scheme that matches output. */
if( past->past_NumInputChannels > 0 )
{
int16 tempS;
long tempL;
Fixed tempF;
long mRefNum;
Str255 namePString;
#if TARGET_API_MAC_CARBON
pahsc->pahsc_InputCompletionProc = NewSICompletionUPP((SICompletionProcPtr)PaMac_InputCompletionProc);
#else
pahsc->pahsc_InputCompletionProc = NewSICompletionProc((ProcPtr)PaMac_InputCompletionProc);
#endif
pahsc->pahsc_BytesPerInputHostBuffer = pahsc->pahsc_FramesPerHostBuffer * past->past_NumInputChannels * sizeof(int16);
for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
{
char *buf = (char *) PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputHostBuffer);
if ( buf == NULL )
{
ERR_RPT(("PaHost_OpenStream: could not allocate input buffer. Size = \n", pahsc->pahsc_BytesPerInputHostBuffer ));
goto memerror;
}
pahsc->pahsc_InputMultiBuffer.buffers[i] = buf;
}
pahsc->pahsc_InputMultiBuffer.numBuffers = pahsc->pahsc_NumHostBuffers;
// err = SPBOpenDevice( (const unsigned char *) &noname, siWritePermission, &mRefNum);
CToPString((char *)sDevices[past->past_InputDeviceID].pad_Info.name, namePString);
err = SPBOpenDevice(namePString, siWritePermission, &mRefNum);
if (err) goto error;
pahsc->pahsc_InputRefNum = mRefNum;
DBUG(("PaHost_OpenStream: mRefNum = %d\n", mRefNum ));
/* Set input device characteristics. */
tempS = 1;
err = SPBSetDeviceInfo(mRefNum, siContinuous, (Ptr) &tempS);
if (err)
{
ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siContinuous returned %d\n", err ));
goto error;
}
tempL = 0x03;
err = SPBSetDeviceInfo(mRefNum, siActiveChannels, (Ptr) &tempL);
if (err)
{
DBUG(("PaHost_OpenStream: setting siActiveChannels returned 0x%x. Error ignored.\n", err ));
}
/* PLB20010908 - Use requested number of input channels. Thanks Dominic Mazzoni. */
tempS = past->past_NumInputChannels;
err = SPBSetDeviceInfo(mRefNum, siNumberChannels, (Ptr) &tempS);
if (err)
{
ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siNumberChannels returned %d\n", err ));
goto error;
}
tempF = ((unsigned long)past->past_SampleRate) << 16;
err = SPBSetDeviceInfo(mRefNum, siSampleRate, (Ptr) &tempF);
if (err)
{
ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siSampleRate returned %d\n", err ));
goto error;
}
/* Setup record-parameter block */
pahsc->pahsc_InputParams.inRefNum = mRefNum;
pahsc->pahsc_InputParams.milliseconds = 0; // not used
pahsc->pahsc_InputParams.completionRoutine = pahsc->pahsc_InputCompletionProc;
pahsc->pahsc_InputParams.interruptRoutine = 0;
pahsc->pahsc_InputParams.userLong = (long) past;
pahsc->pahsc_InputParams.unused1 = 0;
}
#endif /* SUPPORT_AUDIO_CAPTURE */
DBUG(("PaHost_OpenStream: complete.\n"));
return paNoError;
error:
PaHost_CloseStream( past );
ERR_RPT(("PaHost_OpenStream: sPaHostError = 0x%x.\n", err ));
sPaHostError = err;
return paHostError;
memerror:
PaHost_CloseStream( past );
return paInsufficientMemory;
}
/***********************************************************************
** Called by Pa_CloseStream().
** May be called during error recovery or cleanup code
** so protect against NULL pointers.
*/
PaError PaHost_CloseStream( internalPortAudioStream *past )
{
PaError result = paNoError;
OSErr err = 0;
int i;
PaHostSoundControl *pahsc;
DBUG(("PaHost_CloseStream( 0x%x )\n", past ));
if( past == NULL ) return paBadStreamPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paNoError;
if( past->past_NumOutputChannels > 0 )
{
/* TRUE means flush now instead of waiting for quietCmd to be processed. */
if( pahsc->pahsc_Channel != NULL ) SndDisposeChannel(pahsc->pahsc_Channel, TRUE);
{
for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
{
Ptr p = (Ptr) pahsc->pahsc_SoundHeaders[i].samplePtr;
if( p != NULL ) PaHost_FreeFastMemory( p, pahsc->pahsc_BytesPerOutputHostBuffer );
}
}
}
if( past->past_NumInputChannels > 0 )
{
if( pahsc->pahsc_InputRefNum )
{
err = SPBCloseDevice(pahsc->pahsc_InputRefNum);
pahsc->pahsc_InputRefNum = 0;
if( err )
{
sPaHostError = err;
result = paHostError;
}
}
{
for (i = 0; i<pahsc->pahsc_InputMultiBuffer.numBuffers; i++)
{
Ptr p = (Ptr) pahsc->pahsc_InputMultiBuffer.buffers[i];
if( p != NULL ) PaHost_FreeFastMemory( p, pahsc->pahsc_BytesPerInputHostBuffer );
}
}
}
past->past_DeviceData = NULL;
PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) );
DBUG(("PaHost_CloseStream: complete.\n", past ));
return result;
}
/*************************************************************************/
int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate )
{
/* We use the MAC_VIRTUAL_FRAMES_PER_BUFFER because we might be recording.
** This routine doesn't have enough information to determine the best value
** and is being depracated. */
return PaMac_GetMinNumBuffers( MAC_VIRTUAL_FRAMES_PER_BUFFER, framesPerUserBuffer, sampleRate );
}
/*************************************************************************/
static int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerUserBuffer, double sampleRate )
{
int minUserPerHost = ( minFramesPerHostBuffer + framesPerUserBuffer - 1) / framesPerUserBuffer;
int numBufs = PA_MIN_NUM_HOST_BUFFERS * minUserPerHost;
if( numBufs < PA_MIN_NUM_HOST_BUFFERS ) numBufs = PA_MIN_NUM_HOST_BUFFERS;
(void) sampleRate;
return numBufs;
}
/*************************************************************************/
void Pa_Sleep( int32 msec )
{
EventRecord event;
int32 sleepTime, endTime;
/* Convert to ticks. Round up so we sleep a MINIMUM of msec time. */
sleepTime = ((msec * 60) + 999) / 1000;
if( sleepTime < 1 ) sleepTime = 1;
endTime = TickCount() + sleepTime;
do
{
DBUGX(("Sleep for %d ticks.\n", sleepTime ));
/* Use WaitNextEvent() to sleep without getting events. */
/* PLB20010907 - Pass unused event to WaitNextEvent instead of NULL to prevent
* Mac OSX crash. Thanks Dominic Mazzoni. */
WaitNextEvent( 0, &event, sleepTime, NULL );
sleepTime = endTime - TickCount();
}
while( sleepTime > 0 );
}
/*************************************************************************/
int32 Pa_GetHostError( void )
{
int32 err = sPaHostError;
sPaHostError = 0;
return err;
}
/*************************************************************************
* Allocate memory that can be accessed in real-time.
* This may need to be held in physical memory so that it is not
* paged to virtual memory.
* This call MUST be balanced with a call to PaHost_FreeFastMemory().
*/
void *PaHost_AllocateFastMemory( long numBytes )
{
void *addr = NewPtrClear( numBytes );
if( (addr == NULL) || (MemError () != 0) ) return NULL;
#if (TARGET_API_MAC_CARBON == 0)
if( HoldMemory( addr, numBytes ) != noErr )
{
DisposePtr( (Ptr) addr );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -