AudioKit:调用“AudioKit.stop()”后无法重新启动 AudioKit 频率采样

Posted

技术标签:

【中文标题】AudioKit:调用“AudioKit.stop()”后无法重新启动 AudioKit 频率采样【英文标题】:AudioKit: can't restart AudioKit sampling of frequency after calling 'AudioKit.stop()' 【发布时间】:2020-06-05 22:12:02 【问题描述】:

我正在使用 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)
    


然后我可以这样调用“第二个代码测试”:

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


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

【问题讨论】:

【参考方案1】:

您需要确保 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

【讨论】:

是的,我已经看到将“initMicTracker”放在 startMonitoring 的开头会开始采样(我应该写那个),但我有两个大问题。 1)即使我没有“disconnectAllInputs”也会发生这种情况 2)我尝试使用 XCode“Allocations Profiler”运行这样的程序(如你所建议的那样),每次我调用“startMonitoring”然后“stopMonitoring”内存分配增加...似乎内存中有些东西没有正确释放...这就是为什么我认为即使使用这个解决方案仍然不是正确的方法 如果要创建新实例或使用内存中的内容,您必须重置必须重新初始化的引用。我会将此添加到我的答案中,但我的解决方案只是为了回答原始问题...... 是的,是的,你是对的,我必须写得更好......谢谢你的耐心。我什至尝试停止它们,然后将它们置于停止监视内,但显示的“分配探查器”分配没有增长......(我在上面发布了第二个代码)我已经用我的当前代码更新了我的答案我正在尝试使用。 好吧,这似乎是另外一回事;您必须将 AudioKit 更新到最新版本或至少 4.9.5,然后返回此线程并留下反馈。 我现在已经从audiokit.io/downloads 安装了“AudioKit-macOS-4.9.5”框架,没什么新的,同样的内存问题。

以上是关于AudioKit:调用“AudioKit.stop()”后无法重新启动 AudioKit 频率采样的主要内容,如果未能解决你的问题,请参考以下文章

#AudioKit 播放音序器音频 mp3

是否可以在播放 AudioKit 音序器时修改 MusicSequnce

如何使用 AudioKit 加载第三方音频单元

Audiokit Midi 多个虚拟端口

Swift:声音输出和麦克风输入 |使用 AudioKit |

在 AudioKit 中“重新触发”Midi 音符