Im trying to play 3 midi files (200Kb each) simultaneously after loading them to the soundPool.
After the play command I unload each stream and release the soundPool.I set the volume to 1 and the phone isnt silence.(Sorry for the language).
There is no crushes or somthing.
What should i do?
thx in advance
soundPool = new SoundPool(3, AudioManager.STREAM_MUSIC, 0);
soundPool.play(sound_id1, leftVolume, rightVolume, 1, 0, rate);
soundPool.play(sound_id2, leftVolume, rightVolume, 1, 0, rate);
soundPool.play(sound_id3, leftVolume, rightVolume, 1, 0, rate);
soundPool.unload(stream_id1);
soundPool.unload(stream_id2);
soundPool.unload(stream_id3);
soundPool.release();
EDIT:
When Im in debug mode and go over the play command it works great.
Tried to add a OnLoadCompleteListener still nothing.
Instead of unloading the sound resources and releasing the SoundPool object immediately after playing, create a Runnable to perform those tasks, and post it with a delay to a Handler. Declare the following:
final Handler handler = new Handler();
Runnable delayedUnload = new Runnable()
{
#Override
public void run()
{
soundPool.unload(sound_id1);
soundPool.unload(sound_id2);
soundPool.unload(sound_id3);
soundPool.release();
}
};
Then post the Runnable after you've played the sound resources:
soundPool = new SoundPool(3, AudioManager.STREAM_MUSIC, 0);
soundPool.play(sound_id1, leftVolume, rightVolume, 1, 0, rate);
soundPool.play(sound_id2, leftVolume, rightVolume, 1, 0, rate);
soundPool.play(sound_id3, leftVolume, rightVolume, 1, 0, rate);
handler.postDelayed(delayedUnload, 5 * 1000);
The second parameter in postDelayed() is the delay in milliseconds; in this case, the delay is 5 seconds. SoundPool does not provide a method to determine when a sound has finished playing, so you will need to adjust the delay accordingly.
Related
It seems that soundPool Api is not working correctly on android 11. I hear the sound like slow motion. Have anyone any related issue ?
My code
private SoundPool soundPool;
private int wonSound;
...
soundPool = new SoundPool.Builder().setMaxStreams(1).build();
wonSound = soundPool.load(this, R.raw.slot_win_1, 1);
...
soundPool.play(wonSound, 1, 1, 0, 0, 0);
According to the documentation:
https://developer.android.com/reference/android/media/SoundPool#play(int,%20float,%20float,%20int,%20int,%20float)?
SoundPool's function play() takes as its last parameter:
float: playback rate (1.0 = normal playback, range 0.5 to 2.0)
So, playback rates below 1 will sound slower than the original sound. To play your sound in its original playback rate, you should call play() like this:
soundPool.play(wonSound, 1, 1, 0, 0, 1);
changing pitch:
soundPool = new SoundPool(50, AudioManager.STREAM_MUSIC, 0);
/** Sound ID for Later handling of sound pool **/
soundId = soundPool.load(this, R.raw.sounds, 1);
play:
streamId = soundPool.play(soundId, 1, 1, 1, 3, pitch);
How can I save the file?
I don't think you can do this with the SoundPool, as it does not allow you to work at a byte level. I think you want to look into using AudioTracks.
I have created a class MySoundPool (I am using this class as sigelton, but don't think this is relevant as everyting else works). I am initianalizing SoundPool, a HashMap, and get the context for AudioManager. Thereafter I am loading two sounds.
MySoundpool is used by method MySoundPool.playSound(int index, float rate)
playSound clips rate to 0.5 <= rate >= 2.0 an executes statements
float streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
streamVolume = streamVolume / mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
mSoundPool.play(mSoundPoolMap.get(index), streamVolume, streamVolume, index, 0, rate);
So far so good. Everything works fine.
No it happens that playSound is called while the previous sound still plays, and I want to stop that before playing the new sound. Prior to the above code snippet I tried
mSoundPool.stop(mSoundPoolMap.get(index));
and
mSoundPool.autoPause();
with no success. The sound just continues to play to its end.
Any comments will be appreciated
I assume that you create a new SoundPool object in the constructor of your MySoundPool class?
If so then the first argument that SoundPool's constructor takes is the number of streams to allow at the same time. for example...
mSoundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
That will allow 10 sounds to play at once so just change the 10 to a 1 and that should do it.
Edit:
The stop() method takes a stream id as an argument, which should be the number returned from the play() method. You could try setting a variable equal to what play() returns and then use that variable when stopping the sound.
Use the soundId to play a sound but use the streamId to stop it. These are not always the same number!
When you start the sound, store the returned streamId:
int myStreamId = mSoundPool.play(mSoundPoolMap.get(index), streamVolume, streamVolume, index, 0, rate);
Then use that streamId (not the soundId) to stop the sound:
mSoundPool.stop(myStreamId);
As it says in the class document:
public final int play (int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)
Since: API Level 1
Play a sound from a sound ID. Play the sound specified by the soundID. This is the value returned by the load() function. Returns a non-zero streamID if successful, zero if it fails. The streamID can be used to further control playback.
Returns
non-zero streamID if successful, zero if failed
Had the same problem, why does one not read the F M ! :D
-Thanks guys!
I have a .wav file that I'd like to use across my game, currently I am loading the sound in onCreate() of each activity in the game.
soundCount = soundpool.load(this,R.raw.count, 1);
The sound will be played once the activity starts.
soundpool.play(soundCount, 0.9f, 0.9f, 1, -1, 1f);
Problem is at times I will hit the error "sample x not ready".
Is it possible to load the .wav file once upon starting the game and keep it in memory and use it later across the game? Or is it possible to wait for 1-2 seconds for the sound to load finish?
You'll need to wait for it to finish by adding a listener via SoundPool.setOnLoadCompleteListener.
Since my project is compatible with Android 1.5 and I couldn't use setOnLoadCompleteListener, I resolved making the play of sound delayed.
My source code follows:
playSound_Delayed(soundId, 100);
// (..)
private void playSound_Delayed (final int soundId, final long millisec) {
// TIMER
final Handler mHandler = new Handler();
final Runnable mDelayedTimeTask = new Runnable() {
int counter = 0;
public void run() {
counter++;
if (counter == 1) {
boolean ret = mHandler.postDelayed(this, millisec);
if (ret==false) Log.w("playSound_Delayed", "mHandler.postAtTime FAILED!");
} else {
playSound(soundId);
}
}
};
mDelayedTimeTask.run();
}
you should use setOnLoadCompleteListener if possible ... if not, wrap a while loop around your call to 'play'. something like:
int waitLimit = 1000;
int waitCounter = 0;
int throttle = 10;
while(soundPool.play(soundId, 1.f, 1.f, 1, 0, 1.f) == 0 && waitCounter < waitLimit)
{waitCounter++; SystemClock.sleep(throttle);}
this will retry 'play' 1000 times on a 10ms interval. this should be run on a non-ui thread of course, and is still not ideal. but maybe a little stronger than waiting an arbitrary time and expecting the pool to be ready.
The SoundPool library uses the MediaPlayer service to decode the audio into a raw 16-bit PCM mono or stereo stream which we simply can call preparation of Stream, that takes some times depending on size of sound file. And if we try to play the sound before that process is over, we get "sample x not ready" error.
There are two solutions for this
implement setOnLoadCompleteListener or
wait arbitrary amount of time so that preparation is over
and then play it
Note that there is no exception for this condition or application is not crashing without any try-catch
private SoundPool soundPool;
private int my_sound;
boolean loaded = false;
// In the constructor
soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
my_sound = soundPool.load(this, R.raw.blast_sound, 1);
soundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
public void onLoadComplete(SoundPool soundPool, int sampleId,int status) {
loaded = true;
}
});
// then where ever you want to play the sound, type
if (loaded) {
soundPool.play(my_sound, 0.9f, 0.9f, 1, 0, 1f);
}
I solved with problem with simple do-while cicle. The method play() return non-zero streamID if successful, zero if failed. So, it's sufficient to check the return value.
int streamID = -1;
do {
streamID = soundPool.play(soundPoolMap.get(index), streamVolume, streamVolume, 1, 0, 1f);
} while(streamID==0);
This would work for you definitely !
public void playWavFile() {
Thread streamThread = new Thread(new Runnable() {
#Override
public void run() {
SoundPool soundPool;
final int wav;
String path = "/mnt/sdcard/AudioRecorder/record.wav";
soundPool = new SoundPool(5,AudioManager.STREAM_MUSIC, 0);
wav = soundPool.load(path, 1);
soundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
// TODO Auto-generated method stub
soundPool.play(wav,100, 100, 0, 0, 1f);
}
});
}
});
streamThread.start();
}
This sounds crazy, but don't play sounds right away. Give your app a couple of seconds to initialize the SoundPool. In my app, this was exactly the issue; I added a fake "loading" screen of ~3 seconds, and then everything worked. (I didn't even need to preload the sounds.)
I have been trying to get a few sounds to play at the same time; currently i'm using a shared instance of SoundPool. I would like 1, 2 or 3 sounds to be played at the exact same time with no lag.
When calling SoundPool.play(...) X number of times in succession, the sounds are played in that order as one might think. what is the proper what to achieve this where i can prepare all of the sounds to be played at the same time and then play them as one?
Sudo Code:
SoundPool _soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
_soundPool.load(_context, soundId1, 1);
_soundPool.load(_context, soundId2, 1);
_soundPool.load(_context, soundId3, 1);
_soundPool.play(soundId1, vol, vol, 1, 0, 1f);
_soundPool.play(soundId2, vol, vol, 1, 0, 1f);
_soundPool.play(soundId3, vol, vol, 1, 0, 1f);
i done the sound pool for one sound at time it might help you.
Android:sound pool and service
Thank you
You need to understand that SoundPool.load method is asyncronous, so when you call it 3 times in a row, and then call play, there is no garantee that this sounds actually loaded. So you need to wait until all sounds is loaded. For that use OnLoadCompleteListener:
fun loadAndPlay(soundPool: SoundPool, context: Context, resIds: IntArray) {
val soundIds = IntArray(resIds.size) {
soundPool.load(context, resIds[it], 1)
}
var numLoaded: Int = 0
soundPool.setOnLoadCompleteListener { sPool, sampleId, status ->
numLoaded++
if (numLoaded == resIds.size) {
soundPool.setOnLoadCompleteListener(null)
for (id in soundIds) {
soundPool.play(id, 1f, 1f, 1, 0, 1f)
}
}
}
}
To use:
loadAndPlay(soundPool, context, intArrayOf(R.raw.sound_1, R.raw.sound_2, R.raw.sound_3))