Too Many SoundEffects Causes Slowdown for WP7
In my ongoing quest to make Hypership for WP7 perform as fast as inhumanly possible, I discovered that playing too many SoundEffect objects actually hurt performance a lot. With no sound effects playing, the game would run at 30 fps or slightly below. When I got to areas with lots of sounds (such as going through a big section of coins or shooting lasers into a solid wall), the performance would drop to as little as 10 fps. This was not acceptable.
Whenever you play a SoundEffect (mySound.Play()), a SoundEffectInstance object is created for that SoundEffect and it is played. For Zune games, you could have a maximum of 16 concurrently playing SoundEffectInstances and for Xbox that number is around 300. For WP7 the magic number is 64. I know I was not hitting that limit but at some point above 14, in-game performance really did tank. Hypership performs well on some devices (LG Optimus 7) and badly on others (HTC HD7) so it seems not every phone handles playing sounds as well as others.
I believe there is some sort of exception thrown when you pass this maximum number of SoundEffectInstances. It doesn't cause your game to crash but it does cause it to slow down (likely because an exception is being handled somewhere). I haven't found this behavior documented anywhere, it's just what I heard. If you have a better explanation, let me know in the comments and I'll update this article to match.
In order to resolve the slowdown, I decided to setup a way to track what SoundEffectInstances had most recently been played and stop the oldest instance before playing a new one. You cannot stop a SoundEffect object from playing which means that you need to create SoundEffectInstances manually each time and play those because you can stop SoundEffectInstances.
First you need a list to hold all the SoundEffectInstances and you also need to declare whatever SoundEffects you wish to play (you should also load those SoundEffects somewhere but I'm not going to show you code for that).
// This is a global list of all soundInstances played and should be scoped as such.
// This is an example SoundEffect. Use your own!
Wherever you play your sounds, you need to do the following. I play all my sounds from one SoundBank object I created with a Play method, so it was easy to centralize this logic.
// If there are too many sounds playing already, stop the oldest.
// I used 14 just to be safe. You probably could go a couple higher.
if (this.soundInstances.Count > 14)
// Rather than playing mySound directly, create an instance which can be played or stopped.
SoundEffectInstance newInstance = mySound.CreateInstance();
// Add the instance to this collection so you can stop it later.
Simple as that. Now you should be able to easily stop old sounds and prevent slowdown that may otherwise plague your game. If you have other comments or suggestions, please leave them in the comments below.
This article has been view 2205 times.