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()
}
你好,对 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()
}