AVAudioEngine seek the time of the song
Asked Answered
M

2

9

I am playing a song using AVAudioPlayerNode and I am trying to control its time using a UISlider but I can't figure it out how to seek the time using AVAUdioEngine.

Mullet answered 29/4, 2015 at 20:47 Comment(1)
I have been waiting for the answer to this question for months and have been putting it off. I know ti involves getting lastRenderTime of your player node and subtracting or adding time from that. Getting it to play back from that time is the hard part though.Faun
F
20

After MUCH trial and error I think I have finally figured this out.

First you need to calculate the sample rate of your file. To do this get the last render time of your AudioNode:

var nodetime: AVAudioTime  = self.playerNode.lastRenderTime
var playerTime: AVAudioTime = self.playerNode.playerTimeForNodeTime(nodetime)
var sampleRate = playerTime.sampleRate

Then, multiply your sample rate by the new time in seconds. This will give you the exact frame of the song at which you want to start the player:

var newsampletime = AVAudioFramePosition(sampleRate * Double(Slider.value))

Next, you are going to want to calculate the amount of frames there are left in the audio file:

var length = Float(songDuration!) - Slider.value
var framestoplay = AVAudioFrameCount(Float(playerTime.sampleRate) * length)

Finally, stop your node, schedule the new segment of audio, and start your node again!

playerNode.stop()

if framestoplay > 1000 {
   playerNode.scheduleSegment(audioFile, startingFrame: newsampletime, frameCount: framestoplay, atTime: nil,completionHandler: nil)
}

playerNode.play()

If you need further explanation I wrote a short tutorial here: http://swiftexplained.com/?p=9

Faun answered 7/5, 2015 at 15:0 Comment(7)
Thank you so much for your help! I finally understood how things are working!Mullet
Where did you pull songDuration from?Transfinite
For future readers, probably better to get the sample rate from playerNode.outputFormat(forBus: 0).sampleRateArianearianie
Hi, Paul I tried your code, it calculates corret but does not play from that time. Please replyChekiang
I have some coding mistake, other logic mistake so it was not working, sorry Paul.Chekiang
I tried the above answer and it is not working for me. I'm printing the currentTime before and after the function and it shows that things are wrong. Can I get your help? here is my [question] (#56356198)Michal
The link no longer works, but you can find it here: web.archive.org/web/20150918000438/http://swiftexplained.com/… Nothing there that isn't already in Paul's answer though.Ptolemy
A
3

For future readers, probably better to get the sample rate as :

playerNode.outputFormat(forBus: 0).sampleRate

Also take care when converting to AVAudioFramePosition, as it is an integer, while sample rate is a double. Without rounding the result, you may end up with undesirable results.

P.S. The above answer assumes that the file you are playing has the same sample rate as the output format of the player, which may or may not be true.

Arianearianie answered 27/10, 2017 at 21:13 Comment(2)
I tried the above answer and it is not working for me. I'm printing the currentTime before and after the function and it shows that things are wrong. Can I get your help? here is my [question] (#56356198)Michal
OMG! I have been messing around with this code for hours and couldn't get it to work. I put in so many print statements to make sure the numbers were correct and was pulling my hair out! I finally got it to work, because regardless of whether you have a playerNode playing or not, you MUST call the playerNode.stop() method BEFORE you call playerNode.scheduleSegment() method and then it plays. I had omitted the call to playerNode.stop() because I wanted to start an audio track at a specified time. Whew! What a fiasco on my part! Thanks for the code example!Membership

© 2022 - 2024 — McMap. All rights reserved.