Is it possible to loop through a background song but skip the first 30 seconds when the song loops the next iterations? So during the first run, the entire song gets played, but from the second loop onwards, the loop skips the first 30 seconds of the song. This is for a game and the first 30 seconds is simply to get the user excited but the following loops is just the causal background music.
Currently I've found on stackoverflow:
var AudioPlayer = AVAudioPlayer()
let AssortedMusics = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("backgroundMusic", ofType: "mp3")!)
AudioPlayer = try! AVAudioPlayer(contentsOfURL: AssortedMusics)
AudioPlayer.prepareToPlay()
AudioPlayer.numberOfLoops = -1
AudioPlayer.play()
For SwiftUI I'm guessing to put that into a function and run it inside an onAppear() when the game starts. But how'd I be able to play the beginning of the song only in the first loop?
Just play it first time and then loop with
'AudioPlayer.currentTime += 30'
Related
I am currently working on a workout plan app. Part of the app is an exercise timer that will count up or down (this works). Additionally a sound should be played as soon as the timer finishes. Ideally that sound would not interfere with music being played, no volume changes, no pause, nothing. Just play a loud sound while music keeps playing. I have tried two ways to do that, both have critical drawbacks.
First solution:
I tried using an AVAudioPlayer that does play the alarm sound after x seconds, with x being the time set for the timer. It does work sometimes as expected, but sometimes the sound will play early. If the timer is set to 60 seconds, the alarm might play after 60 seconds, but sometimes after 55-57 seconds. The alarm is implemented like this:
private let audioPlayer: AVAudioPlayer
// init audioPlayer
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers])
try AVAudioSession.sharedInstance().setActive(true)
} catch {
print(error)
}
do {
audioPlayer = try AVAudioPlayer(contentsOf: alarmSound)
} catch {
audioPlayer = AVAudioPlayer()
}
audioPlayer.play(atTime: audioPlayer.deviceCurrentTime + timeTarget)
My second solution that always fires at the right time is using a userNotification. This approach has different drawbacks. The notification will not show if my app is in foreground and the sound will not play if the phone is in silent mode. Aditionally, it will interfere with music being played and show a banner, but I want my alert to be as less intrusive as possible. It is implemented like this:
private var notificationCenter: UNUserNotificationCenter
private var alarmMessage: UNMutableNotificationContent
notificationCenter = UNUserNotificationCenter.current()
alarmMessage = UNMutableNotificationContent()
alarmMessage.title = "Workout Plan"
alarmMessage.subtitle = "Exercise Timer"
alarmMessage.categoryIdentifier = "alarm"
alarmMessage.sound = UNNotificationSound(named: UNNotificationSoundName("dummy.wav"))
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeTarget, repeats: false)
let identifier = "exerciseTimer"
let request = UNNotificationRequest(identifier: identifier, content: alarmMessage, trigger: trigger)
notificationCenter.add(request)
How do I play a sound at a specific time without any offsets or annoying the user with useless notifications?
I'm using the following code to play a sound file twice. The second sound plays immediately following the first
Is it possible to leave a time gap (1 second) between them? I've tried to find a solution reading the Apple Docs
var letterSound: AVAudioPlayer!
...
#IBAction func speakLetter(sender: AnyObject) {
let soundFile: String = "SoundFile" + String(letterNumber)
let path = Bundle.main.path(forResource: soundFile, ofType:"mp3")!
let url = URL(fileURLWithPath: path)
do {
let sound = try AVAudioPlayer(contentsOf: url)
letterSound = sound
letterSound.numberOfLoops = 1
letterSound.play()
} catch {
// couldn't load file :(
}
}
One option would be to add some 'white space' or silence at the end of your audio file.
If you don't have an audio editor i'd recommend Audacity, it's free and there are lots of tutorials on how to add silence.
If you want a more code based option you could look in to using the AVAudioPlayerDelegate didFinishPlaying method to detect the end of the first play and then use play(atTime:) to trigger the next loop 1 second from now.
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
player.play(atTime: player.deviceCurrentTime + 1.0)
}
This code is untested and I think it might create an infinite loop so you may need some additional logic here to make sure it only loops once
I am trying to add sound effects to a game app I am making in Xcode 6. Here is the code that I am using to play the sounds:
var jumpSoundPlayer:AVAudioPlayer = AVAudioPlayer()
var jumpAudioPath:String = ""
var jumpSoundError: NSError? = nil
func setUpSoundPlayers(){
jumpAudioPath = NSBundle.mainBundle().pathForResource("Jump", ofType: "mp3")!
jumpSoundError = nil
jumpSoundPlayer = AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: jumpAudioPath), fileTypeHint: "mp3", error: &jumpSoundError)
}
func playJumpSound(volume:Float = 1){
jumpSoundPlayer.volume = volume
jumpSoundPlayer.play()
}
I can get sounds to play, but it seems as though it will not play a sound until the one currently playing is finished. How can I get it so that multiple sounds can play at once and overlap each other?
Also, every time a sound plays it drops the frame rate down a little bit. Is there a way to fix that?
I believe you have to use
jumpSoundPlayer.prepareToPlay()
before using
jumpSoundPlayer.play()
Also the only solution to drop the frame rate a little less, is to set up all the AVAudioPlayers before using them or at the beginning of the game.
I've got the following code tied to a 'Jump Forward' button:
#IBAction func jumpForwardPressed(sender: AnyObject) {
var currentTime = audioPlayer.currentTime
var playForwardSkip = NSTimeInterval()
audioPlayer.stop()
audioPlayer.prepareToPlay()
playForwardSkip = 3.0 // skip forward 3 seconds
var skipF = currentTime + playForwardSkip
println("currentTime:\(currentTime) and playForwardSkip:\(playForwardSkip) and skipF:\(skipF)")
audioPlayer.playAtTime(skipF)
When button is pressed, audio stops, console reads out correct 'skipF' to skip to but audio does not play at that new point in time. It does not play at all.
Any pointers as to what might be wrong with my code?
You have misread the docs. playAtTime: does not seek to a later time in a sound file. It delays the start of playing the sound file (from the start).
To play from the middle of a sound file, set the player's currentTime and start playing.
Im trying to play a pop sound whenever a ball is touched but if the ball is touched again, before the pop sound ends, the sound will not play. I want the pop sound to cut out and start playing again if the ball is touched over and over again. The code i have now is below...
let popSound = NSBundle.mainBundle().URLForResource("pop",withExtension: "wav")
let Pop = AVAudioPlayer(contentsOfURL: popSound, error: nil)
////this is in the touches begin function/////
if touchedNode==ball{
Pop.play()
}
//////////////////////////////////
I fixed it with the help of this post. AVAudioPlayer stop a sound and play it from the beginning
I needed to set the Pop.currentTime to = 0
if touchedNode==ball{
Pop.currentTime=0
Pop.play()
}