?? pa_mac.c
字號(hào):
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 );
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -