4

我正在尝试播放具有不同效果的声音。在之前的 viewController 中我录制了一个声音,然后在下一个屏幕中,可以播放效果。第一次它工作正常,但第二次它崩溃并出现如下错误:

2015-08-07 13:00:45.900 Pitch Perfect[9643:1121173] 13:00:45.900 错误:AVAudioEngine.mm:253:AttachNode:所需条件为假:!nodeimpl->HasEngineImpl() 2015-08-07 13 :00:45.953 Pitch Perfect [9643:1121173]由于未捕获的异常'com.apple.coreaudio.avfaudio'而终止应用程序,原因:'必需条件为假:!nodeimpl->HasEngineImpl()'

import UIKit
import AVFoundation

class PlaySoundsViewController: UIViewController, AVAudioPlayerDelegate {

    var receivedAudio:RecordedAudio!
    var audioPlayer: AVAudioPlayer!
    var disabledButton:UIButton!
    var firstTime:Bool = true

    var audioEngine:AVAudioEngine!
    var audioFile:AVAudioFile!
    var audioPlayerNode:AVAudioPlayerNode!

    var audioStopped:Bool!
    var typeOfSound:IntegerLiteralType!


    @IBOutlet weak var stopButton: UIButton!

    @IBOutlet weak var reverbButton: UIButton!

    @IBOutlet weak var echoButton: UIButton!

    @IBOutlet weak var darthButton: UIButton!

    @IBOutlet weak var chipmonkButton: UIButton!

    @IBOutlet weak var snailButton: UIButton!

    @IBOutlet weak var rabbitButton: UIButton!



    override func viewDidLoad() {
        super.viewDidLoad()

        audioPlayer = AVAudioPlayer(contentsOfURL: receivedAudio.filePathUrl, error: nil)
        audioPlayer.enableRate=true
        audioPlayer.delegate=self

        var session = AVAudioSession.sharedInstance()
        session.setCategory(AVAudioSessionCategoryPlayback, error: nil)
        audioPlayerNode=AVAudioPlayerNode();
        audioEngine = AVAudioEngine()
        audioFile = AVAudioFile(forReading: receivedAudio.filePathUrl, error: nil)
        audioStopped=true;


    }

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

    func playAnimalSound(animal: String) {
        if audioStopped==false {
            resetAudio(typeOfSound)
        }
        typeOfSound = 1
        audioPlayer.currentTime=0

        switch animal {
            case "snail":
                audioPlayer.rate=0.5
            case "rabbit":
                 audioPlayer.rate=2.0
        default:
            showMessage("Sound not found. How can it be?")
        }

        audioPlayer.play()
        stopButton.hidden=false
        stopButton.enabled=true

    }



    @IBAction func playSnailSound(sender: UIButton) {
        highlightButton(sender)
       playAnimalSound("snail")
    }

    @IBAction func playRabbitSound(sender: UIButton) {
        highlightButton(sender)
        playAnimalSound("rabbit")
    }

    func soundEnded() {
        stopButton.hidden=true
        disabledButton.enabled=true;
        if(audioEngine.running) {
            audioEngine.stop()
            audioEngine.reset();
        }

    }


