构建一个简单的均衡器

Posted

技术标签:

【中文标题】构建一个简单的均衡器【英文标题】:Build a simple Equalizer 【发布时间】:2017-10-29 12:23:04 【问题描述】:

我想使用AVAudioEngine 制作一个 5 频段音频均衡器(60Hz、230Hz、910Hz、4kHz、14kHz)。我希望通过垂直滑块让用户输入每个频段的增益,并相应地调整正在播放的音频。我尝试使用AVAudioUnitEQ 来执行此操作,但在播放音频时我听不到任何区别。我试图硬编码值以指定每个频率的增益,但它仍然不起作用。这是我的代码:

var audioEngine: AVAudioEngine = AVAudioEngine()
var equalizer: AVAudioUnitEQ!
var audioPlayerNode: AVAudioPlayerNode = AVAudioPlayerNode()
var audioFile: AVAudioFile!

// in viewDidLoad():
equalizer = AVAudioUnitEQ(numberOfBands: 5)
audioEngine.attach(audioPlayerNode)
audioEngine.attach(equalizer)
let bands = equalizer.bands
let freqs = [60, 230, 910, 4000, 14000]
audioEngine.connect(audioPlayerNode, to: equalizer, format: nil)
audioEngine.connect(equalizer, to: audioEngine.outputNode, format: nil)
for i in 0...(bands.count - 1) 
    bands[i].frequency = Float(freqs[i])


bands[0].gain = -10.0
bands[0].filterType = .lowShelf
bands[1].gain = -10.0
bands[1].filterType = .lowShelf
bands[2].gain = -10.0
bands[2].filterType = .lowShelf
bands[3].gain = 10.0
bands[3].filterType = .highShelf
bands[4].gain = 10.0
bands[4].filterType = .highShelf

do 
    if let filepath = Bundle.main.path(forResource: "song", ofType: "mp3") 
        let filepathURL = NSURL.fileURL(withPath: filepath)
        audioFile = try AVAudioFile(forReading: filepathURL)
        audioEngine.prepare()
        try audioEngine.start()
        audioPlayerNode.scheduleFile(audioFile, at: nil, completionHandler: nil)
        audioPlayerNode.play()
    
 catch _ 

由于低频的增益为 -10,高频的增益为 10,因此在播放任何媒体时应该会有非常明显的差异。但是,当媒体开始播放时,听起来就像没有连接任何均衡器一样播放。

我不确定为什么会发生这种情况,但我尝试了几种不同的方法进行调试。我认为这可能是函数的顺序,所以我尝试切换它,以便在调整所有频段后调用 audioEngine.connect,但这也没有任何区别。

我使用AVAudioUnitTimePitch 尝试了相同的代码,它运行良好,所以我对为什么它不能与AVAudioUnitEQ 一起使用感到目瞪口呆。

我不想在这个项目中使用任何第三方库或可可豆荚,我想单独使用AVFoundation

任何帮助将不胜感激!

提前致谢。

【问题讨论】:

我是 avkit 新手,您能告诉我如何在屏幕上显示均衡器的输出吗? 【参考方案1】:

AVAudioUnitEQFilterParameters 查看文档,我注意到除了bypass 之外的所有参数我都弄乱了,似乎更改此标志可以解决所有问题!

所以,我认为这里的主要问题是每个 AVAudioUnitEQ 频段不能被提供的系统值而不是程序员设置的值绕过。

所以,我改变了

for i in 0...(bands.count - 1) 
    bands[i].frequency = Float(freqs[i])

for i in 0...(bands.count - 1) 
    bands[i].frequency  = Float(freqs[i])
    bands[i].bypass     = false
    bands[i].filtertype = .parametric

一切都开始工作了。此外,要制作允许用户修改各个频率的有效均衡器,每个频段的filtertype 应设置为.parametric

我仍然不确定我应该将带宽设置为什么,但我可能可以在网上检查一下,或者只是弄乱它,直到声音与不同的均衡器应用程序匹配。

【讨论】:

这非常有用...但我也注意到您正在重新分配过滤器类型 - 首先是参数,然后是低架/高架。 谢谢!我正在尝试在我的 macOS 应用程序中实现一个总的 ReplayGain 方法。这让我更接近了,因为它向我展示了如何访问这个类的 globalGain 属性。现在我只需要弄清楚如何在应用全局增益来增加或减少增益之前确定音频文件的最大增益。

以上是关于构建一个简单的均衡器的主要内容,如果未能解决你的问题,请参考以下文章

Ambassador 部署过程和简单使用

如何为 iPhone 制作一个简单的音频均衡器?

使用 Go 语言徒手撸一个简单的负载均衡器

Haproxy 构建负载均衡集群

使用 HaProxy 制作一个简单的负载均衡器

使用 HaProxy 制作一个简单的负载均衡器