iOS AVAudioPlayer play sound again - ios

Hey I have a couple of AVAudioPlayers containing one sound each. If I press the same button a couple of times, it should repeat the sound from the beginning. If I press another button afterwards, the running sound shall be stopped in order to "make room" for the new one.
The code I am using for that:
-(void) plays:(int)p{ // p is the index of the sound being triggered
if([players[p] isPlaying])
{ // setting the time back to 0 makes
players[p].currentTime = 0.0; // the player automatically play again
}
else
{
[players[p] play]; // if not playing, start playing
}
if(last!=p)
{ // if the last sound is different from the current
[players[last] stop]; // stop the last one
players[last].currentTime = 0.0;} // put its position back to 0
last=p; // set the 'last' variable
}
However, hitting the same button again ends up in a little delay (maybe 20ms) in which no sound is heard. This is the time, the AVAudioPlayer seems to need to "rewind" the track in order to play it again. One Idea to get around this would be to create multiple objects of AVAudioPlayer for each sound but that'd make some awful code! Any ideas on how to make this process quicker?
Thanks, Alex
EDIT: playing 2 different sounds works perfectly fine, I can't hear any delay in between them as I prepareToPlay all the sounds beforehand.

I know how to eliminate the 20ms gap, but first consider if you want to.
Imagine if you jumped immediately from the mid-point of the sound file to the beginning with no gap at all. Better yet, download Audacity and hear how it sounds. Because of the discontinuity, you are going to get an unpleasant crackling or pop sound. Perhaps that 1 fiftieth of a second of silence actually sounds better than immediately restarting.
If you want an uninterrupted audio stream, you're going to have to put away the easy AVAudioPlayer interface and build an AUGraph. Of course, this means learning a complex audio interface and learning all about audio formats. And then you have to figure out what data you're going to stuff into your audio stream.
How would you make your loop sounds nice? You might try fading out at the touch point, and then fading back in. Or you could search for the zero crossings at the beginning and end of your loop (zero crossings are the place where the value of your sound wave is 0. They happen all the time in a mono output, but might be harder to find if your output is stereo.) In the end will this sound nicer than the 20 ms of silence? Get out Audacity and experiment with looping before you enter the long road of learning the AUGraph interace.

To the same song, how about stopping it, then prepareToPlay and play?

Related

SpriteKit background music not looping forever

I'm making a simple SpriteKit game with two scenes, and I want the background music to loop unconditionally through both scenes. Right now, I'm using
if soundIsPlaying == false {
runAction(SKAction.repeatActionForever(backgroundMusicEffect), withKey: "backgroundMusic")
soundIsPlaying = true
}
in my menu scene where backgroundMusicEffect is a global variable
let backgroundMusicEffect = SKAction.playSoundFileNamed("content/divertimentoK131.mp3", waitForCompletion: true)
When I play my game, the music never loops. It always stops after one play. If I remove the if-else statement, the music plays over itself every time I reenter the menu.
Is there a better way to play background music? What am I doing wrong?
I believe that the way you are doing it, after the first time looping, every iteration after is "complete" since the sound is finished. You would need to create a new SKAction instance every time if you want to get this to loop.
This of course is a bad idea, since playSoundFileNamed is designed to only play a sound file once with as little over head as possible.
As #Alessandro Omano has commented, use SKAudioNode to get sound playing in a loop. This is my preferred way of doing in, but you limit yourself to >= iOS 9 users.
If you have to support iOS 8 users (At this point I would say why bother) then you need to look into the AVFoundation sections of the libs to get audio going, or use OpenAL.

Upon button press how can play a sound at EXACT same time as screen activity

I have a very specific issue and I have not yet found a solution.
I have an IBAction for a button press. What I want to happen when this button is pressed is:
play a sound file (this is about 5 seconds long sound)
flash words on the screen (this is also about 5 seconds long)
I want this to happen concurrently so total time is about 5 seconds (words flashing while sound is playing).
What I end up with is that the words flash first, then the sound plays. I can never get them to go concurrently. Interestingly also I can never get the sound to play first even when placed at the very start of the action.
I've tried NSThread the sound, exec, CATransaction flush, but nothing can get them concurrent.
any ideas, btw I am total beginner programmer so sorry if not described the proper way.
-(IBAction) playButtonClick:(id)sender {
int i;
[_audioPlayer play];
for (i=0; i<10; i++){
[self.model getNextWord];
[self displayWord];
[CATransaction flush];
usleep(550000); // word on screen for 0.55 seconds
}
}
[CATransaction flush] is required else all I would see would be the very last word.
You have 2 tools at your disposal:
prepareToPlay()
playAtTime(_:)
Prepare so that the sound is in memory.
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.
Wait until the rest of your UI is ready prior playing.
Use this method to precisely synchronize the playback of two or more AVAudioPlayer objects.

Looped sound Hiccups

I have a sound file I wish to loop like the engine of a vehicle.
The sound I have is 1 second long and it is a .wav file.
I'm quite certain the file is cut to be seamless,
it loops perfectly in Audacity.
I'm calling the sound with this code:
let playEngineSound = SKAction.playSoundFileNamed("engine.wav", waitForCompletion: true)
let engineSoundLoop = SKAction.repeatActionForever(playEngineSound)
self.runAction(EngineSoundLoop, withKey: "engine sound")
I use "withKey" to be able to cancel it later.
The Sound comes out fine but there is a small but distinctive hiccup where the sound seems to be reloading or waiting for the other to stop completely before starting the new loop.
Any help would be much appreciated!
Edit: After trying the AVAudioPlayer route, it plays flawlessly, someone knows anything about the behaviour? I still want to go purely SKAction if possible.

iphone-loading sound files quickly

I have a space shooter game I am making. I want to play a sound every time a user hits the button fire. This is a short .wav file of about half a second in length. Also, when the user dies, I have an explosion .mp3 file to play. Since the fire button can be clicked very rapidly, I need to play sounds quickly. I used some avaudio player code previously where I make a new audioplayer every time I need to fire, but this crashes occasionally if I fire very quickly. Any suggestions on ways to play sound files very quickly? (including some example code in you answer would be great)
if you using MPMediaPlayback you can try prepareToPlay

Using AVAudioPlayer play in for

How I can use play sound in cycle example for
when i try to use like
..
mySound.numberOfLoops = 1; // or 0 (if -1 play infinitely)
..
for ...
{
///....
if .... {
//...
[mySound play];
}
only one play time
I'm not sure if you mean that you want to play multiple sounds at the same time or if you want to play the sound forever. To play the sound forever set the value of mySound.numberOfLoops to -1. If you want to play multiple sounds you have to allocate new AVAudioPlayers every time. In order to do this you could allocate a new one at the beggining of the if expression, although it might be difficult to stop the sounds whenever you want.

Resources