使用 Avaudioengine iOS 的低通滤波器 + 采样率转换

2023-11-26

我们正在开发一个项目,该项目允许我们使用一些低通滤波器和高通滤波器以 5k Hz 采样率从麦克风录制一些声音。

我们正在使用什么

我们正在使用音频引擎以此目的。

我们正在使用AVA音频转换器用于降低采样率。

我们正在使用AVAudioUnitEQ用于低通和高通滤波器。

Code

let bus = 0
let inputNode = engine.inputNode

let equalizer = AVAudioUnitEQ(numberOfBands: 2)

equalizer.bands[0].filterType = .lowPass
equalizer.bands[0].frequency = 3000
equalizer.bands[0].bypass = false

equalizer.bands[1].filterType = .highPass
equalizer.bands[1].frequency = 1000
equalizer.bands[1].bypass = false
engine.attach(equalizer) //Attach equalizer

// Connect nodes
engine.connect(inputNode, to: equalizer, format: inputNode.inputFormat(forBus: 0))
engine.connect(equalizer, to: engine.mainMixerNode, format: inputNode.inputFormat(forBus: 0))
engine.connect(engine.mainMixerNode, to: engine.outputNode, format: inputNode.inputFormat(forBus: 0))

let outputFormat = AVAudioFormat(commonFormat: .pcmFormatInt16,
                                            sampleRate: 5000,
                                            channels: 1,
                                            interleaved: false)!

// Converter to downgrade sample rate
guard let converter: AVAudioConverter = AVAudioConverter(from: inputNode.inputFormat(forBus: 0), to: outputFormat) else {
           print("Can't convert in to this format")
           return
       }

engine.mainMixerNode.installTap(onBus: bus, bufferSize: 2688, format: engine.mainMixerNode.outputFormat(forBus: 0)) { (buffer, time) in
           
     var newBufferAvailable = true
           
     let inputCallback: AVAudioConverterInputBlock = { inNumPackets, outStatus in
           if newBufferAvailable {
                outStatus.pointee = .haveData
                newBufferAvailable = false
                return buffer
           } else {
                outStatus.pointee = .noDataNow
                return nil
           }
     }
           
           
     let convertedBuffer = AVAudioPCMBuffer(pcmFormat: outputFormat, frameCapacity: AVAudioFrameCount(outputFormat.sampleRate) * buffer.frameLength / AVAudioFrameCount(buffer.format.sampleRate))!

           var error: NSError?
           let status = converter.convert(to: convertedBuffer, error: &error, withInputFrom: inputCallback)
           assert(status != .error)

           
           if status == .haveData {
             // Process with converted buffer
           }
            
       }
       
       engine.prepare()
       
       do {
           try engine.start()
       } catch {
           print("Can't start the engine: \(error)")
       }

Issue

低通和高通滤波器不起作用。

替代方法

为了检查代码是否正常工作,我们添加了混响效果而不是低通滤波器。 混响效果(使用AVAudioUnit混响) 使用相同的代码。

谁能帮我看看我们在应用低通滤波器时哪里做错了?


我认为这段代码的主要问题是AVAudioConverter正在调用之前创建engine.prepare()这可以而且将会改变mainMixerNode输出格式。除此之外,还有一个冗余连接mainMixerNode to outputNode,以及可能不正确的格式 -mainMixerNode被记录为“按需”自动创建并连接到输出节点。水龙头也不需要格式。

let bus = 0
let inputNode = engine.inputNode

let equalizer = AVAudioUnitEQ(numberOfBands: 2)

equalizer.bands[0].filterType = .lowPass
equalizer.bands[0].frequency = 3000
equalizer.bands[0].bypass = false

equalizer.bands[1].filterType = .highPass
equalizer.bands[1].frequency = 1000
equalizer.bands[1].bypass = false
engine.attach(equalizer) //Attach equalizer

// Connect nodes
engine.connect(inputNode, to: equalizer, format: inputNode.inputFormat(forBus: 0))
engine.connect(equalizer, to: engine.mainMixerNode, format: inputNode.inputFormat(forBus: 0))

// call before creating converter because this changes the mainMixer's output format
engine.prepare()

let outputFormat = AVAudioFormat(commonFormat: .pcmFormatInt16,
                                 sampleRate: 5000,
                                 channels: 1,
                                 interleaved: false)!

// Downsampling converter
guard let converter: AVAudioConverter = AVAudioConverter(from: engine.mainMixerNode.outputFormat(forBus: 0), to: outputFormat) else {
    print("Can't convert in to this format")
    return
}

engine.mainMixerNode.installTap(onBus: bus, bufferSize: 2688, format: nil) { (buffer, time) in
    var newBufferAvailable = true
    
    let inputCallback: AVAudioConverterInputBlock = { inNumPackets, outStatus in
        if newBufferAvailable {
            outStatus.pointee = .haveData
            newBufferAvailable = false
            return buffer
        } else {
            outStatus.pointee = .noDataNow
            return nil
        }
    }
    
    
    let convertedBuffer = AVAudioPCMBuffer(pcmFormat: outputFormat, frameCapacity: AVAudioFrameCount(outputFormat.sampleRate) * buffer.frameLength / AVAudioFrameCount(buffer.format.sampleRate))!
    
    var error: NSError?
    let status = converter.convert(to: convertedBuffer, error: &error, withInputFrom: inputCallback)
    assert(status != .error)
    
    
    if status == .haveData {
        // Process with converted buffer
    }
}

do {
    try engine.start()
} catch {
    print("Can't start the engine: \(error)")
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Avaudioengine iOS 的低通滤波器 + 采样率转换 的相关文章

随机推荐

  • Swift 协议继承和通用函数

    考虑以下游乐场 import Foundation protocol StringInitable init string String class A StringInitable var stored String required i
  • 如何在 Apache Spark 中获取上一行的数据

    从 Spark Data 框架中查找每个城市上个月的销售情况 City Month Sale c1 JAN 2017 49 c1 FEB 2017 46 c1 MAR 2017 83 c2 JAN 2017 59 c2 MAY 2017 6
  • ServiceStack没有服务器端异步支持

    我的一个朋友告诉我他过去看过 ServiceStack 说它看起来不错 但没有异步支持 所以在他的书中 它不是使用这个框架的选项 如果没有异步就不好 我必须同意 除非ServiceStack添加了异步 否则不确定这对我来说是否是一个不错的选
  • 使用 Async 和 Await 的 ASP.NET C#5 异步 Web 应用程序

    研究了异步 Web 开发的概念 特别是来自this来源 我创建了一个示例应用程序来证明这个概念 该解决方案由 2 个 ASP NET Web API 应用程序组成 第一个是模拟的慢端点 它等待 1000 毫秒 然后返回一个名为 Studen
  • 突出显示 HTML 文本中的单词(但不是标记)

    我试图突出显示正文内的所有匹配单词 但不突出显示任何 html 标记内的单词 例如 给出的关键字是 para 这是该段落 p class para Example of paragraph Lorem ipsum dolor sit ame
  • 课程末尾的美元符号在 Eclipse MAT 中意味着什么?

    我正在使用 Eclipse MAT 尝试追踪 Android 中的资源泄漏 如果您经常更改屏幕方向 当我转到直方图视图时 我看到我的活动与一次又一次列出的相同活动一起列出 并带有 在它之后 So like com test TestActi
  • 将“rlang”准引用与“dplyr::_join”函数一起使用

    我正在尝试编写一个我使用的自定义函数rlang的准引用 该函数内部也使用dplyr s join功能 我在下面提供了一个最小的工作示例来说明我的问题 needed libraries library tidyverse function d
  • 打印 html 文档时所有页面中的 HTML 页眉和页脚

    我创建了一个带有页眉 一些内容和页脚的 html 页面 我尝试打印 HTML 页面 结果有 2 页 我在第一页得到了页眉 在最后一页得到了页脚 我真正需要的是在所有页面中显示页眉和页脚 就像在 Word 文档中一样 我查了一下 发现使用th
  • 如何使用 Android 数据绑定动态更改视图可见性

    我正在尝试使用数据绑定实现一种简单的视图隐藏 显示 我有一个 api 调用 并且在 api 调用正在进行时我必须显示一个进度条 一旦我收到响应 就必须忽略此进度并显示数据 我尝试使用数据绑定动态更改进度条的可见性 但什么也没发生 仅在第一次
  • Python - 使用 pytest 跳过测试,除非指定

    背景 我正在使用 pytest 来测试将数据推送到数据库的网络抓取工具 该类仅拉取 html 并将 html 推送到数据库以供稍后解析 我的大多数测试都使用虚拟数据来表示 html Question 我想做一个测试 从网站上抓取网页 但我希
  • Jaxb 生成的 xml - 根元素前缀问题

    我正在尝试使用 jaxb 生成 xml 我创建了 xsd 并生成了 java 类 但是当我生成 xml 时 我在根标记中添加前缀 ns2 这是我不想要的 例如 我希望根标签是
  • 如何使SurfaceView具有透明背景?

    我有简单的布局
  • SQLAlchemy 不会更新我的数据库

    我正在使用 SQLAlchemy 0 7 8 制作金字塔应用程序 我使用的是64位Python3 2 问题是 为什么以下函数不向数据库提交任何内容 def create card sText sCard create a wildcard
  • Objectify 和 TimerTask:没有为此线程注册 API 环境

    我想得到一个TimerTask设置为定期从 Google App Engine 数据存储中删除条目 我是否设置了一个ServletContextListener with a Timer 在 的里面contextInitialized 我已
  • 涉及 Enum 的多重继承元类冲突

    我需要一个枚举类的双重继承 但也支持我自己的方法 这是上下文 import abc from enum import Enum class MyFirstClass abc ABC abc abstractmethod def func s
  • 如何在 DENO 中使用 npm 模块?

    德诺超级酷 我早上看到了 现在想迁移到 deno 我试图将现有的 Nodejs 脚本移至 deno 任何人都可以帮助我如何在 deno 中使用 npm 模块 我需要 esprima 模块 这个有包https github com denol
  • 通过 jquery.couch.js 或其他方式在 Couchapp/CouchDB 中进行用户注册

    背景 现在 我正在尝试使用 couchDB couchapp 构建一个应用程序 该应用程序将存储来自用户的持久且重要的信息 并且停留在用户使用 couchapp 注册所需的步骤上 本质上 我想做的是有一个简单的注册表单 用户可以使用它来注册
  • 如何与 PHP 设置 WebSocket 安全连接?

    我找不到任何有关在 PHP 中设置 wss 连接的信息 我连接抛出ws没有问题 顺便说一句 我正在使用这个非常棒的库来做到这一点 https github com albeva php websocket 但我的网站使用 https 我需要
  • 设置RadioButton的value属性

    我需要根据从数据库返回的数据构建一个单选按钮列表 每个按钮都需要有一个与之关联的值 我可以根据所选按钮获取该值 理想情况下我只会使用RadioButtonList控件 但是 我需要一个非常自定义的布局RadioButtonList似乎无法处
  • 使用 Avaudioengine iOS 的低通滤波器 + 采样率转换

    我们正在开发一个项目 该项目允许我们使用一些低通滤波器和高通滤波器以 5k Hz 采样率从麦克风录制一些声音 我们正在使用什么 我们正在使用音频引擎以此目的 我们正在使用AVA音频转换器用于降低采样率 我们正在使用AVAudioUnitEQ