Создайте простой эквалайзер

Я хотел бы сделать 5-полосный звуковой эквалайзер (60 Гц, 230 Гц, 910 Гц, 4 кГц, 14 кГц), используя AVAudioEngine. Я хотел бы, чтобы усиление пользовательского ввода на полосу через вертикальный ползунок и соответственно регулировка воспроизводимого звука. Я пытался использовать 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.

Любая помощь будет принята с благодарностью!

Заранее спасибо.


person Kevin Rajan    schedule 29.05.2017    source источник
comment
Я новичок в avkit, не могли бы вы рассказать мне, как я могу отобразить вывод эквалайзера на экран?   -  person    schedule 21.01.2021


Ответы (1)


Параметры AVAudioUnitEQFilter AVAudioUnitEQFilterParameters Documentation Просматривая документацию, я заметил, что перепутал все параметры, кроме bypass, и кажется, что изменение этого флага все исправило!

Итак, я считаю, что основная проблема здесь заключается в том, что каждая полоса AVAudioUnitEQ не должна быть обойдена предоставленными системными значениями, а не значениями, установленными программистом.

Итак, я изменил

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

to

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

и все стало работать. Кроме того, чтобы сделать эффективный эквалайзер, который позволяет пользователю изменять отдельные частоты, filtertype для каждой полосы следует установить на .parametric.

Я все еще не уверен, на что мне следует установить полосу пропускания, но я, вероятно, могу проверить это в Интернете или просто возиться с этим, пока звук не будет соответствовать другому приложению эквалайзера.

person Kevin Rajan    schedule 29.05.2017
comment
Это было очень полезно... но я также заметил, что вы переназначаете тип фильтра - сначала как параметрический, а затем как lowshelf/highshelf. - person Nerdy Bunz; 06.11.2019
comment
Благодарю вас! Я пытаюсь реализовать грубый метод ReplayGain в своем приложении для macOS. Это приблизило меня, поскольку показало, как получить доступ к свойствам этого класса для globalGain. Теперь мне просто нужно выяснить, как определить максимальное усиление аудиофайла, прежде чем применять глобальное усиление для увеличения или уменьшения усиления. - person SouthernYankee65; 08.06.2020