swift AVFoundation调整了音频内存问题

时间:2016-06-22 15:20:02

标签: swift audio memory pitch

对于swift和编程,你还是新手。

我有这个功能,以指定的音高播放一段音频。它被一个NStimer调用,所以每秒播放一次。 (包含在SoundPlayer类中的函数,然后是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,并且永远不会重新获得空间。做了一些关于内存泄漏的研究,但找不到任何有助于我的具体情况的东西,所以希望有人可以指出我正确的方向。

我认为这与创建新节点和TimePitch有关,每次调用它时都会将它们移动到包含该函数的类中但是得到了“libc ++ abi.dylib:以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()
    }
}

1 个答案:

答案 0 :(得分:2)

“泄漏”是一种技术性很强的东西:一段永不释放的未引用内存(因为它没有被引用)。我怀疑你有泄漏。你只有越来越多的对象,就是这样。

您反复重复此代码(每次定时器触发时):

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

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

  

我认为这与每次调用

时创建新节点和TimePitch有关

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

想一想你要做什么。你有一个带节点的音频引擎。每次运行时唯一可能改变的是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()

}