How to make [AVAudioPlayerNode scheduleFile] play immediately without clipping

If I call [AVAudioPlayerNode scheduleFile] with atTime = nil, my sound plays very nicely but only after all other sounds have finished playing.

This is inappropriate for the project I'm working on, I need sound effects to be able to play simultaneously.

So now I'm calling scheduleFile to play a sound with atTime = mach.absolute.time(). (Underscores instead of dots.)

The problem is, the beginnings of the sounds are often clipped, because presumably it takes a fraction of a second to copy the sound to the output buffer.

So I guess I could add an arbitrary delay to when I want the sound to play, but that's very hacky.

Is there a way to tell scheduleFile, "play the entire sound as soon as you're ready to play it, even if other sounds are playing simultaneously."

Thanks in advance!
Answered by DTS Engineer in 612809022
It sounds like you're using one player node for multiple files. You should probably have a "pool" of player nodes that you can use for simultaneous sounds.

Also, take a look at https://developer.apple.com/documentation/avfoundation/avaudioplayernode/1388511-prepare. This doesn't help if you need to play a sound now, but is good to use for sounds that will start soon (or at a specific time), provided you do the "prepare" slightly in advance.

The problem with the sounds being clipped seems like a known behavior: when you start playing, there is a short volume ramp (to avoid audio artifacts at the start of sound data). For sound effects that have a short but prominent start (such as the abrupt sound of something hitting a wall), this may have the effect of cutting off the important part of the sound.

If that's the issue you're running into, the workaround is to add a fraction of a second of silence to the start of your sound file. I also recommend you file a bug report about the issue, to indicate your interest in a possible API-level solution in the future.
Passing atTime = nil will play the sound as soon as possible, if the node is not playing something else (see the discussion of timestamps in AVAudioPlayerNode.h). If it's delaying until other sounds have finished, that implies that you're playing other sounds with the same player node. The simplest solution is to use multiple player nodes.
Accepted Answer
It sounds like you're using one player node for multiple files. You should probably have a "pool" of player nodes that you can use for simultaneous sounds.

Also, take a look at https://developer.apple.com/documentation/avfoundation/avaudioplayernode/1388511-prepare. This doesn't help if you need to play a sound now, but is good to use for sounds that will start soon (or at a specific time), provided you do the "prepare" slightly in advance.

The problem with the sounds being clipped seems like a known behavior: when you start playing, there is a short volume ramp (to avoid audio artifacts at the start of sound data). For sound effects that have a short but prominent start (such as the abrupt sound of something hitting a wall), this may have the effect of cutting off the important part of the sound.

If that's the issue you're running into, the workaround is to add a fraction of a second of silence to the start of your sound file. I also recommend you file a bug report about the issue, to indicate your interest in a possible API-level solution in the future.
Thanks guys--using a pool of player nodes is a great idea.
How to make [AVAudioPlayerNode scheduleFile] play immediately without clipping
 
 
Q