简体   繁体   中英

AudioKit crashes

I'm trying to create an app that:

  1. Records my microphone and saves the output to a file
  2. Plays the last recorded file
  3. The playback should be manipulated with effects such as pitch-shift

So far I've got 1+2 down, but when I try to assign the AudioKit.output to my timePitch (or PitchShifter for that matter), I get an exception (see below). Can anyone help me out? Seems like if I set output to anything else than player, it crashes..

Disclaimer: I'm new to Swift, so please go easy on me and forgive my bad code

2017-11-08 16:39:58.637075+0100 mysoundplayer[41113:759865] *** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'player started when in a disconnected state'
*** First throw call stack:
(
    0   CoreFoundation                      0x0000000108a3c1ab __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x00000001047ddf41 objc_exception_throw + 48
    2   CoreFoundation                      0x0000000108a41372 +[NSException raise:format:arguments:] + 98
    3   AVFAudio                            0x000000010b3bb00e _Z19AVAE_RaiseExceptionP8NSStringz + 158
    4   AVFAudio                            0x000000010b4131ce _ZN21AVAudioPlayerNodeImpl9StartImplEP11AVAudioTime + 204
    5   AVFAudio                            0x000000010b412482 -[AVAudioPlayerNode playAtTime:] + 82
    6   AudioKit                            0x0000000103a2270d _T08AudioKit13AKAudioPlayerC4playySo11AVAudioTimeCSg2at_tFTf4gn_n + 1933
    7   AudioKit                            0x0000000103a1c78d _T08AudioKit13AKAudioPlayerC5startyyF + 45
    8   mysoundplayer                          0x00000001035dd3b8 _T010mysoundplayer14ViewControllerC14playLoadedFileyyF + 1832
    9   mysoundplayer                          0x00000001035dca1e _T010mysoundplayer14ViewControllerC4playySo8UIButtonCF + 46
    10  mysoundplayer                          0x00000001035dca6c _T010mysoundplayer14ViewControllerC4playySo8UIButtonCFTo + 60
    11  UIKit                               0x000000010507c275 -[UIApplication sendAction:to:from:forEvent:] + 83
    12  UIKit                               0x00000001051f94a2 -[UIControl sendAction:to:forEvent:] + 67
    13  UIKit                               0x00000001051f97bf -[UIControl _sendActionsForEvents:withEvent:] + 450
    14  UIKit                               0x00000001051f81e7 -[UIControl touchesBegan:withEvent:] + 282
    15  UIKit                               0x00000001050f1916 -[UIWindow _sendTouchesForEvent:] + 2130
    16  UIKit                               0x00000001050f32de -[UIWindow sendEvent:] + 4124
    17  UIKit                               0x0000000105096e36 -[UIApplication sendEvent:] + 352
    18  UIKit                               0x00000001059d9434 __dispatchPreprocessedEventFromEventQueue + 2809
    19  UIKit                               0x00000001059dc089 __handleEventQueueInternal + 5957
    20  CoreFoundation                      0x00000001089df231 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    21  CoreFoundation                      0x0000000108a7ee41 __CFRunLoopDoSource0 + 81
    22  CoreFoundation                      0x00000001089c3b49 __CFRunLoopDoSources0 + 185
    23  CoreFoundation                      0x00000001089c312f __CFRunLoopRun + 1279
    24  CoreFoundation                      0x00000001089c29b9 CFRunLoopRunSpecific + 409
    25  GraphicsServices                    0x000000010cc289c6 GSEventRunModal + 62
    26  UIKit                               0x000000010507a5e8 UIApplicationMain + 159
    27  mysoundplayer                          0x00000001035e12a7 main + 55
    28  libdyld.dylib                       0x000000010aa49d81 start + 1
    29  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Source code:

import AudioKit
import AudioKitUI
import UIKit

class ViewController: UIViewController {

var micMixer: AKMixer!
var recorder: AKNodeRecorder!
var player: AKAudioPlayer!
var tape: AKAudioFile!
var timePitch: AKTimePitch!
var pitchShifter: AKPitchShifter!
var mainMixer : AKMixer!
var loadedFile: AKAudioFile!

let mic = AKMicrophone()

var state = State.readyToRecord

enum State {
    case readyToRecord
    case recording
    case readyToPlay
    case playing
}

@IBAction func toggleRecord(_ sender: UIButton) {
    switch state {
    case .recording:
        sender.setTitle("record", for: .normal)
        state = .readyToRecord
        do {
            try player.reloadFile()
        } catch {
            print("Error reloading!")
        }

        let recordedDuration = player != nil ? player.audioFile.duration : 0
        if recordedDuration > 0.0 {
            recorder.stop()
            let randomfilename:String = NSUUID().uuidString + ".m4a"
            print("Filename: \(randomfilename)")
            player.audioFile.exportAsynchronously(name: randomfilename, baseDir: .documents, exportFormat: .m4a, callback: {file, exportError in
                if let error = exportError {
                    print("Export failed \(error)")
                } else {
                    print("Export succeeded")
                    self.loadedFile = file
                }
            })
        }
    case .readyToRecord:
        do {
            try recorder.record()
            sender.setTitle("stop", for: .normal)
            state = .recording
        } catch { print("Error recording!") }

    default:
        print("no")
    }
}


@IBAction func play(_ sender: UIButton) {
    playLoadedFile()
}

@IBAction func valueChanged(_ sender: UISlider) {
    timePitch.pitch = Double(sender.value)
}

func playLoadedFile() {
    do {
        try player.replace(file: loadedFile)
        player.start()
    } catch { print("Error playing!") }
}

func exportedAudioFile(filename: String) {
    print("yay")
}

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view, typically from a nib.

    AKAudioFile.cleanTempDirectory()
    AKSettings.bufferLength = .medium
    AKSettings.defaultToSpeaker = true

    //inputPlot.node = mic
    micMixer = AKMixer(mic)
    mainMixer = AKMixer(player,timePitch)

    pitchShifter = AKPitchShifter(player)
    timePitch = AKTimePitch(player)

    recorder = try? AKNodeRecorder(node: micMixer)
    if let file = recorder.audioFile {
        player = try? AKAudioPlayer(file: file)
    }

    AudioKit.output = timePitch // works with player
    AudioKit.start()
    print("mainMixer status: \(mainMixer.isStarted)")


}

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

}

It looks like mainMixer isn't connected to anything. Try changing AudioKit.output = timePitch to AudioKit.output = mainMixer .

As for best practices, get rid of any try? s. Use a do try catch and at least print the error.

if let file = recorder.audioFile {
    do{
        player = try AKAudioPlayer(file: file)
    } catch {
        print(error)
    }
}

You're attaching the player to the mixer before you create it. At the time where you give player to AKMixer(), it is nil. Move the mixer creation after the player assignment.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM