如何更改 iPhone 的麦克风采样率

发布于 2025-01-12 06:14:50 字数 3022 浏览 0 评论 0原文

我正在努力向现有应用程序添加一项功能,以从设备麦克风获取音频输入,通过 FFT 将其转换为频域并将其发送到 coreML 模型。我正在使用标准 AVCaptureDevice:

guard let microphone = AVCaptureDevice.default(.builtInMicrophone,
                                                   for: .audio,
                                                   position: .unspecified),
let microphoneInput = try? AVCaptureDeviceInput(device: microphone) else {
                fatalError("Can't create microphone.")
}

问题是,我需要为麦克风定义自定义采样率。按照 Apple 的文档,setPreferredSampleRate (link) 应该能够在 8000-48000 Hz 范围内做到这一点。然而,无论我选择哪个值,采样率都不会改变,也不会抛出错误:

print("Microphone sample rate: ", AVAudioSession.sharedInstance().sampleRate)

do { var flag = try AVAudioSession.sharedInstance().setPreferredSampleRate(20000) }
catch { print("Unable to set microphone sampling rate!") }

print("Microphone sample rate: ", AVAudioSession.sharedInstance().sampleRate)

输出:

Microphone sample rate: 48000.0
Microphone sample rate: 48000.0

How can I Define the Sample Rate for iOS devices?

编辑:

遵循使用<的建议code>AVAudioConverter 来重新采样麦克风输入,考虑到我正在使用 AVCaptureAudioDataOutputSampleBufferDelegate 和相应的,最有效的方法是什么?从麦克风收集原始音频输入的 captureOutput 方法:

extension AudioSpectrogram: AVCaptureAudioDataOutputSampleBufferDelegate {

    public func captureOutput(_ output: AVCaptureOutput,
                              didOutput sampleBuffer: CMSampleBuffer,
                              from connection: AVCaptureConnection) {

        var audioBufferList = AudioBufferList()
        var blockBuffer: CMBlockBuffer?

        CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(
            sampleBuffer,
            bufferListSizeNeededOut: nil,
            bufferListOut: &audioBufferList,
            bufferListSize: MemoryLayout.stride(ofValue: audioBufferList),
            blockBufferAllocator: nil,
            blockBufferMemoryAllocator: nil,
            flags: kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment,
            blockBufferOut: &blockBuffer)

        guard let data = audioBufferList.mBuffers.mData else {
            return
        }

        if self.rawAudioData.count < self.sampleCount * 2 {
            let actualSampleCount = CMSampleBufferGetNumSamples(sampleBuffer)

            let ptr = data.bindMemory(to: Int16.self, capacity: actualSampleCount)
            let buf = UnsafeBufferPointer(start: ptr, count: actualSampleCount)

            rawAudioData.append(contentsOf: Array(buf))
        }

        while self.rawAudioData.count >= self.sampleCount {
            let dataToProcess = Array(self.rawAudioData[0 ..< self.sampleCount])
            self.rawAudioData.removeFirst(self.hopCount)
            self.processData(values: dataToProcess)
        }
 }

I'm working on adding a feature to an existing app, to take audio input from the device microphone, convert it to frequency domain via an FFT and sends it to a coreML model. I'm using a standard AVCaptureDevice:

guard let microphone = AVCaptureDevice.default(.builtInMicrophone,
                                                   for: .audio,
                                                   position: .unspecified),
let microphoneInput = try? AVCaptureDeviceInput(device: microphone) else {
                fatalError("Can't create microphone.")
}

The issue is, I require a custom sample rate to be defined for the microphone. Following Apple's documentation, setPreferredSampleRate (link) should be able to do that in a range between 8000-48000 Hz. However no matter which value I choose, the sample rate won't change, and no error is thrown:

print("Microphone sample rate: ", AVAudioSession.sharedInstance().sampleRate)

do { var flag = try AVAudioSession.sharedInstance().setPreferredSampleRate(20000) }
catch { print("Unable to set microphone sampling rate!") }

print("Microphone sample rate: ", AVAudioSession.sharedInstance().sampleRate)

Output:

Microphone sample rate: 48000.0
Microphone sample rate: 48000.0

How could I define the sampling rate for iOS devices?

EDIT:

Following the suggestion of using AVAudioConverter to resample microphone input, what's the most efficient way of doing this, considering I'm using AVCaptureAudioDataOutputSampleBufferDelegate and the corresponding captureOutput method to collect raw audio input from the microphone:

extension AudioSpectrogram: AVCaptureAudioDataOutputSampleBufferDelegate {

    public func captureOutput(_ output: AVCaptureOutput,
                              didOutput sampleBuffer: CMSampleBuffer,
                              from connection: AVCaptureConnection) {

        var audioBufferList = AudioBufferList()
        var blockBuffer: CMBlockBuffer?

        CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(
            sampleBuffer,
            bufferListSizeNeededOut: nil,
            bufferListOut: &audioBufferList,
            bufferListSize: MemoryLayout.stride(ofValue: audioBufferList),
            blockBufferAllocator: nil,
            blockBufferMemoryAllocator: nil,
            flags: kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment,
            blockBufferOut: &blockBuffer)

        guard let data = audioBufferList.mBuffers.mData else {
            return
        }

        if self.rawAudioData.count < self.sampleCount * 2 {
            let actualSampleCount = CMSampleBufferGetNumSamples(sampleBuffer)

            let ptr = data.bindMemory(to: Int16.self, capacity: actualSampleCount)
            let buf = UnsafeBufferPointer(start: ptr, count: actualSampleCount)

            rawAudioData.append(contentsOf: Array(buf))
        }

        while self.rawAudioData.count >= self.sampleCount {
            let dataToProcess = Array(self.rawAudioData[0 ..< self.sampleCount])
            self.rawAudioData.removeFirst(self.hopCount)
            self.processData(values: dataToProcess)
        }
 }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文