⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pa_mac_core.c

📁 一个任天堂掌上游戏机NDS的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:

/*************************************************************************
** Try to fill in the device info for this device.
** Return 1 if a good device that PA can use.
** Return 0 if not appropriate
** or return negative error.
**
*/
static int PaOSX_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput )
{
    OSStatus         err;
    UInt32           outSize;
    AudioStreamBasicDescription formatDesc;
    AudioDeviceID    devID;
    PaDeviceInfo    *deviceInfo = &hostDeviceInfo->paInfo;
    int              maxChannels;

    deviceInfo->structVersion = 1;
    deviceInfo->maxInputChannels = 0;
    deviceInfo->maxOutputChannels = 0;

    deviceInfo->sampleRates = supportedSampleRateRange; // because we use sample rate converter to get continuous rates
    deviceInfo->numSampleRates = -1;

    devID = sCoreDeviceIDs[ coreDeviceIndex ];
    hostDeviceInfo->audioDeviceID = devID;
    DBUG(("PaOSX_QueryDeviceInfo: coreDeviceIndex = %d, devID = %d, isInput = %d\n",
        coreDeviceIndex, (int) devID, isInput ));
        
    // Get data format info from the device.
    outSize = sizeof(formatDesc);
    err = AudioDeviceGetProperty(devID, 0, isInput, kAudioDevicePropertyStreamFormat, &outSize, &formatDesc);
    // This just may not be an appropriate device for input or output so leave quietly.
    if( (err != noErr)  || (formatDesc.mChannelsPerFrame == 0) ) goto error;
    
    DBUG(("PaOSX_QueryDeviceInfo: mFormatID = 0x%x\n", (unsigned int) formatDesc.mFormatID));
    DBUG(("PaOSX_QueryDeviceInfo: mFormatFlags = 0x%x\n",(unsigned int)  formatDesc.mFormatFlags));

    // Right now the Core Audio headers only define one formatID: LinearPCM
    // Apparently LinearPCM must be Float32 for now.
    if( (formatDesc.mFormatID == kAudioFormatLinearPCM) &&
        ((formatDesc.mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0) )
    {
        deviceInfo->nativeSampleFormats = paFloat32;
    }
    else
    {
        PRINT(("PaOSX_QueryDeviceInfo: ERROR - not LinearPCM & Float32!!!\n"));
        return paSampleFormatNotSupported;
    }
    
    maxChannels = PaOSX_GetMaxChannels( devID, isInput );
    if( maxChannels <= 0 ) goto error;
    if( isInput )
    {
        deviceInfo->maxInputChannels = maxChannels;
    }
    else
    {
        deviceInfo->maxOutputChannels = maxChannels;
    }
    
    // Get the device name
    deviceInfo->name = PaOSX_DeviceNameFromID( devID, isInput );
    DBUG(("PaOSX_QueryDeviceInfo: name = %s\n", deviceInfo->name ));
    return 1;

error:
    return 0;
}

/**********************************************************************/
static PaError PaOSX_MaybeQueryDevices( void )
{
    if( sNumPaDevices == 0 )
    {
        return PaOSX_QueryDevices();
    }
    return 0;
}

static char zeroPad[256] = { 0 };

/**********************************************************************
** This is the proc that supplies the data to the AudioConverterFillBuffer call.
** We can pass back arbitrarily sized blocks so if the FIFO region is split
** just pass back the first half.
*/
static OSStatus PaOSX_InputConverterCallbackProc (AudioConverterRef			inAudioConverter,
								UInt32*						outDataSize,
								void**						outData,
								void*						inUserData)
{
    internalPortAudioStream   *past = (internalPortAudioStream *) inUserData;
    PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
    void *dataPtr1;
    long size1;
    void *dataPtr2;
    long size2;
           
    /* Pass contiguous region from FIFO directly to converter. */
    RingBuffer_GetReadRegions( &pahsc->ringBuffer, *outDataSize,
            &dataPtr1, &size1, &dataPtr2, &size2 );

    if( size1 > 0 )
    {
        *outData = dataPtr1;
        *outDataSize = size1;
        RingBuffer_AdvanceReadIndex( &pahsc->ringBuffer, size1 );
        DBUGX(("PaOSX_InputConverterCallbackProc: read %ld bytes from FIFO.\n", size1 ));
    }
    else
    {
        DBUGBACK(("PaOSX_InputConverterCallbackProc: got no data!\n"));
        *outData = zeroPad; /* Give it zero data to keep it happy. */
        *outDataSize = sizeof(zeroPad);
    }
	return noErr;
}

/*****************************************************************************
** Get audio input, if any, from passed in buffer, or from converter or from FIFO,
** then run PA callback and output data.
*/
static OSStatus PaOSX_LoadAndProcess( internalPortAudioStream   *past,
    void *inputBuffer, void *outputBuffer )
{
    OSStatus err = noErr;
    PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
    
    if( past->past_StopSoon )
    {
        if( outputBuffer )
        {
            /* Clear remainder of audio buffer if we are waiting for stop. */
            AddTraceMessage("PaOSX_LoadAndProcess: zero rest of wave buffer ", i );
            memset( outputBuffer, 0, pahsc->output.bytesPerUserNativeBuffer );
        }
    }
    else
    {
        /* Do we need data from the converted input? */
        if( PA_USING_INPUT )
        {
            UInt32 size = pahsc->input.bytesPerUserNativeBuffer;
            err = AudioConverterFillBuffer(
                pahsc->input.converter,
                PaOSX_InputConverterCallbackProc,
                past,
                &size,
                pahsc->input.converterBuffer);
            if( err != noErr ) return err;
            inputBuffer = pahsc->input.converterBuffer;
        }
        
        /* Measure CPU load. */
#if PA_ENABLE_LOAD_MEASUREMENT
        Pa_StartUsageCalculation( past );
#endif

        /* Fill part of audio converter buffer by converting input to user format,
        * calling user callback, then converting output to native format. */
        if( PaConvert_Process( past, inputBuffer, outputBuffer ))
        {
            past->past_StopSoon = 1;
        }
        
#if PA_ENABLE_LOAD_MEASUREMENT
        Pa_EndUsageCalculation( past );
#endif

    }
    return err;
}

/*****************************************************************************
** This is the proc that supplies the data to the AudioConverterFillBuffer call
*/
static OSStatus PaOSX_OutputConverterCallbackProc (AudioConverterRef			inAudioConverter,
								UInt32*						outDataSize,
								void**						outData,
								void*						inUserData)
{
    internalPortAudioStream   *past = (internalPortAudioStream *) inUserData;
    PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
    
	*outData = pahsc->output.converterBuffer;
	*outDataSize = pahsc->output.bytesPerUserNativeBuffer;
    
	return PaOSX_LoadAndProcess ( past, pahsc->input.converterBuffer, pahsc->output.converterBuffer );
}

/**********************************************************************
** If data available, write it to the Ring Buffer so we can
** pull it from the other side.
*/
static OSStatus PaOSX_WriteInputRingBuffer( internalPortAudioStream   *past,
        const AudioBufferList*  inInputData  )
{
    int   numBytes = 0;
    int   currentInterleavedChannelIndex;
    int   numFramesInInputBuffer;
    int   numInterleavedChannels;
    int   numChannelsRemaining;
	int   i;
    long  writeRoom;
    char *inputNativeBufferfPtr = NULL;
    PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;

    /* Do we need to deinterleave the buffers first? */
    if( past->past_NumInputChannels != inInputData->mBuffers[0].mNumberChannels )
    {
		numFramesInInputBuffer = inInputData->mBuffers[0].mDataByteSize /
            (sizeof(float) * inInputData->mBuffers[0].mNumberChannels);
		
		numBytes = numFramesInInputBuffer * sizeof(float) * past->past_NumInputChannels;
	
		/* Allocate temporary buffer if needed. */
		if ( (pahsc->input.streamInterleavingBuffer != NULL) &&
			 (pahsc->input.streamInterleavingBufferLen < numBytes) )
		{
			PaHost_FreeFastMemory( pahsc->input.streamInterleavingBuffer, pahsc->input.streamInterleavingBufferLen );
			pahsc->input.streamInterleavingBuffer = NULL;
		}
		if ( pahsc->input.streamInterleavingBuffer == NULL )
		{
			pahsc->input.streamInterleavingBufferLen = numBytes;
			pahsc->input.streamInterleavingBuffer = (float *)PaHost_AllocateFastMemory( pahsc->input.streamInterleavingBufferLen );
		}
	
		/* Perform interleaving by writing to temp buffer. */
		currentInterleavedChannelIndex = 0;
		numInterleavedChannels = past->past_NumInputChannels;
		numChannelsRemaining = numInterleavedChannels;
		
		for( i=0; i<inInputData->mNumberBuffers; i++ )
		{
			int j;
			int numBufChannels = inInputData->mBuffers[i].mNumberChannels;
			/* Don't use more than we need or more than we have. */
			int numChannelsUsedInThisBuffer = (numChannelsRemaining < numBufChannels ) ?
				  numChannelsRemaining : numBufChannels;
			for( j=0; j<numChannelsUsedInThisBuffer; j++ )
			{
				int k;
                float *dest = &pahsc->input.streamInterleavingBuffer[ currentInterleavedChannelIndex ];
                float *src = &((float *)inInputData->mBuffers[i].mData)[ j ];
				/* Move one channel from CoreAudio buffer to interleaved buffer. */
				for( k=0; k<numFramesInInputBuffer; k++ )
				{
					*dest = *src;
                    src += numBufChannels;
                    dest += numInterleavedChannels;
				}
				currentInterleavedChannelIndex++;
			}
			numChannelsRemaining -= numChannelsUsedInThisBuffer;
			if( numChannelsRemaining <= 0 ) break;
		}

        inputNativeBufferfPtr = (char *)pahsc->input.streamInterleavingBuffer;
    }
    else
    {
        inputNativeBufferfPtr = (char*)inInputData->mBuffers[0].mData;
        numBytes = inInputData->mBuffers[0].mDataByteSize;
    }

    writeRoom = RingBuffer_GetWriteAvailable( &pahsc->ringBuffer );
    
    if( numBytes <= writeRoom )
    {
        RingBuffer_Write(  &pahsc->ringBuffer, inputNativeBufferfPtr, numBytes );
        DBUGBACK(("PaOSX_WriteInputRingBuffer: wrote %ld bytes to FIFO.\n", numBytes));
    } // FIXME else drop samples on floor, remember overflow???            

    return noErr;
}

/**********************************************************************
** Use any available input buffers by writing to RingBuffer.
** Process input if PA_MODE_INPUT_ONLY.
*/
static OSStatus PaOSX_HandleInput( internalPortAudioStream   *past,
        const AudioBufferList*  inInputData )
{
    OSStatus            err = noErr;
    PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;

    if( inInputData == NULL )
    {
        DBUG(("PaOSX_HandleInput: inInputData == NULL\n"));
        return noErr;
    }
    
    if(  inInputData->mNumberBuffers > 0  )
    {    
        /* Write to FIFO here if we are only using this callback. */
        if( (pahsc->mode == PA_MODE_INPUT_ONLY) || (pahsc->mode == PA_MODE_IO_ONE_DEVICE) )
        {
            err = PaOSX_WriteInputRingBuffer( past, inInputData  );
            if( err != noErr ) goto error;
        }
    }
    
    if( pahsc->mode == PA_MODE_INPUT_ONLY )
    {
        /* Generate user buffers as long as we have a half full input FIFO. */
        long halfSize = pahsc->ringBuffer.bufferSize / 2;
        while( (RingBuffer_GetReadAvailable( &pahsc->ringBuffer ) >= halfSize) &&
            (past->past_StopSoon == 0) )
        {
            err = PaOSX_LoadAndProcess ( past, NULL, NULL );
            if( err != noErr ) goto error;
        }
    }
        
error:
    return err;
}

/**********************************************************************
** Fill any available output buffers.
*/
static OSStatus PaOSX_HandleOutput( internalPortAudioStream   *past,
            AudioBufferList*  outOutputData )
{
    OSStatus            err = noErr;
    void               *outputNativeBufferfPtr = NULL;
    PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
    UInt32              numBytes = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -