音频单元录制噪音

Posted

技术标签:

【中文标题】音频单元录制噪音【英文标题】:Audio unit recording noise 【发布时间】:2012-07-18 09:17:52 【问题描述】:

我昨天一直在努力解决这个问题,非常感谢您的帮助。

我有一个多通道混音器音频单元,分配给每个通道的回调在调用时填充所需的音频缓冲区。我正在尝试通过将数据写入文件来在同一个回调中进行记录。

目前,如果我不调用 AudioUnitRender 并且如果我调用它,我会收到两个错误。错误 10877 和错误 50。

回调中的录音代码是这样的

if (recordingOn) 

    AudioBufferList *bufferList = (AudioBufferList *)malloc(sizeof(AudioBuffer));

    SInt16 samples[inNumberFrames]; 
    memset (&samples, 0, sizeof (samples));

    bufferList->mNumberBuffers = 1;
    bufferList->mBuffers[0].mData = samples;
    bufferList->mBuffers[0].mNumberChannels = 2;
    bufferList->mBuffers[0].mDataByteSize = inNumberFrames*sizeof(SInt16);

    OSStatus status;
    status = AudioUnitRender(audioObject.mixerUnit,     
                             ioActionFlags, 
                             inTimeStamp, 
                             inBusNumber, 
                             inNumberFrames, 
                             bufferList);

    if (noErr != status) 
        printf("AudioUnitRender error: %ld", status); 
        return noErr;
    

    ExtAudioFileWriteAsync(audioObject.recordingFile, inNumberFrames, bufferList);

在每个通道回调中写入数据是否正确,还是应该将其连接到远程 I/O 单元?

我使用的是 LPCM,录音文件 (caf) 的 ASBD 是

recordingFormat.mFormatID = kAudioFormatLinearPCM;
recordingFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger |
kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsPacked;
recordingFormat.mSampleRate = 44100;
recordingFormat.mChannelsPerFrame = 2;
recordingFormat.mFramesPerPacket = 1;
recordingFormat.mBytesPerPacket = recordingFormat.mChannelsPerFrame * sizeof (SInt16);
recordingFormat.mBytesPerFrame = recordingFormat.mChannelsPerFrame * sizeof (SInt16);
recordingFormat.mBitsPerChannel = 16;

我不确定自己做错了什么。

立体声如何影响在写入文件之前必须处理记录的数据的方式?

【问题讨论】:

【参考方案1】:

有几个问题。如果您尝试录制最终的“混音”,您可以使用 AudioUnitAddRenderNotify(iounit,callback,file) 在 I/O 单元上添加回调。然后回调简单地获取 ioData 并将其传递给 ExtAudioFileWriteAsync(...)。因此,您也不需要创建任何缓冲区。旁注:在渲染线程中分配内存是不好的。您应该避免渲染回调中的所有系统调用。无法保证这些调用将在音频线程的最后期限内执行。因此为什么有一个 ExtAudioFileWriteAsync,它会考虑到这一点并在另一个线程中写入磁盘。

【讨论】:

非常感谢您的帮助。这些音频问题获得的观看次数越来越少。好的,我将添加它,看看它是如何进行的。那么在这个添加的录制回调中,我可以将 &ioData 传递给 writeAsync 调用吗?关于回调中的分配,是的,它真的很糟糕,我现在脑子很乱,需要逐步分解。我也在我的回调中这样做 [[NSNotificationCenter defaultCenter] postNotificationName: MixerAudioObjectSampleFinishedPlayingNotification object:nil];为了将完成的通道设置为静音,并将 kMultiChannelMixerParam_Enable 设置为 False。这很糟糕吧? 是的,这很糟糕。一种常见的方法是在您的主线程中进行轮询并收听/观察您的数据。并且该数据应该是 c 结构或 c++ 对象。是的,ioData 在缓冲区列表中有渲染的音频。【参考方案2】:

我找到了一个演示代码,可能有用 4 U;

演示网址:https://github.com/JNYJdev/AudioUnit

博客:http://atastypixel.com/blog/using-remoteio-audio-unit/

static OSStatus recordingCallback(void *inRefCon, 
                          AudioUnitRenderActionFlags *ioActionFlags, 
                          const AudioTimeStamp *inTimeStamp, 
                          UInt32 inBusNumber, 
                          UInt32 inNumberFrames, 
                          AudioBufferList *ioData) 
// Because of the way our audio format (setup below) is chosen:
// we only need 1 buffer, since it is mono
// Samples are 16 bits = 2 bytes.
// 1 frame includes only 1 sample

AudioBuffer buffer;

buffer.mNumberChannels = 1;
buffer.mDataByteSize = inNumberFrames * 2;
buffer.mData = malloc( inNumberFrames * 2 );

// Put buffer in a AudioBufferList
AudioBufferList bufferList;
bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0] = buffer;

// Then:
// Obtain recorded samples

OSStatus status;

status = AudioUnitRender([iosAudio audioUnit], 
                     ioActionFlags, 
                     inTimeStamp, 
                     inBusNumber, 
                     inNumberFrames, 
                     &bufferList);
checkStatus(status);

// Now, we have the samples we just read sitting in buffers in bufferList
// Process the new data
[iosAudio processAudio:&bufferList];

// release the malloc'ed data in the buffer we created earlier
free(bufferList.mBuffers[0].mData);

return noErr;

【讨论】:

以上是关于音频单元录制噪音的主要内容,如果未能解决你的问题,请参考以下文章

使用 aurioTouch 录制音频单元文件 - AudioStreamBasicDescription 配置问题?

使用音频会话录制时如何减少录制噪音?

音频单元录制:增加缓冲区的音量

使用音频单元录制扬声器输出

如何使用robolectric对Android音频录制应用进行单元测试

使用 Pyaudio 在 Python 中录制音频,错误 ||PaMacCore (AUHAL)|| ... msg=音频单元:在当前上下文中无法执行