gpt4 book ai didi

ios - 将 AVCaptureAudioDataOutput 数据传递到 vDSP/Accelerate.framework

转载 作者:可可西里 更新时间:2023-11-01 04:31:05 25 4
gpt4 key购买 nike

我正在尝试创建一个对麦克风数据运行 FFT 的应用程序,因此我可以检查例如输入中最响亮的频率。

我看到有很多获取音频输入的方法(RemoteIO AudioUnit、AudioQueue 服务和 AVFoundation),但 AVFoundation 似乎是最简单的。我有这个设置:

// Configure the audio session
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryRecord error:NULL];
[session setMode:AVAudioSessionModeMeasurement error:NULL];
[session setActive:YES error:NULL];

// Optional - default gives 1024 samples at 44.1kHz
//[session setPreferredIOBufferDuration:samplesPerSlice/session.sampleRate error:NULL];

// Configure the capture session (strongly-referenced instance variable, otherwise the capture stops after one slice)
_captureSession = [[AVCaptureSession alloc] init];

// Configure audio device input
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:NULL];
[_captureSession addInput:input];

// Configure audio data output
AVCaptureAudioDataOutput *output = [[AVCaptureAudioDataOutput alloc] init];
dispatch_queue_t queue = dispatch_queue_create("My callback", DISPATCH_QUEUE_SERIAL);
[output setSampleBufferDelegate:self queue:queue];
[_captureSession addOutput:output];

// Start the capture session.
[_captureSession startRunning];

(加上错误检查,为了便于阅读这里省略了)。

然后我执行以下 AVCaptureAudioDataOutputSampleBufferDelegate方法:

- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
{
NSLog(@"Num samples: %ld", CMSampleBufferGetNumSamples(sampleBuffer));
// Usually gives 1024 (except the first slice)
}

我不确定下一步应该做什么。 CMSampleBuffer 格式到底描述了什么(如果有的话,可以对它做出什么假设)?我应该如何将原始音频数据放入 vDSP_fft_zrip用尽可能少的额外预处理? (此外,您建议如何验证我看到的原始数据是否正确?)

最佳答案

CMSampleBufferRef 是一种不透明类型,包含 0 个或多个媒体样本。文档中有一些内容:

http://developer.apple.com/library/ios/#documentation/CoreMedia/Reference/CMSampleBuffer/Reference/reference.html

在本例中它将包含一个音频缓冲区,以及样本格式和时间信息的描述等。如果您真的有兴趣,只需在委托(delegate)回调中放置一个断点并查看即可。

第一步是获取指向已返回的数据缓冲区的指针:

// get a pointer to the audio bytes
CMItemCount numSamples = CMSampleBufferGetNumSamples(sampleBuffer);
CMBlockBufferRef audioBuffer = CMSampleBufferGetDataBuffer(sampleBuffer);
size_t lengthAtOffset;
size_t totalLength;
char *samples;
CMBlockBufferGetDataPointer(audioBuffer, 0, &lengthAtOffset, &totalLength, &samples);

iPhone 麦克风的默认样本格式是线性 PCM,具有 16 位样本。这可能是单声道或立体声,具体取决于是否有外部麦克风。要计算 FFT,我们需要一个浮点向量。幸运的是,有一个加速函数可以为我们做转换:

// check what sample format we have
// this should always be linear PCM
// but may have 1 or 2 channels
CMAudioFormatDescriptionRef format = CMSampleBufferGetFormatDescription(sampleBuffer);
const AudioStreamBasicDescription *desc = CMAudioFormatDescriptionGetStreamBasicDescription(format);
assert(desc->mFormatID == kAudioFormatLinearPCM);
if (desc->mChannelsPerFrame == 1 && desc->mBitsPerChannel == 16) {
float *convertedSamples = malloc(numSamples * sizeof(float));
vDSP_vflt16((short *)samples, 1, convertedSamples, 1, numSamples);
} else {
// handle other cases as required
}

现在您有一个样本缓冲区的浮点向量,您可以将其与 vDSP_fft_zrip 一起使用。使用 AVFoundation 似乎无法将麦克风的输入格式更改为 float 样本,因此您只能执行最后一个转换步骤。我会在实践中保留缓冲区,如果有必要,在更大的缓冲区到达时重新分配它们,这样您就不会在每次委托(delegate)回调时分配和释放缓冲区。

至于你的最后一个问题,我想最简单的方法是注入(inject)一个已知的输入并检查它是否给你正确的响应。您可以向麦克风播放正弦波并检查您的 FFT 是否在正确的频率仓中有一个峰值,诸如此类。

关于ios - 将 AVCaptureAudioDataOutput 数据传递到 vDSP/Accelerate.framework,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14088290/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com