I'm building an app that plays multiple short sound effects in one activity.
There are over 80 buttons with each buttons that plays a specific sound effect.
I've searched about SoundPool and MediaPlayer and found out SoundPool is more efficient for short sound files.
Here's my question, if I should load over 80 sound effects in one activity, would SoundPool still be the better option? I ask because SoundPool loads the sound at once and reuses it, I think it's a bit heavy to load 80 sounds in one activity (Maybe I'm wrong.) Would like to hear the experts here for a better way or any advice!
Thanks in advance
It does not depend by the number of sounds, but from their size in terms of bytes. Every sound is loaded into memory and if they are too big, you could not have enough memory to load them all.
I would consider using AudioTrack. You instantiate it and when you have to play a sound you can read it from file system or assets or resources and add it to the play queue. It works only with PCM.
Related
I have started a android.media.MediaPlayer file with:
mp1.start()
and then trying the looping with:
setLooping(true);
but this is ending up with a delay in playing the file again.
I am trying to run an mp3 file containing a rhythm with a set tempo. Is there any better way of looping it in such a manner that the tempo timing does not get disturbed and the rhythm plays seamlessly without any stutter/delay?
Should I use SoundPool instead?
Most of best practices for this particular case recommend using .ogg format. You can convert you file easily using VNC media player.
Wiki for .ogg file format - http://en.wikipedia.org/wiki/.ogg
Another solution is the SoundPool and the third one - is to use Audacity and cut the quiet/“blanksound” from you audio file.
If your audio is not long, then use SoundPool for low-latency media playback, instead of MediaPlayer. Also convert it to ogg, as others have already pointed it out.
Edit: if it is just a tempo, and not a continous sound, then maybe you can also measure the latency and seek your audio based on that, but I am not sure you will get better results this way.
Mediaplayer solutions:
If you insist on using MediaPlayer, then you can:
either crop the sound at the end of your audio files, so there's no sound gap between two playback loops
or create a custom solution yourself as the one described here.
Soundpool alternative:
Now, from my personal experience, if you want to loop files small in size and duration, not more than 1MB, then Soundpool is more convenient and it seems that not any relevant problems are reported in contrary to the MediaPlayer. There have been many complaints when trying to loop sounds using MediaPlayer, so generally Soundpool is usually preferred for looping.
Soundpool size limit:
If you are concerned about Sounpool's size limit, keep in mind that it has 1Mb buffer size limit per track. But this limit applies not to file size but to decompressed raw PCM data. SoundPool is going to decompress the loaded audio to PCM data so it is ready to play instantly without the latency of decoding. If the audio you are loading is compressed heavily, such as MP3, then that can get blown up quite a bit.
Improve performance:
Also, as suggested in another answer, files of type ".ogg" according to many sources appear to perform better than ".mp3" in general. So, you should try to convert your files for better performance, but I don't think you will see an improvement concerning looping.
To convert your files you can use an online tool such as this. If you convert your files remember to also make these changes:
Change your sound file's sampling rate to 16000 Hz
Change your audio channel to mono, instead of stereo.
Make sure your file after these processes is smaller than 1 mb in size.
Please try to do it this way.
audio = MediaPlayer.create(this, R.raw.pl);
audio.setLooping(true);
audio.start();
How can I play background audio, in Android, without interrupting the MediaPlayer playback, by either using MediaPlayer (preferred) or OpenSL ES?
I know SoundPool is able to play sound effects without interrupting any MediaPlayer playback, but the size is limited to 1M per effect, which is way to less. Not requesting audio focus, via AudioManager doesn't seem to work either, audio doesn't play at all in this case.
And in the case of OpenSL ES, all audio generally stops when I start to play a longer asset file. It's similar to the behaviour of SoundPool described above.
Edit from the comments:
I don't want to interrupt other music players, it's the background
audio of a game, which shall play without interrupting the, for
example, music of a player. Games like Subway Surfer, Clash Royale and
such seem to have this achieved somehow, but I could not achieve it
via OpenSL ES, or MediaPlayer.
In order to play sound in background you can use SoundPool, AudioTracks and OpenSlES.
Soundpool: Use small files and make a sequence. In my last project i use 148 sound files (all small) in different scenarios and played using soundpool. Make a list and play one by one or in parallel. Also in games usually you have a small set of sound for particular scenario and it loops. Best is soundpool for that. You can also perform some effects like rate change. Also ogg files are way small, so use them.
AudioTrack: You can use RAW PCM data in audio track. If you want you can extract pcm data using MediaExtractor from almost all formats and use it. But it will be a little work for you in your case, but it is really good (supports huge data, even live streaming).
OpenSLES: Apparently android uses opensles in background for all its purpose. So using it will help you a lot. But it's not easy to get everything done on it. You need to learn more for lesser work.
I have been deeply working on OpenSlES for about 20 days and still i will say for small purpose use soundpool, medium to high level implementation use AudioTracks and for kickass implementation use OpenSLES.
PS: It will be bad effect on your user if you play game sound in background while they are playing their music or their call. Personal experience.
When using a SoundPool audio class, it definitely has some advantages over a MediaPlayer when just playing short audio clips. The two I've noticed is SoundPool is a lot faster. MediaPlayer can lag a bit on startup and it's much easier to go from one sound clip to the next, where I don't have to stop,reset,prepare each time.
However, is it possible to use the visualizer to get real time fft data from audio data playing in the SoundPool like it is for MediaPlayer? I couldn't come across any topics that cover that, but by the off chance I thought I would ask because it seems like it should be possible. The documentation says, "The SoundPool library uses the MediaPlayer service to decode the audio into a raw 16-bit PCM mono or stereo stream." So if I could reference the MediaPlayer that SoundPool is using then I think I could just use getAudioSessionId() perhaps?
I already tried setting session ID to 0 to just get the output mix. It didn't work but it's not really the ideal effect that I am looking for anyway. Also one of the first things I did was try using the loaded SoundPool SoundID in place of the visualizers session ID, but that also didn't work.
I'm working on a little game that is uses soundpool to play small sound-files.
However, it now seems that I have too many sound files that I want to add to the soundpool since I get an error saying that the heap has an overflow.
So then I tried to load the sound files when they are needed instead of loading them when the class instance is initialized, but the result of that turned out very bad.
Are there any other ways I can make it work using soundpool or do I have to use media player instead? I already have media player class that is used to play long sound clips like music files and so on. So the backup plan is to make two instances of the media player class that runs on two separate threads where one of them handles the small sound files.
Any help and ideas is highly appreciated.
Greetings!
Try dividing the SoundPool object you are using into multiple instances. Ex. SoundPool sp1, sp2, sp3; Do not use multiple MediaPlayer objects as this will be very slow and inefficient.
I'm having troubles with the soundpool class. Here it goes:
In my game app (music app btw) I need to reproduce at least 32 short sounds at the same time, so I declare my soundpool like that:
private SoundPool sp;
sp = new SoundPool(128, AudioManager.STREAM_MUSIC, 0);
After that I load all the MP3 sounds needed, about 80 sound of 55KB each. I have no troubles loading all the sounds, but its slow! Well it's no the problem. The real trouble is when I play about 20 sounds at the same time, there's an error in my log:
ERROR/AudioFlinger(59): no more track names available
ERROR/AudioTrack(26349): AudioFlinger could not create track, status: -12
ERROR/SoundPool(26349): Error creating AudioTrack
After that every sound that i try to play throws the same error, and no sound can be played. Not even sounds of another Activity / soundpool. I have no clue of what's going or how to fix it! Should I change the format of the sound files? Should I free memory or something after playing a sound?
(I'm testing on a Samsung Galaxy S I9000, 2.3.3 OS system. The app is 2.1)
see this (in android group)
For audio, there's a hard limit of 32 active AudioTrack objects per device (not per app:
you need to share those 32 with rest of the system),
A couple of thoughts here. One: the first parameter to the SoundPool constructor is not the number of sounds you want to load into it, it's the maximum number of simultaneous streams that you'll be playing. Second, SoundPool has limited memory for sounds, about 1MB. So I wouldn't be at all surprised if you hit some undocumented limit to the number of tracks you can load in at one time. Notice that 80 sounds times 55k per sound is definitely over 1MB. And that limit is for after the mp3s have been uncompressed into audio data inside SoundPool.