Playing Sound File while Game is Paused in SpriteKit / Swift - ios

In my game I made a pause menu which pauses the entire game and loads a play button, score label, and a main menu button. When I click the play button, pause button, or main menu button, I want to have it play a sound file. However, it is not letting me do this because everything is paused. I tried manually pausing all nodes, but this is not working. Is there anyway to unpause actions? Also, can you programmatically change a sound file's volume? Below is my code for when the user taps the pause button. I am using xCode 6.4 by the way.
if targetNode.physicsBody?.categoryBitMask == PhysicsCategory.Pause {
switch gameState {
case (.GameRunning):
if paused == false {
runAction(SKAction.playSoundFileNamed("beep1.mp3", waitForCompletion: false))
paused = true
pauseScene()
}
case (.GameOver):
return
}
}

Related

How to stop currently playing audio automatically when another play button in different UITableView cells are pressed? - Swift

I am a swift beginner currently working on my first iOS app.
I have a TableViewController which has several cells and each cell contains a play button. When a few play buttons are pressed, a few different audios are played at the same time, but I would like to stop a currently playing audio when another playing play button is pressed.
Here are the sample codes I created.
Please give me an advice. Thank you so much!
The problem is that every single cell has its own independent player. You want just one player, so that you can stop it and start a new sound. For example, make the one player a property of the view controller. Every cell can see it but there is just one.
create an extension for AVPlayer because AVPlayer does not own condition for playing. extension given below.
extension AVPlayer {
var isPlaying: Bool {
return rate != 0 && error == nil
}
}
use it while tap on play like this.
if player?.isPlaying == true {
player?.pause()
player?.seek(to: CMTime(seconds: 0, preferredTimescale: 60))
}
//set up you audio file to player
player?.play()

When I tap the "next" button it pauses the music instead of automatically going to the next song

Hi I recently implemented a play/pause button which works perfectly using MPMusicPlayerController I have now added a "next song" button. But when I click this "next song" button it pauses the music and when I tap the "play" button then it plays the next song. I was wondering if there was a way where as I click the "next song" button it would automatically play the next song instead of pausing it. Heres my code for the 2 buttons:
var musicPlayer = MPMusicPlayerController.systemMusicPlayer
#IBAction func nextMusicTapped(_ sender: UIButton) {
musicPlayer.skipToNextItem()
musicPlayer.prepareToPlay()
musicPlayer.play()
}
#IBAction func playPauseMusicTapped(_ sender: UIButton) {
let state = musicPlayer.playbackState.rawValue
if (state == 1) { //playing
musicPlayer.pause()
musicPlayPauseButton.setImage(UIImage(systemName: "play.fill"), for: .normal)
musicNextButton.isHidden = true
} else if (state == 2) { //paused
musicPlayer.prepareToPlay()
musicPlayer.play()
musicPlayPauseButton.setImage(UIImage(systemName: "pause.fill"), for: .normal)
musicNextButton.isHidden = false
}
}
First off, according to Apple's documentation, skipToNextItem() does the following:
Starts playback of the next media item in the playback queue; or, if the music player is not playing, designates the next media item as the next to be played.
So in other words, if the music player is already playing a song, you shouldn't have to tell it to play the next item, it should automatically start playing. So you wouldn't need the following lines:
musicPlayer.prepareToPlay()
musicPlayer.play()
This also leads me to believe that somehow your music player is being paused prior to that skipToNextItem() being called. Try putting print(musicPlayer.playbackState.rawValue) before line 4. If it prints 2, then your music player seems to pause by clicking the "next song" button, so that would mean something weird is going on with your IBAction connections. I've done this before where I accidentally call two different IBAction methods with the same button (due to an error in setting up the outlets in the first place). In your particular case, you could be accidentally calling both the playPauseMusicTapped (which pauses the music), and the nextMusicTapped() method to switch the songs, but that's just a random thought. Let me know what that playback state before line 4 is, regardless. That would be good to know.

AVAudioPlayer audio not playing when its set and played from different methods

