2015-11-24 49 views
0

在我的应用程序中,我正在渲染回调中进行音频处理(仅输入,不输出)。 这里是我初始化音频:iOS在渲染回调处理之前添加音频效果?

-(void) initAudio { 

OSStatus status; 

NewAUGraph(&graph); 

AudioComponentDescription desc; 
desc.componentType   = kAudioUnitType_Output; 
desc.componentSubType  = kAudioUnitSubType_RemoteIO; 
desc.componentFlags   = 0; 
desc.componentFlagsMask  = 0; 
desc.componentManufacturer = kAudioUnitManufacturer_Apple; 

AUNode ioNode; 

status = AUGraphAddNode(graph, &desc, &ioNode); 
checkStatus(status, "At adding node"); 

AUGraphOpen(graph); 

AUGraphNodeInfo(graph, ioNode, NULL, &audioUnit); 

//Enable IO for recording 
UInt32 enableInput = 1; 
status = AudioUnitSetProperty(audioUnit, 
           kAudioOutputUnitProperty_EnableIO, 
           kAudioUnitScope_Input, 
           kInputBus, 
           &enableInput, 
           sizeof(enableInput)); 
checkStatus(status, "At setting property for input"); 

//Disable playback 
UInt32 enableOutput = 0; 
status = AudioUnitSetProperty(audioUnit, 
           kAudioOutputUnitProperty_EnableIO, 
           kAudioUnitScope_Output, 
           kOutputBus, 
           &enableOutput, 
           sizeof(enableOutput)); 
checkStatus(status, "At setting property for input"); 

// ASBD 
AudioStreamBasicDescription audioFormatIn; 
audioFormatIn.mSampleRate   = SampleRate; 
audioFormatIn.mFormatID   = kAudioFormatLinearPCM; 
audioFormatIn.mFormatFlags  = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; 
audioFormatIn.mFramesPerPacket = 1; 
audioFormatIn.mChannelsPerFrame = 1; 
audioFormatIn.mBitsPerChannel  = 16;//sizeof(AudioSampleType) * 8; 
audioFormatIn.mBytesPerPacket  = 2 * audioFormatIn.mChannelsPerFrame; 
audioFormatIn.mBytesPerFrame  = 2 * audioFormatIn.mChannelsPerFrame; 

//Apply format 
status = AudioUnitSetProperty(audioUnit, 
           kAudioUnitProperty_StreamFormat, 
           kAudioUnitScope_Output, 
           kInputBus, 
           &audioFormatIn, 
           sizeof(audioFormatIn)); 
checkStatus(status,"At setting property for AudioStreamBasicDescription for input"); 


//Set up 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,"At setting property for recording callback"); 

// Disable buffer allocation for the recorder 
UInt32 flag = 0; 
status = AudioUnitSetProperty(audioUnit, 
           kAudioUnitProperty_ShouldAllocateBuffer, 
           kAudioUnitScope_Output, 
           kInputBus, 
           &flag, 
           sizeof(flag)); 
checkStatus(status, "At set property should allocate buffer"); 

// Allocate own buffers 
tempBuffer.mNumberChannels = 1; 
tempBuffer.mDataByteSize = 1024 * 2; 
tempBuffer.mData   = malloc(1024 * 2); 

status = AUGraphInitialize(graph); 
checkStatus(status,"At AUGraph Initalize"); 
} 

现在,我想在渲染回调处理之前增加一个高通滤波器或带通滤波器的输入音频。所以我觉得我应该增加这样的:

desc.componentType   = kAudioUnitType_Effect; 
desc.componentSubType  = kAudioUnitSubType_BandPassFilter; 
desc.componentFlags   = 0; 
desc.componentFlagsMask  = 0; 
desc.componentManufacturer = kAudioUnitManufacturer_Apple; 

,但我没能创造/正确连接节点,使这项工作... 感谢您的帮助!

+0

您的渲染链条是否在没有带通的情况下工作? – dave234

+0

@Dave我曾经使用过经典的音频单元初始化,但是我开始转向AUGraph,即使我不确定自己做的是否正确,我上面的代码似乎也能正常工作。 – jcr

回答

0

当我想做类似的事情时,我发现你的问题 - 很遗憾没有任何解决方案:-(现在几天后,设法做到了这一点,所以这是我的工作解决方案,每个人都在努力解决同样的问题:

  1. 准备Remote_IO的输入作为一个独立的音频单元,用于记录音频
  2. 添加一个回调到输入我把它叫做“话筒回调”

    (注意:苹果来电这是一个输入回调,而事实上,这只是一个NOTIFICATION回调,对t来说ELL您的应用程序,样品是可用的,你要“问”输入单元明确地使它们...)

  3. 建立一个AU图:转换器单元 - >过滤器 - >通用输出

    (注:通用输出可以转换,但不是过滤器。所以,如果你想喂入除8.24格式以外的链,那么你需要转换器。)

  4. 向转换器单元的输入添加一个回调。我将这称为“流程回调”。

现在关键的一点是,定期调用由操作系统到MIC回调将驱动整个处理链:

  • 在MIC回叫,准备一个与麦克风可用的输入样本数量一样大的缓冲区,然后“请求”GENERIC OUTPUT(!)渲染相同数量的样本(通过调用AudioUnitRender)。请注意,您并不是要求输入单位进行渲染,而是要求输出单位在图表的最后!

  • 通用输出将转发呈现请求,直到它到达转换器单元的输入回调,即进程回调。在这个例子中,你得到了一个指向缓冲区的输入参数,你必须填写请求的样本数。此时,请INPUT UNIT将样本准确地渲染到该缓冲区。

  • 和中提琴,你完成了。你只需要开始/停止话筒单元!

    在整个过程的关键是,总是有来带动整个渲染过程,并作为通用输出没有任何规则的“需要”得到的样品,你有输出单元手动要求它渲染样本。并且这必须与麦克风的A/D转换器同步,该转换器希望以规则的时间间隔放置样本。

    理论上你可以链中的输入单元和你的图,但有两个问题:

    1. MIC输入单元计数作为输出单元和不能有在图中,两个输出单元...

    2. 当单元连接在一起时,则不能在两者之间进行回调。如果你在那里放一个,它将永远不会被调用...所以你会把回调放在链的末尾,并期望“样本可用”通知将我们从麦克风单元的输出传播到通用输出。但它不会。因此您必须将流程分为麦克风输入单元和处理链。

    最后说明:如果要直接呈现的麦克风的样本插入到所述转换器单元,那么你必须设置相同的流格式(优选远程IO(即16位的规范输出格式,整数)的转换器单元的输入和麦克风单元的输出(即远程io,总线1的输入范围)。