AudioKit:调用后无法重启 AudioKit 频率采样 'AudioKit.stop()'

AudioKit: can't restart AudioKit sampling of frequency after calling 'AudioKit.stop()'

我正在使用 AudioKit 4.10。 我使用这个简单的代码从麦克风采样频率和振幅:

import AudioKit

protocol MicAnalyzerDelegate {
    /**
     * The MicAnalyzer calls this delegate function.
     */
    func micAnalyzerInfos(infos: (frequency : Double, amplitude : Double)?)
}

class MicAnalyzer: NSObject {

    // MARK: - Properties
    private static var micAnalyzer: MicAnalyzer = MicAnalyzer()
    var delegate: MicAnalyzerDelegate?

    fileprivate var mic: AKMicrophone!
    fileprivate var tracker: AKFrequencyTracker!
    fileprivate var silence: AKBooster!
    fileprivate var timer: Timer?

    // MARK: - Initializations
    private override init() {
        super.init()
        AKSettings.audioInputEnabled = true
        self.initMicTracker()
    }

    private func initMicTracker(){
        /* Add the built-in microphone. */
        mic = AKMicrophone()
        /* Add a traker */
        tracker = AKFrequencyTracker(mic)
        silence = AKBooster(tracker, gain: 0)
    }

    // MARK: - Accessors
    class func shared() -> MicAnalyzer {
        return micAnalyzer
    }

    func startMonitoring() {
        /* Start the microphone and analyzer. */
        AudioKit.output = silence
        do {
            try AudioKit.start()
        } catch {
            AKLog("AudioKit did not start!")
        }

        /* Initialize and schedule a new run loop timer. */
        timer = Timer.scheduledTimer(timeInterval: 0.1,
                                     target: self,
                                     selector: #selector(MicAnalyzer.tick),
                                     userInfo: nil,
                                     repeats: true)
    }

    // Stopped as described here: https://github.com/AudioKit/AudioKit/issues/1716
    func stopMonitoring() {
        do {
            AudioKit.disconnectAllInputs()
            try AudioKit.stop()
            try AudioKit.shutdown()
        } catch {
            print("AudioKit did not stop")
        }
        AudioKit.output = nil

        // Interrupts polling on tick infos
        timer?.invalidate()
        timer = nil
    }

    var infos: (frequency : Double, amplitude : Double)? {
        if(!tracker.isStopped){
            let frequency = tracker.frequency
            let amplitude = tracker.amplitude

            return (frequency: frequency, amplitude: amplitude)
        } else {
            return nil
        }
    }


    /* Call the delegate. */
    @objc func tick() {
        self.delegate?.micAnalyzerInfos(infos: infos)
    }

}

按顺序调用以下代码我遇到了这种情况:

MicAnalyzer.shared().startMonitoring() // --> Everything works good
MicAnalyzer.shared().stopMonitoring()  // --> I think it is stopped correctly
MicAnalyzer.shared().startMonitoring() // --> From now on the delegate is called but I get always 0 as frequency and amplitude

为什么在调用AudioKit.start()(在MicAnalyzer.shared().startMonitoring()内)后我不能再采样频率和振幅了?我应该如何重新开始整个事情?


如果我每次重新启动变量 mictrackersilence,内存就会增长,因为它们并没有真正被释放。 这是相同代码思路的第二个版本:

import AudioKit

protocol MicAnalyzerDelegate : class {
    /**
     * The tuner calls this delegate function 
     */
    func micAnalyzerInfos(infos: (frequency : Double, amplitude : Double)?)
}

// https://audiokit.io/examples/MicrophoneAnalysis/
class MicAnalyzer: NSObject {

    // MARK: - Properties
    private weak var delegate: MicAnalyzerDelegate?

    fileprivate var mic: AKMicrophone!
    fileprivate var tracker: AKFrequencyTracker!
    fileprivate var silence: AKBooster!
    fileprivate var timer: Timer?

    // MARK: - Initializations
    init(delegate: MicAnalyzerDelegate) {
        print("Init called!!!")
        self.delegate = delegate
        super.init()
    }

    deinit {
        print("Deinit called!!!")
    }

    // MARK: - Accessors
    func startMonitoring() {
        AKSettings.audioInputEnabled = true
        /* Add the built-in microphone. */
        mic = AKMicrophone()
        /* Add a traker */
        tracker = AKFrequencyTracker(mic)
        silence = AKBooster(tracker, gain: 0)

        /* Start the microphone and analyzer. */
        AudioKit.output = silence
        do {
            try AudioKit.start()
        } catch {
            AKLog("AudioKit did not start!")
        }

        /* Initialize and schedule a new run loop timer. */
        timer = Timer.scheduledTimer(timeInterval: 1,
                                     target: self,
                                     selector: #selector(MicAnalyzer.tick),
                                     userInfo: nil,
                                     repeats: true)
    }

    func stopMonitoring() {
        do {
            AudioKit.disconnectAllInputs()
            try AudioKit.stop()
            try AudioKit.shutdown()
        } catch {
            print("AudioKit did not stop")
        }
        AudioKit.output = nil

        // Interrupts polling on tick infos
        timer?.invalidate()
        timer = nil

        silence.stop()
        silence = nil
        tracker.stop()
        tracker = nil
        mic.stop()
        mic = nil
    }

    var infos: (frequency : Double, amplitude : Double)? {
        if(!tracker.isStopped){
            let frequency = tracker.frequency
            let amplitude = tracker.amplitude

            return (frequency: frequency, amplitude: amplitude)
        } else {
            return nil
        }
    }

    /* Call the delegate. */
    @objc func tick() {
        print(infos?.frequency ?? "0.0")
        //self.delegate.micAnalyzerInfos(infos: infos)
    }

}

然后我可以按顺序调用 'second code test':

override func viewDidAppear() {
    super.viewDidAppear()
    print("viewDidAppear!!!")
    tuner = Tuner(delegate: self)
    tuner?.startMonitoring()
}

override func viewDidDisappear() {
    super.viewDidDisappear()
    print("viewDidDisappear!!!")
    tuner?.stopMonitoring()
    tuner = nil
}

您需要确保 AKFrequencyTracker 是信号链的一部分,因为这是 AVAudioEngine 引擎的要求。

这意味着如果你这样做:

do {
    AudioKit.disconnectAllInputs()
    try AudioKit.stop()
    try AudioKit.shutdown()
} catch {
   // error handler
}

AudioKit.output = nil

您必须调用 initMicTracker 才能使 AKFrequencyTracker 回到信号链中。因此,要重新启动,您需要执行以下操作:

  • initMicTracker
  • 开始监控

因为您的 stopMonitoring 做了:

  • AudioKit.disconnectAllInputs(),即(stop)MicTracker

您知道您已经为 AKMicrophoneAKFrequencyTrackerAKBooster 创建了实例,将其从内存中释放出来

func stopMonitoring() {
    ...

    self.mic = nil
    self.tracker = nil
    self.silence = nil
}