I have an app with different button press sounds. I'm trying to use two functions to set the next button press sound and then play it. The idea is to load the audio file for when the next button is pressed, and then finally play it through a different function when a button is pressed. Using prepareToPlay(), this should make playback faster.
The problem is that when I press a button, I hear 'silence'. I say 'silence' because my speakers actually receive some signal, but its too week to be heard.
Here's my code:
func loadNextButtonPressSound() {
let randomSoundIndex = Int(arc4random_uniform(UInt32(pressSounds.count)))
pressSoundPlayer = try! AVAudioPlayer(contentsOfURL: pressSounds[randomSoundIndex])
pressSoundPlayer.prepareToPlay()
pressSoundPlayer.delegate = self
}
func playButtonPressSound() { // called when a button is pressed
if(StoredSettings.instance.getEnableSoundsSetting()) {
pressSoundPlayer.play()
loadNextButtonPressSound()
}
}
If I instead merge the codes to form this:
internal func playButterPressSound() {
if(StoredSettings.instance.getEnableSoundsSetting()) {
let randomSoundIndex = Int(arc4random_uniform(UInt32(pressSounds.count)))
pressSoundPlayer = try! AVAudioPlayer(contentsOfURL: pressSounds[randomSoundIndex])
pressSoundPlayer.play()
}
}
It starts working (i.e. I hear button presses), but it defeats the purpose of using prepareToPlay() to preload the next sound.
Any suggestions on how to make the first code above work ?

Keep AVAudioPlayer sound in the memory

I use AVAudioPlayer to play a click sound if the user taps on a button.
Because there is a delay between the tap and the sound, I play the sound once in viewDidAppear with volume = 0
I found that if the user taps on the button within a time period the sound plays immediately, but after a certain time there is a delay between the tap and the sound in this case also.
It seems like in the first case the sound comes from cache of the initial play, and in the second case the app has to load the sound again.
Therefore now I play the sound every 2 seconds with volume = 0 and when the user actually taps on the button the sound comes right away.
My question is there a better approach for this?
My goal would be to keep the sound in cache within the whole lifetime of the app.
Thank you,
To avoid audio lag, use the .prepareToPlay() method of AVAudioPlayer.
Apple's Documentation on Prepare To Play
Calling this method preloads buffers and acquires the audio hardware
needed for playback, which minimizes the lag between calling the
play() method and the start of sound output.
If player is declared as an AVAudioPlayer then player.prepareToPlay() can be called to avoid the audio lag. Example code:
struct AudioPlayerManager {
var player: AVAudioPlayer? = AVAudioPlayer()
mutating func setupPlayer(soundName: String, soundType: SoundType) {
if let soundURL = Bundle.main.url(forResource: soundName, withExtension: soundType.rawValue) {
do {
player = try AVAudioPlayer(contentsOf: soundURL)
player?.prepareToPlay()
}
catch {
print(error.localizedDescription)
}
} else {
print("Sound file was missing, name is misspelled or wrong case.")
}
}
Then play() can be called with minimal lag:
player?.play()
If you save the pointer to AVAudioPlayer then your sound remains in memory and no other lag will occur.
First delay is caused by sound loading, so your 1st playback in viewDidAppear is right.

How to Stop AVAudioPlayer

I am making a noiseMaker application for iOS in xCode where there are different buttons that play different sounds. Each sound is given a tag of 0-3 along with each button in the storyboard. And the randomize button has a tag of 4, Here is the code so far:
func play (index: Int) {
if !player.isEmpty && index >= 0 && index < player.count {
player[index].play()
}
if index == 4{
let randomNumber = Int(arc4random_uniform (4) + 0)
player[randomNumber].play()
}
However, what I want is for the current song to stop playing when I press on another button or even on the same button again. I believe the stop AVAudioPlayer code would go right when the function "play" begins so that it stops the player before any other song starts playing.
All help is appreciated. Thanks in advance...
You can check that currently player is playing or not.
Check the playing property returns status of player is playing or not.
if (aPlayer.playing) {
aPlayer.stop()
//Then play again by aPlayer.play()
}
else {
aPlayer.play()
}

Resources