简体   繁体   English

如何使用Audiokit根据频率调用函数

[英]How to use Audiokit to call a function based on frequency

I've seen that it's possible to use the frequency tracker in a function, but I can't pull it off myself.我已经看到可以在函数中使用频率跟踪器,但我自己无法实现。 There's an example file that can display frequency, but I haven't found anything that calls a function when the tracker hits a certain frequency.有一个可以显示频率的示例文件,但我没有找到任何在跟踪器达到某个频率时调用函数的内容。

I'm trying to call the AKAudioPlayer.pause() function when the Frequency drops below 40hz.当频率低于 40hz 时,我试图调用AKAudioPlayer.pause()函数。 I edited a test .mp3 file so that there is a section of 32hz in the audio file.我编辑了一个测试 .mp3 文件,以便音频文件中有 32hz 的部分。 I can even see on the frequency tracker text, that the tracker is reading the 32 hz, but I don't have any success in getting it to pause, even when I write the function to be dependent on this text.我什至可以在频率跟踪器文本上看到,跟踪器正在读取 32 hz,但我没有成功让它暂停,即使我编写了依赖于此文本的函数。

This is a modified version of the microphone tracker, for tracking an audio file.是麦克风跟踪器的修改版本,用于跟踪音频文件。

I receive the error: "Unexpectedly found nil while unwrapping an Optional value" both when trying to form the function directly with the tracker.frequency value, and when using a variable, converted to a string based off of the tracker.frequency.我收到错误:“在解包可选值时意外发现 nil”,无论是在尝试直接使用 tracker.frequency 值形成函数时,还是在使用变量时,转换为基于 tracker.frequency 的字符串。

This leads me to believe that the tracker frequency is my problematic nil optional value and to the conclusion that, that's what brings the whole thing down in flames.这让我相信跟踪器频率是我有问题的 nil 可选值,并得出结论,这就是让整个事情陷入困境的原因。 But I can't figure out what to do about it.但我不知道该怎么做。 I know there is a function that works to display the frequency, but I can't recreate its success.我知道有一个函数可以显示频率,但我无法重现它的成功。

In the below code (mostly an Audiokit example file) I've tried to use the Tracker.Frequency to trigger the pause function:在下面的代码(主要是 Audiokit 示例文件)中,我尝试使用 Tracker.Frequency 来触发暂停功能:

import AudioKit
import AudioKitUI
import UIKit


class ViewController: UIViewController {

    @IBOutlet private var frequencyLabel: UILabel!
    @IBOutlet private var amplitudeLabel: UILabel!
    @IBOutlet private var noteNameWithSharpsLabel: UILabel!
    @IBOutlet private var noteNameWithFlatsLabel: UILabel!
    @IBOutlet private var audioInputPlot: EZAudioPlot!


    @IBAction func Play(_ sender: Any) {

        if input.isStarted == false
        {
            input.play()
        }
    }


    @IBAction func Pause(_ sender: Any)
    {

        if input.isStarted
        {
            input.pause()
        }

    }



    var input: AKAudioPlayer!
    var song = try! AKAudioFile(readFileName: "TEST.mp3")// ... the error is here

    var tracker: AKFrequencyTracker!
    var silence: AKBooster!

    let noteFrequencies = [16.35, 17.32, 18.35, 19.45, 20.6, 21.83, 23.12, 24.5, 25.96, 27.5, 29.14, 30.87]
    let noteNamesWithSharps = ["C", "C♯", "D", "D♯", "E", "F", "F♯", "G", "G♯", "A", "A♯", "B"]
    let noteNamesWithFlats = ["C", "D♭", "D", "E♭", "E", "F", "G♭", "G", "A♭", "A", "B♭", "B"]

    func setupPlot() {
        let plot = AKNodeOutputPlot(input, frame: audioInputPlot.bounds)
        plot.plotType = .rolling
        plot.shouldFill = true
        plot.shouldMirror = true
        plot.color = UIColor.blue
        audioInputPlot.addSubview(plot)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
          pauseOnQueue()

        AKSettings.audioInputEnabled = true
        do {input = try AKAudioPlayer(file: song)}
            catch {print("ERROR")}
        tracker = AKFrequencyTracker(input)
        silence = AKBooster(tracker, gain: 1)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        AudioKit.output = silence
        AudioKit.start()
        setupPlot()


        Timer.scheduledTimer(timeInterval: 0.1,
                             target: self,
                             selector: #selector(ViewController.updateUI),
                             userInfo: nil,
                             repeats: true)
    }




    @objc func updateUI() {
        if tracker.amplitude > 0.1 {
            frequencyLabel.text = String(format: "%0.1f", tracker.frequency)

            var frequency = Float(tracker.frequency)
            while frequency > Float(noteFrequencies[noteFrequencies.count - 1]) {
                frequency /= 2.0
            }
            while frequency < Float(noteFrequencies[0]) {
                frequency *= 2.0
            }

            var minDistance: Float = 10_000.0
            var index = 0

            for i in 0..<noteFrequencies.count {
                let distance = fabsf(Float(noteFrequencies[i]) - frequency)
                if distance < minDistance {
                    index = i
                    minDistance = distance
                }
            }
            let octave = Int(log2f(Float(tracker.frequency) / frequency))
            noteNameWithSharpsLabel.text = "\(noteNamesWithSharps[index])\(octave)"
            noteNameWithFlatsLabel.text = "\(noteNamesWithFlats[index])\(octave)"
        }
        amplitudeLabel.text = String(format: "%0.2f", tracker.amplitude)
    }

    func pauseOnQueue() {

        frequencyLabel.text = String(format: "%0.1f", tracker.frequency)

        let frequency = Float(tracker.frequency)


        if  frequency < 50 && frequency > 20  && input.isStarted == true

        { input.pause() }

    }

    }

I've answered a similar question here: AudioKit (iOS) - Add observer for frequency / amplitude change我在这里回答了一个类似的问题: AudioKit (iOS) - 添加频率/幅度变化的观察者

There's a decision that you have to make about how you want to detect this frequency - is it something that happens fast and needs to be in the DSP code or can you just poll for frequency at semi-regular intervals from Swift.您必须决定如何检测此频率 - 它是否发生得很快并且需要在 DSP 代码中,或者您是否可以从 Swift 中以半规则间隔轮询频率。

I don't think you should add !s to the AudioKit node definitions because they might not exist at the time you're expecting them to even though it seems like it should from the view controller life cycle.我认为您不应该将 !s 添加到 AudioKit 节点定义中,因为它们可能在您期望它们时不存在,即使它看起来应该来自视图控制器生命周期。 In general, don't rely on view controller code to controller your audio.通常,不要依赖视图控制器代码来控制音频。 Perhaps put all the audio related stuff in a singleton and let it manage itself?也许将所有与音频相关的东西放在一个单例中并让它自行管理?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM