2

I have a bunch audio nodes set up as so

var audioPlayers = [AVAudioPlayerNode]()

var engine = AVAudioEngine()

var player = AVAudioPlayerNode()


@IBAction func key(_ sender: UIButton) {
        audioPlayers[someindex].play()
}

func createPlayers() {

        for key in constructedArrayOfNotes {
            player = AVAudioPlayerNode()


            player.volume = 0.5

            let reverb = AVAudioUnitReverb()
            reverb.loadFactoryPreset(AVAudioUnitReverbPreset.cathedral)

            reverb.wetDryMix = 50

            let audiopath = Bundle.main.path(forResource: key, ofType: "mp3",inDirectory: directory)!
            let url = NSURL.fileURL(withPath: audiopath)

            do {
                let file = try! AVAudioFile.init(forReading: url)
                let buffer = AVAudioPCMBuffer(pcmFormat: file.processingFormat, frameCapacity: AVAudioFrameCount(file.length))
                try file.read(into: buffer!)
                engine.attach(player)
                engine.attach(reverb)



                engine.connect(player, to: reverb, format: buffer!.format)
                engine.connect(reverb, to: engine.mainMixerNode, format: buffer!.format)
                player.scheduleFile(file, at: nil, completionHandler: nil)



                audioPlayers.append(player)
            } catch {
                print("error")
            }


        }


}


override func viewDidLoad() {

    createPlayers()
    engine.prepare()
    try! engine.start()

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

Is there a way for me to replay an audio file that is stored in an AVAudioPlayerNode from the beginning? Currently when I press the IBAction the sound plays but I'm not able to replay it. I'm trying to do the equivalent of AVAudioPlayer.starttime = 0

buttonSmasher96
  • 133
  • 1
  • 11

1 Answers1

1

To answer the question you're asking:

AVAudioPlayerNode doesn't have a seek function, you have to schedule the file again.

One clean way to do it is to just hold references to the audio files as you create them. Then, in your key function reschedule the file and play.

var audioPlayers = [AVAudioPlayerNode]()
var audioFiles = [AVAudioFile]() // Populate in same loop you create the players.

@IBAction func key(_ sender: UIButton) {
    let player = audioPlayers[sender.tag]
    let audioFile = audioFiles[sender.tag]
    player.scheduleFile(audioFile, at: nil, completionHandler: nil)
    player.play()
}

To offer advice based on assumption :)

With a key function that is the target of a button, I'm assuming that you want to play different audio files when buttons are pressed. If you don't mind there being a little lag from the time you press the button until the time audio starts playing, or, if you're dealing with really long audio files, then your current approach is fine. However, if an unpredictable lag time isn't acceptable, you have a few options.

Schedule audio AVAudioBuffers instead of files, there is much less of a lag time when starting playback. You would use the same approach I outlined above, but instead of storing the AVAudioFile and scheduling, store and schedule the AVAudioBuffer.

If you are making a pad or keyboard style sampler, you need to get the lag down to the absolute minimum. AVAudioUnitSampler is ideal for this. It's capable of achieving very low latency audio and it can be configured to map files to keys. It's a little more difficult to set up, but well worth the effort if timing is important.

dave234
  • 4,793
  • 1
  • 14
  • 29
  • 1
    Unfortunately I'm still unable to replay the same sound that I want whenever I press the button again. I would like it to replay the sound from the very beginning. I was wondering maybe the play(at:...) function would do the trick but it needs an AVAudioTime argument and I don't know how to construct one. – buttonSmasher96 Nov 15 '17 at 18:11