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

📄 pa_mac_core.c

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

}

#if 0
static void PaOSX_DumpDeviceInfo( AudioDeviceID devID, Boolean isInput )
{
    OSStatus err = noErr;
    UInt32    dataSize;
    UInt32    uidata32;
    Float32   fdata32;
    AudioValueRange audioRange;
    
    dataSize = sizeof( uidata32 );
    err = AudioDeviceGetProperty( devID, 0, isInput, 
        kAudioDevicePropertyLatency, &dataSize, &uidata32 );
    if( err != noErr )
    {
        PRINT_ERR("Error reading kAudioDevicePropertyLatency", err);
        return;
    }
    PRINT(("kAudioDevicePropertyLatency = %d\n", (int)uidata32 ));
    
    dataSize = sizeof( fdata32 );
    err = AudioDeviceGetProperty( devID, 1, isInput, 
        kAudioDevicePropertyVolumeScalar, &dataSize, &fdata32 );
    if( err != noErr )
    {
        PRINT_ERR("Error reading kAudioDevicePropertyVolumeScalar", err);
        return;
    }
    PRINT(("kAudioDevicePropertyVolumeScalar = %f\n", fdata32 ));
    
    dataSize = sizeof( uidata32 );
    err = AudioDeviceGetProperty( devID, 0, isInput, 
        kAudioDevicePropertyBufferSize, &dataSize, &uidata32 );
    if( err != noErr )
    {
        PRINT_ERR("Error reading buffer size", err);
        return;
    }
    PRINT(("kAudioDevicePropertyBufferSize = %d bytes\n", (int)uidata32 ));

    dataSize = sizeof( audioRange );
    err = AudioDeviceGetProperty( devID, 0, isInput, 
        kAudioDevicePropertyBufferSizeRange, &dataSize, &audioRange );
    if( err != noErr )
    {
        PRINT_ERR("Error reading buffer size range", err);
        return;
    }
    PRINT(("kAudioDevicePropertyBufferSizeRange = %g to %g bytes\n", audioRange.mMinimum, audioRange.mMaximum ));
    
    dataSize = sizeof( uidata32 );
    err = AudioDeviceGetProperty( devID, 0, isInput, 
        kAudioDevicePropertyBufferFrameSize, &dataSize, &uidata32 );
    if( err != noErr )
    {
        PRINT_ERR("Error reading buffer size", err);
        return;
    }
    PRINT(("kAudioDevicePropertyBufferFrameSize = %d frames\n", (int)uidata32 ));
    
    dataSize = sizeof( audioRange );
    err = AudioDeviceGetProperty( devID, 0, isInput, 
        kAudioDevicePropertyBufferFrameSizeRange, &dataSize, &audioRange );
    if( err != noErr )
    {
        PRINT_ERR("Error reading buffer size range", err);
        return;
    }
    PRINT(("kAudioDevicePropertyBufferFrameSizeRange = %g to %g frames\n", audioRange.mMinimum, audioRange.mMaximum ));

    return;
}
#endif