    func playAudioWithVariablePitch(pitch: Float, type: String) {
        if audioStopped==false {
             resetAudio(typeOfSound)
        }

        audioEngine.attachNode(audioPlayerNode)


        switch type {
        case "normal":
             typeOfSound = 2
            var changePitchEffect = AVAudioUnitTimePitch()
            changePitchEffect.pitch = pitch
            audioEngine.attachNode(changePitchEffect)

            audioEngine.connect(audioPlayerNode, to: changePitchEffect, format: nil)
            audioEngine.connect(changePitchEffect, to: audioEngine.outputNode, format: nil)

        case "reverb":
             typeOfSound = 3
            var changeReverbEffect = AVAudioUnitReverb()
            changeReverbEffect.loadFactoryPreset(AVAudioUnitReverbPreset(rawValue: 4)!)
            changeReverbEffect.wetDryMix=50;
            audioEngine.attachNode(changeReverbEffect)

            audioEngine.connect(audioPlayerNode, to: changeReverbEffect, format: nil)
            audioEngine.connect(changeReverbEffect, to: audioEngine.outputNode, format: nil)

        case "delay":
             typeOfSound = 3
            var changeDelayEffect = AVAudioUnitDelay()
            audioEngine.attachNode(changeDelayEffect)

            audioEngine.connect(audioPlayerNode, to: changeDelayEffect, format: nil)
            audioEngine.connect(changeDelayEffect, to: audioEngine.outputNode, format: nil)
        default:
            showMessage("oops, there was an internal problem. Never mind")

        }


       audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: soundEnded)
        audioEngine.startAndReturnError(nil)
        stopButton.hidden=false
        stopButton.enabled=true
        audioPlayerNode.play()


    }



    func audioPlayerDidFinishPlaying(player: AVAudioPlayer!, successfully flag: Bool) {
        if flag {
            stopButton.hidden=true
            disabledButton.enabled=true;
            audioStopped=true
            println("I hid stopButton and enabled the disabled one")

        }

    }



    @IBAction func playDelaySound(sender: UIButton) {
        highlightButton(sender)
        playAudioWithVariablePitch(0, type: "delay")

    }


    @IBAction func playReverbSound(sender: UIButton) {
        highlightButton(sender)
        playAudioWithVariablePitch(0, type: "reverb")

    }

    @IBAction func playChipmunkSound(sender: UIButton) {
        highlightButton(sender)
        playAudioWithVariablePitch(1000.0, type: "normal")

    }

    @IBAction func playDarthVaderSound(sender: UIButton) {
        highlightButton(sender)
        playAudioWithVariablePitch(-900.0, type: "normal")

    }

    @IBAction func stopPlaying(sender: UIButton) {
        resetAudio(typeOfSound)
        stopButton.hidden=true
        stopButton.enabled=false;
        disabledButton.enabled=true;
    }

    func highlightButton(button: UIButton) {
        if firstTime {
            firstTime=false
        } else {
            disabledButton.enabled=true;
        }
        button.enabled=false;
        disabledButton=button;

    }

    func resetAudio(type: IntegerLiteralType) {
        switch type {
        case 1 :
            audioPlayer.stop()
            println("case 1")
        case 2 :
            println("case 2")
            if audioEngine.running {
                audioEngine.stop()
            }
            audioEngine.reset()
        case 3 :
             audioEngine.stop()

        default:
            break
        }

        audioStopped=true;

    }

    func showMessage(msg: String) {
        var message=UIAlertView(title: "Alert", message: msg, delegate: nil, cancelButtonTitle: "ok I won't panic")
    }


}

有人知道为什么会崩溃吗?我研究了 AVAudioEngine、AVAudioPlayer 和 AVAudioPlayerNode 类,但没有任何结果。

谢谢

4

4 回答 4

13

我知道这是一个老问题,但我没有看到上面的正确答案。

错误消息中实际上概述了它崩溃的原因:

AttachNode:所需条件为假:!nodeimpl->HasEngineImpl()

换句话说,在附加节点时,该节点必须尚未附加到引擎(!nodeimpl->HasEngineImpl())。

audioEngine.detachNode解决方案是在尝试再次添加之前删除使用的节点。

于 2016-11-23T14:04:34.483 回答
3

最后崩溃是由于在 viewDidLoad 函数中初始化 audioPlayerNode 和 audioEngine 对象引起的。显然,每次使用它们时,或者可能在停止和重置之后,它们都需要实例化。将这些行直接放在 playAudioWithVariablePitch 函数的开头而不是在 viewDidLoad 函数中,解决了崩溃问题。我仍然对音高、混响和回声的播放有问题。他们在到期之前就被削减了,我仍然不知道为什么。它与 audioPlayerNode.scheduleFile 方法的完成处理程序有关。

于 2015-08-07T18:06:56.633 回答
1

就我而言,我的计时器一次又一次地调用,这段代码写在我的计时器中

self.recognitionTask?.finish()
node.removeTap(onBus: 0)
self.request.endAudio()

self.recognitionTask = nil
//Maybe this line was causing the issue
self.audioEngine.stop()

因此,如果您已经停止了请求,移除了水龙头并停止了引擎,那么不应再次调用这些行。

希望这对某人有帮助

于 2018-08-17T11:03:04.890 回答
0

播放可变音高效果后,您似乎正在重置引擎。

func soundEnded() {
    stopButton.hidden=true
    disabledButton.enabled=true;
    if(audioEngine.running) {
        audioEngine.stop()
        audioEngine.reset();
    }
}

audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: soundEnded)
audioEngine.startAndReturnError(nil)
stopButton.hidden=false
stopButton.enabled=true
audioPlayerNode.play()

因此,在添加节点和链接链的情况下,尚未再次设置引擎。当您尝试播放 playerNode 时,它​​会崩溃。

于 2015-08-07T11:21:20.980 回答