对于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()
}
}
答案 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()
}