/*******************************************************************/
static OSStatus PAOSX_DevicePropertyListener (AudioDeviceID					inDevice,
								UInt32							inChannel,
								Boolean							isInput,
								AudioDevicePropertyID			inPropertyID,
								void*							inClientData)
{
    PaHostSoundControl       *pahsc;
    internalPortAudioStream  *past;
    UInt32                    dataSize;
    OSStatus                  err = noErr;
	AudioStreamBasicDescription userStreamFormat, hardwareStreamFormat;
    PaHostInOut              *hostInOut;
	AudioStreamBasicDescription *destFormatPtr, *srcFormatPtr;

    past = (internalPortAudioStream *) inClientData;
    pahsc = (PaHostSoundControl *) past->past_DeviceData;

    DBUG(("PAOSX_DevicePropertyListener: called with propertyID = 0x%0X\n", (unsigned int) inPropertyID ));

    if(inPropertyID == kAudioDevicePropertyStreamFormat)
    {    
        /* Get target device format */
        dataSize = sizeof(hardwareStreamFormat);
        err = AudioDeviceGetProperty(inDevice, 0, isInput,
            kAudioDevicePropertyStreamFormat, &dataSize, &hardwareStreamFormat);
        if( err != noErr )
        {
            PRINT_ERR("PAOSX_DevicePropertyListener: Could not get device format", err);
            sSavedHostError = err;
            goto error;
        }

        DBUG(("PAOSX_DevicePropertyListener: HW mChannelsPerFrame = %d\n", (int)hardwareStreamFormat.mChannelsPerFrame ));
        
        /* Set source user format. */
        userStreamFormat = hardwareStreamFormat;
        userStreamFormat.mSampleRate = past->past_SampleRate;	// sample rate of the user synthesis code
        userStreamFormat.mChannelsPerFrame = (isInput) ? past->past_NumInputChannels : past->past_NumOutputChannels;	//	the number of channels in each frame
        DBUG(("PAOSX_DevicePropertyListener: User mChannelsPerFrame = %d\n", (int)userStreamFormat.mChannelsPerFrame ));
    
        userStreamFormat.mBytesPerFrame = userStreamFormat.mChannelsPerFrame * sizeof(float);
        userStreamFormat.mBytesPerPacket = userStreamFormat.mBytesPerFrame * userStreamFormat.mFramesPerPacket;
    
    	/* Don't use AudioConverter for merging or splitting channels. */
        hardwareStreamFormat.mChannelsPerFrame = userStreamFormat.mChannelsPerFrame;
        hardwareStreamFormat.mBytesPerFrame = userStreamFormat.mBytesPerFrame;
        hardwareStreamFormat.mBytesPerPacket = userStreamFormat.mBytesPerPacket;
    	        
        if( isInput )
        {
            hostInOut = &pahsc->input;
            srcFormatPtr = &hardwareStreamFormat;
            destFormatPtr = &userStreamFormat;
        }
        else
        {
            hostInOut = &pahsc->output;
            srcFormatPtr = &userStreamFormat;
            destFormatPtr = &hardwareStreamFormat;
        }
        DBUG(("PAOSX_DevicePropertyListener: source rate = %f\n", srcFormatPtr->mSampleRate ));
        DBUG(("PAOSX_DevicePropertyListener: dest rate = %f\n", destFormatPtr->mSampleRate ));
        
        // Don't delete old converter until we create new one so we don't pull
        // the rug out from under other audio threads.
        AudioConverterRef oldConverter = hostInOut->converter;
        
        // Make converter to change sample rate.
        err = AudioConverterNew (
            srcFormatPtr, 
            destFormatPtr, 
            &hostInOut->converter );
        if( err != noErr )
        {
            PRINT_ERR("Could not create format converter", err);
            sSavedHostError = err;
            goto error;
        }
        
        if( oldConverter != NULL )
        {
            verify_noerr( AudioConverterDispose( oldConverter ) );
        }
    }
    
error:
    pahsc->formatListenerCalled = true;
    return err;
}

/* Allocate FIFO between Device callback and Converter callback so that device can push data
* and converter can pull data.
*/
static PaError PaOSX_CreateInputRingBuffer( internalPortAudioStream   *past )
{
    PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
    OSStatus  err = noErr;
    UInt32    dataSize;
    double    sampleRateRatio;
    long      numBytes;
    UInt32    framesPerHostBuffer;
    UInt32    bytesForDevice;
    UInt32    bytesForUser;
    UInt32    bytesPerFrame;
    AudioStreamBasicDescription formatDesc;
    
    dataSize = sizeof(formatDesc);
    err = AudioDeviceGetProperty( pahsc->input.audioDeviceID, 0, IS_INPUT,
        kAudioDevicePropertyStreamFormat, &dataSize, &formatDesc);
    if( err != noErr )
    {
        PRINT_ERR("PaOSX_CreateInputRingBuffer: Could not get input format.\n", err);
        sSavedHostError = err;
        return paHostError;
    }

    // If device is delivering audio faster than being consumed then buffer must be bigger.
    sampleRateRatio = formatDesc.mSampleRate / past->past_SampleRate;
    
    // Get size of CoreAudio IO buffers.
    dataSize = sizeof(framesPerHostBuffer);
    err = AudioDeviceGetProperty( pahsc->input.audioDeviceID, 0, IS_INPUT,
                                kAudioDevicePropertyBufferFrameSize, &dataSize,
                                &framesPerHostBuffer);
    if( err != noErr )
    {
        PRINT_ERR("PaOSX_CreateInputRingBuffer: Could not get input buffer size.\n", err);
        sSavedHostError = err;
        return paHostError;
    }
    
    bytesPerFrame = past->past_NumInputChannels * sizeof(Float32);
    
    bytesForDevice = framesPerHostBuffer * bytesPerFrame * 2;
    bytesForUser = past->past_FramesPerUserBuffer * bytesPerFrame * 3 * sampleRateRatio;
        
    // Ring buffer should be large enough to consume audio input from device,
    // and to deliver a complete user buffer.
    numBytes = (bytesForDevice > bytesForUser) ? bytesForDevice : bytesForUser;
            
    numBytes = RoundUpToNextPowerOf2( numBytes );

    DBUG(("PaOSX_CreateInputRingBuffer: FIFO numBytes = %ld\n", numBytes));
    pahsc->ringBufferData = PaHost_AllocateFastMemory( numBytes );
    if( pahsc->ringBufferData == NULL )
    {
        return paInsufficientMemory;
    }
    RingBuffer_Init( &pahsc->ringBuffer, numBytes, pahsc->ringBufferData );
    // Make it look almost full at beginning. We must advance by an integral number of frames
    // so that the channels don't get scrambled when numChannels is not a power of 2.
    {
        int numZeroFrames = numBytes / bytesPerFrame;
        int numZeroBytes = numZeroFrames * bytesPerFrame;
        RingBuffer_AdvanceWriteIndex( &pahsc->ringBuffer, numZeroBytes );
    }
    
    return paNoError;
}

