2016-06-22 26 views
1

まだ一般的には迅速でプログラミングに新しいです。swift AVFoundationがオーディオメモリの問題を解決しました

私は指定されたピッチでオーディオを再生するこの機能を持っています。 NStimerによって呼び出され、1秒に1回再生されます。 (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() 

} 

それは正常に動作しないと動作しますが、メモリにその呼ばれるたびに、数メガバイトを追加し、決してスペースを取り戻します。メモリリークについていくつかの調査をしましたが、私の特定のシナリオに役立つものを見つけることができなかったので、誰かが私に正しい方向を向けることを望んでいます。

私は、新しいノードとTimePitchを呼び出すたびに関数を含むクラスに移動したが、 "libC++ abi.dylib:NSException型のキャッチされていない例外で終了"サウンドが2回目に再生しようとしたときのエラー。

ありがとうございました。

余分なもの。 (それが参照されていないため)にリリースすることはできません参照されていないメモリの一部: -

// 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

質問がありますか?リークかクラッシュですか? – matt

+0

申し訳ありませんが、漏れが問題です。クラッシュは、漏れを修正しようとして失敗した試みです。 –

+0

どうすれば接続できますか?問題になるだろう。私はリークがあることを確かに知りませんが、私がタイマーを実行するとメモリ使用量は約120MBまで継続的に増加し、クラッシュします。私はAVAudioPlayerを使用していたときにアプリが正常に機能しましたが(ピッチの変更はできません)、この機能が原因です。私は漏れを追跡する方法を知らない、私は楽器を使用しようとしましたが、この段階では私を少し超えていました。私が実際に手伝ってくれなかったコードを指しているようでした。それをXcodeで直接行う方法を知らないでください。助けてくれてありがとう! –

答えて

2

A "漏れ" は、高度な技術のことです。私はあなたに漏れがあるとは思わない。あなたは、ますます多くのオブジェクトを持っているだけです。

あなたは何度も(一回ごとにタイマーがトリガーを)このコードを繰り返しています

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

オーディオエンジン自体は、しかし、あなたの財産として、それは関数の外で宣言されます(場所に残っていますビューコントローラ)。したがって、タイマーが起動するたびに、同じオーディオエンジンに2つのノードを追加します。ノードがメモリを占有するため、メモリが増加し続けます。ここで驚きはありません。もしそれが起こらないようにするなら、それをしないでください。

私はあなたが行くその存在

と呼ばれる新しいノードと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() 

} 
+0

漏れについての私の誤解を解決してくれてありがとう!それは助ける。だから私は問題を理解したが、私の試みた修正はうまくいかなかった!他のものを試してみてください。 –

+0

しかし、あなたはあなたの試行を見せなかったので、あなたはどうしたのか分かりますか?私はあなたがここに従う必要がある戦略を示すために私の答えを改訂しました。 – matt

+0

だから私はこれを試しました..しかし、サウンドは一度だけ(最初のタイマーヒット時に)再生され、メモリの問題はまだそこにあります。 (質問にコードを追加) –

関連する問題