重置 AVAudioEngine

Reset AVAudioEngine

我正在创建一个基本的音板应用程序。我有两个开关。一种激活后会使音频变慢和降低音调,另一种使其变快和变高。我有一个 if else if if 语句查看这些开关然后相应地播放音频,但是当我尝试第二次按下它时,无论是相同的声音还是不同的声音声音,它崩溃了。

我大约 99% 确定这是由于 AVAudioEngine 需要重置或节点本身重置所致,但我已经超出了我的范围。我搜索过高音和低音,但我找到的答案似乎与使用不同按钮发出高音或低音时重置播放器有关。有什么想法吗?

class ViewController: UIViewController {

@IBOutlet weak var sassSwitch: UISwitch!
@IBOutlet weak var chipSwitch: UISwitch!

@IBAction func sassAction(_ sender: UISwitch) {
    chipSwitch.setOn(false, animated: true)
}
@IBAction func chipSwitch(_ sender: UISwitch) {
    sassSwitch.setOn(false, animated: true)
}


///Playback Engine
private let audioEngine = AVAudioEngine()

///Player's Nodes
private let pitchPlayer = AVAudioPlayerNode()
private let timePitch = AVAudioUnitTimePitch()

///Audio Files to be played
private var audioFile1 = AVAudioFile()
private var audioFile2 = AVAudioFile()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    if let filePath = Bundle.main.path(forResource: "PeteNope", ofType:
        "mp3") {
        let filePathURL = URL(fileURLWithPath: filePath)

        setPlayerFile(filePathURL)

    }

    if let filePath2 = Bundle.main.path(forResource: "Law_WOW", ofType:
        "mp3") {
        let filePath2URL = URL(fileURLWithPath: filePath2)

        setPlayerFile2(filePath2URL)

    }
}

private func setPlayerFile(_ fileURL: URL) {
    do {
        let file = try AVAudioFile(forReading: fileURL)

        self.audioFile1 = file


    } catch {
        fatalError("Could not create AVAudioFile instance. error: \(error).")
    }
}

private func setPlayerFile2(_ fileURL: URL) {
    do {
        let file = try AVAudioFile(forReading: fileURL)

        self.audioFile2 = file


    } catch {
        fatalError("Could not create AVAudioFile instance. error: \(error).")
    }
}


@IBAction func sound1Play(_ sender: UIButton) {
    if sassSwitch.isOn {
        timePitch.pitch = -300
        timePitch.rate = 0.5
        audioEngine.attach(pitchPlayer)
        audioEngine.attach(timePitch)

        audioEngine.connect(pitchPlayer, to: timePitch, format: audioFile1.processingFormat)
        audioEngine.connect(timePitch, to: audioEngine.outputNode, format: audioFile1.processingFormat)
        pitchPlayer.scheduleFile(audioFile1, at: nil, completionHandler: nil)

        // Start the engine.
        do {
            try audioEngine.start()
        } catch {
            fatalError("Could not start engine. error: \(error).")
        }

        pitchPlayer.play()

    } else if chipSwitch.isOn {
        timePitch.pitch = +500
        timePitch.rate = 2.0
        audioEngine.attach(pitchPlayer)
        audioEngine.attach(timePitch)

        audioEngine.connect(pitchPlayer, to: timePitch, format: audioFile1.processingFormat)
        audioEngine.connect(timePitch, to: audioEngine.outputNode, format: audioFile1.processingFormat)
        pitchPlayer.scheduleFile(audioFile1, at: nil, completionHandler: nil)

        // Start the engine.
        do {
            try audioEngine.start()
        } catch {
            fatalError("Could not start engine. error: \(error).")
        }

        pitchPlayer.play()

    } else {
        timePitch.pitch = +0
        timePitch.rate = 1.0
        audioEngine.attach(pitchPlayer)
        audioEngine.attach(timePitch)

        audioEngine.connect(pitchPlayer, to: timePitch, format: audioFile1.processingFormat)
        audioEngine.connect(timePitch, to: audioEngine.outputNode, format: audioFile1.processingFormat)
        pitchPlayer.scheduleFile(audioFile1, at: nil, completionHandler: nil)

        // Start the engine.
        do {
            try audioEngine.start()
        } catch {
            fatalError("Could not start engine. error: \(error).")
        }
        pitchPlayer.play()
    }

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


}

看来您可能只需要将 attachconnectengine.start 函数移出 sound1Play 函数,并将它们放入 viewDidLoad 中。目前您正在连接节点的每个动作,并多次重新启动引擎。