/******************************************************************
 * Try to set the I/O bufferSize of the device.
 * Scale the size by the ratio of the sample rates so that the converter will have
 * enough data to operate on.
 */
static OSStatus PaOSX_SetDeviceBufferSize( AudioDeviceID devID, Boolean isInput, int framesPerUserBuffer, Float64 sampleRateRatio )
{
    UInt32    dataSize;
    UInt32    ioBufferSize;
    int       scaler;    
    
	scaler = (int) sampleRateRatio;
    if( sampleRateRatio > (Float64) scaler ) scaler += 1;
    DBUG(("PaOSX_SetDeviceBufferSize: buffer size scaler = %d\n", scaler ));
    ioBufferSize = framesPerUserBuffer * scaler;
    
    // Limit buffer size to reasonable value.
    if( ioBufferSize < 128 ) ioBufferSize = 128;

    dataSize = sizeof(ioBufferSize);
    return AudioDeviceSetProperty( devID, 0, 0, isInput,
                            kAudioDevicePropertyBufferFrameSize, dataSize,
                            &ioBufferSize);
}


/*******************************************************************/
static PaError PaOSX_OpenCommonDevice( internalPortAudioStream   *past,
        PaHostInOut *inOut, Boolean isInput )
{
    PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
    PaError          result = paNoError;
    OSStatus         err = noErr;
    Float64          deviceRate;

    PaOSX_FixVolumeScalars( inOut->audioDeviceID, isInput,
        inOut->numChannels, 0.1, 0.9 );

    // The HW device format changes are asynchronous.
    // So we don't know when or if the PAOSX_DevicePropertyListener() will
    // get called. To be safe, call the listener now to forcibly create the converter.
    if( inOut->converter == NULL )
    {
        err = PAOSX_DevicePropertyListener (inOut->audioDeviceID,
                                0, isInput, kAudioDevicePropertyStreamFormat, past);
        if (err != kAudioHardwareNoError)
        {
            PRINT_ERR("PaOSX_OpenCommonDevice: PAOSX_DevicePropertyListener failed.\n", err);
            sSavedHostError = err;
            return paHostError;
        }
    }

    // Add listener for when format changed by other apps.
    DBUG(("PaOSX_OpenCommonDevice: call AudioDeviceAddPropertyListener()\n" ));
	err = AudioDeviceAddPropertyListener( inOut->audioDeviceID, 0, isInput,
        kAudioDevicePropertyStreamFormat,
        (AudioDevicePropertyListenerProc) PAOSX_DevicePropertyListener, past );
    if (err != noErr)
    {
        return -1; // FIXME
    }

    // Only change format if current HW format is different.
    // Don't bother to check result because we are going to use an AudioConverter anyway.
    pahsc->formatListenerCalled = false;
    result = PaOSX_SetFormat( inOut->audioDeviceID, isInput, past->past_SampleRate, inOut->numChannels );
    // Synchronize with device because format changes put some devices into unusable mode.
    if( result > 0 )
    {
        const int sleepDurMsec = 50;
        int spinCount = MIN_TIMEOUT_MSEC / sleepDurMsec;
        while( !pahsc->formatListenerCalled && (spinCount > 0) )
        {
            Pa_Sleep( sleepDurMsec ); // FIXME - use a semaphore or signal
            spinCount--;
        }
        if( !pahsc->formatListenerCalled )
        {
            PRINT(("PaOSX_OpenCommonDevice: timed out waiting for device format to settle.\n"));
        }
        result = 0;
    }
    
#if SET_DEVICE_BUFFER_SIZE
    // Try to set the I/O bufferSize of the device.
    {
        Float64   ratio;
        deviceRate = PaOSX_GetDeviceSampleRate

⌨️ 快捷键说明

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