本文介绍了iOS:如何在运行时使用音频单元重新采样音频(PCM数据)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在运行时/现场使用音频单元对音频(PCM数据)重新采样?

How can i resample audio(PCM data) using Audio Unit at runtime/live ?

我的音频单元设置如下。

I have an Audio Unit setup as follows.

- (void) setUpAudioUnit {
    OSStatus status;
    AudioComponentInstance audioUnit;
    AudioComponent inputComponent;
    AudioComponentDescription audioComponentDescription;
    AudioStreamBasicDescription audioStreamBasicDescription;

    // Describe audio component
    audioComponentDescription.componentType = kAudioUnitType_Output;
    audioComponentDescription.componentSubType = kAudioUnitSubType_VoiceProcessingIO;
    audioComponentDescription.componentFlags = 0;
    audioComponentDescription.componentFlagsMask = 0;
    audioComponentDescription.componentManufacturer = kAudioUnitManufacturer_Apple;

    // Get component
    inputComponent = AudioComponentFindNext(NULL, &audioComponentDescription);

    // Get audio units
    status = AudioComponentInstanceNew(inputComponent, &audioUnit);
    checkStatus(status);

    // Enable IO for recording
    UInt32 flag = 1;
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioOutputUnitProperty_EnableIO,
                                  kAudioUnitScope_Input,
                                  kInputBus,
                                  &flag,
                                  sizeof(flag));
    checkStatus(status);

    // Enable IO for playback
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioOutputUnitProperty_EnableIO,
                                  kAudioUnitScope_Output,
                                  kOutputBus,
                                  &flag,
                                  sizeof(flag));
    checkStatus(status);

    // Describe format
    audioStreamBasicDescription.mSampleRate         = AUDIO_SAMPLE_RATE;
    audioStreamBasicDescription.mFormatID           = kAudioFormatLinearPCM;
    audioStreamBasicDescription.mFormatFlags        = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    audioStreamBasicDescription.mFramesPerPacket    = AUDIO_FRAMES_PER_PACKET;
    audioStreamBasicDescription.mChannelsPerFrame   = AUDIO_CHANNELS_PER_FRAME;
    audioStreamBasicDescription.mBitsPerChannel     = AUDIO_BITS_PER_CHANNEL;
    audioStreamBasicDescription.mBytesPerPacket     = AUDIO_BYTES_PER_PACKET;
    audioStreamBasicDescription.mBytesPerFrame      = AUDIO_BYTES_PER_FRAME;

    // Apply format
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioUnitProperty_StreamFormat,
                                  kAudioUnitScope_Output,
                                  kInputBus,
                                  &audioStreamBasicDescription,
                                  sizeof(audioStreamBasicDescription));
    checkStatus(status);


    /* Make sure we set the correct audio category before restarting */
    UInt32 audioCategory = kAudioSessionCategory_PlayAndRecord;
    status = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
                                     sizeof(audioCategory),
                                     &audioCategory);

    checkStatus(status);


    status = AudioUnitSetProperty(audioUnit,
                                  kAudioUnitProperty_StreamFormat,
                                  kAudioUnitScope_Input,
                                  kOutputBus,
                                  &audioStreamBasicDescription,
                                  sizeof(audioStreamBasicDescription));
    checkStatus(status);


    // Set input callback
    AURenderCallbackStruct callbackStruct;
    callbackStruct.inputProc = recordingCallback;
    callbackStruct.inputProcRefCon = (__bridge void *)(self);
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioOutputUnitProperty_SetInputCallback,
                                  kAudioUnitScope_Global,
                                  kInputBus,
                                  &callbackStruct,
                                  sizeof(callbackStruct));
    checkStatus(status);

    // Set output callback
    callbackStruct.inputProc = playbackCallback;
    callbackStruct.inputProcRefCon = (__bridge void *)(self);
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioUnitProperty_SetRenderCallback,
                                  kAudioUnitScope_Global,
                                  kOutputBus,
                                  &callbackStruct,
                                  sizeof(callbackStruct));
    checkStatus(status);

    // Disable buffer allocation for the recorder (optional - do this if we want to pass in our own)
    flag = 0;
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioUnitProperty_ShouldAllocateBuffer,
                                  kAudioUnitScope_Output,
                                  kInputBus,
                                  &flag,
                                  sizeof(flag));


}

