swift AVFoundation 音调音频内存问题

swift AVFoundation pitched audio memory issue

你好,对 swift 和一般的编程还是陌生的。

我有这个功能可以以指定的音高播放一段音频。它被 NStimer 调用,所以每秒播放一次。 (函数包含在 SoundPlayer class 中,然后是 NStimer 设置并在 viewController 中使用)

func playPitchedAudio(audioFile: AVAudioFile, pitch: Float){
    audioEngine.stop()
    audioEngine.reset()

    let audioPlayerNode = AVAudioPlayerNode()
    let changePitchEffect = AVAudioUnitTimePitch()

    changePitchEffect.pitch = pitch

    audioEngine.attachNode(audioPlayerNode)
    audioEngine.attachNode(changePitchEffect)

    audioEngine.connect(audioPlayerNode, to: changePitchEffect, format: nil)

    audioEngine.connect(changePitchEffect, to: audioEngine.outputNode, format: nil)

    audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: nil)

    do {
        try audioEngine.start()
    } catch {
        print("error")
    }

    audioPlayerNode.play()

}

它运行良好并且工作正常,但每次调用时都会增加几 mb 的内存并且永远不会重新获得 space。对内存泄漏进行了一些研究,但找不到任何对我的特定情况有帮助的东西,所以希望有人能指出我正确的方向。

我认为这与每次调用时创建一个新节点和 TimePitch 有关,因此将它们移动到包含该函数的 class 中,但当声音尝试播放时出现 "libc++abi.dylib: terminating with uncaught exception of type NSException" 错误第二次玩

非常感谢任何帮助,谢谢!

额外的东西。

// defined in class to be used by function
var pitchedAudioPlayer = AVAudioPlayerNode()
var audioEngine = AVAudioEngine()

//Timer Start 
self.timer.invalidate()
self.timer = NSTimer.scheduledTimerWithTimeInterval(tempo, target: self,     selector: #selector(ViewController.timeTriggerPointer), userInfo: nil, repeats: true)

//Timer calls... (along with some other unrelated stuff)
func timeTriggerPointer() {
    soundPlayer.playPitchedAudio(pitchFilePath, pitch: -1000.0)
}

解决方案 -

import AVFoundation

class SoundPlayer {
    var pitchedAudioPlayer = AVAudioPlayerNode()
    var audioEngine = AVAudioEngine()

    let audioPlayerNode = AVAudioPlayerNode()
    let changePitchEffect = AVAudioUnitTimePitch()

    init() {
        audioEngine.attachNode(audioPlayerNode)
        audioEngine.attachNode(changePitchEffect)

        audioEngine.connect(audioPlayerNode, to: changePitchEffect, format: nil)
        audioEngine.connect(changePitchEffect, to: audioEngine.outputNode, format: nil)
    }

    func playPitchedAudio(audioFile: AVAudioFile, pitch: Float){
        audioPlayerNode.stop()

        changePitchEffect.pitch = pitch

        audioPlayerNode.scheduleFile(audioFile, atTime: nil,     completionHandler: nil)



        do {
            try audioEngine.start()
        } catch {
            print("error")
        }

        audioPlayerNode.play()
    }
}

A "leak" 是一个技术含量很高的东西:一块永远无法释放的未引用内存(因为它是未引用的)。我怀疑你有泄漏。你只是有越来越多的对象,仅此而已。

您一遍又一遍地重复此代码(每次计时器触发一次):

let audioPlayerNode = AVAudioPlayerNode()
let changePitchEffect = AVAudioUnitTimePitch()
audioEngine.attachNode(audioPlayerNode)
audioEngine.attachNode(changePitchEffect)

然而,音频引擎本身仍然存在(它在函数外部声明,作为视图控制器的 属性)。因此,每次计时器触发时,您都会向同一个音频引擎添加两个节点。节点占用内存,所以你的内存不断上升。这里不足为奇。如果您不希望发生这种情况,请不要那样做。

I assumed it was something to do with creating a new node and TimePitch everytime its called

给你。所以你已经解决了你自己的问题。

想一想您要做什么。您有一个带节点的音频引擎。每个 运行 上唯一可能改变的是 AVAudioUnitTimePitch 节点的音高和要播放的文件。因此,请事先创建整个音频引擎和节点,并将其留在原地。将 AVAudioUnitTimePitch 的引用保留为 属性。在计时器功能中,只需更改音高值即可!

let theTimePitchNode = AVAudioUnitTimePitch()
// and you have also added that node to the engine in your setup
func playPitchedAudio(audioFile: AVAudioFile, pitch: Float){

    audioPlayerNode.stop()

    theTimePitchNode.pitch = pitch
    audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: nil)

    do {
        try audioEngine.start()
    } catch {
        print("error")
    }

    audioPlayerNode.play()

}