音频设置如下。

kOutputBus 0
kInputBus 1
AUDIO_SAMPLE_RATE 44100
AUDIO_FRAMES_PER_PACKET 1
AUDIO_CHANNELS_PER_FRAME 1
AUDIO_BITS_PER_CHANNEL 16
AUDIO_BYTES_PER_PACKET 2
AUDIO_BYTES_PER_FRAME 2

我正在接收记录为回调的PCM数据

I am receiving the PCM data from recording callback as

audioBufferList->mBuffers[0].mData

SO,我如何将该PCM数据从44.1KHz重采样到8KHz,反之亦然?
我在Google上搜索了很多,但是没有找到任何代码示例或直接的说明。

SO, how can i resample this PCM data from 44.1KHz to 8KHz and vice versa ?I have googled a lot but didn't find any code sample or straight instruction for this.

找到了这些线程,但没有一个提供清晰的指令。

Found these thread but none of these provides clear instruction.




  1. Which built in AudioUnit can resample audio?
  2. Changing sample rate of an AUGraph on iOS

高度赞赏任何代码示例或信息。

Any code sample or information is highly appreciated.

推荐答案

转换器音频单元将处理您的采样率转换。我发现解决此问题的最佳方法是使您的链适应硬件本身所做的事情。这意味着您应该获取系统AudioStreamBasicDescription(sysASBD),然后将转换器单元放置在系统与需要不同内容的链部分之间。因此,要使用8K sampleRate进行音频播放,您可以执行以下操作:ReomoteIO(mic)->转换器-> your8Kprocessing->转换器-> RemoteIO(out)。

A converter audio unit will handle your sample rate conversions. I find the best way to deal with this is to adapt your chain to what the hardware is doing natively. This means that you should get the system AudioStreamBasicDescription (sysASBD) then put converter units between the system and the parts of your chain that need something different. So for audio play through with 8K sampleRate you would do this: ReomoteIO(mic) -> converter -> your8Kprocessing -> converter -> RemoteIO(out).

这是转换器的描述。

AudioComponentDescription convDesc;
convDesc.componentType = kAudioUnitType_FormatConverter;
convDesc.componentSubType = kAudioUnitSubType_AUConverter;
convDesc.componentFlags = 0;
convDesc.componentFlagsMask = 0;
convDesc.componentManufacturer = kAudioUnitManufacturer_Apple;

以下是获取系统ASBDin和ASBDout的方法

Here is how you get the system ASBDin and ASBDout

UInt32 sizeASBD = sizeof(AudioStreamBasicDescription);
AudioStreamBasicDescription ioASBDin;
AudioStreamBasicDescription ioASBDout;
AudioUnitGetProperty(remoteIO, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &ioASBDin, &sizeASBD);
AudioUnitGetProperty(remoteIO, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &ioASBDout, &sizeASBD);

使用转换器所需要做的就是设置输入ASBD和输出ASBD为所需格式它完成所有工作。建立连接,您就可以播放8K。

All you have to do to use a converter is set it's input ASBD and output ASBD to the desired formats and it does all the work. The make your connections and you have your 8K play through.

AudioStreamBasicDescription asbd8K;

AudioComponentInstance converter44To8;
AudioUnitSetProperty(converter44To8,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Input,0,& ioASBDin,sizeof(AudioStreamBasicDescription));
AudioUnitSetProperty(converter44To8,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Output,0,&asbd8K,sizeof(AudioStreamBasicDescription));


AudioComponentInstance converter8To44;
AudioUnitSetProperty(converter8To44,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Input,0,&asbd8K,sizeof(AudioStreamBasicDescription));
AudioUnitSetProperty(converter8To44,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Output,0,& ioASBDout,sizeof(AudioStreamBasicDescription));

这篇关于iOS:如何在运行时使用音频单元重新采样音频(PCM数据)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 00:53