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))
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);
I have some sounds in a SoundPool that I need to play. Sometimes when they should play, there's just a low pitched click sound instead of the sound that should play. Sometimes they play just fine.
Here's the code I use for the SoundPool:
open class PingSoundPool(context: Context) {
open var mAttributes = AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_GAME)
.build()
open var mSoundPool = SoundPool.Builder()
.setMaxStreams(9)
.setAudioAttributes(mAttributes)
.build()
open var babping = mSoundPool.load(context, R.raw.ab830ping, 1)
open var aaping = mSoundPool.load(context, R.raw.a220ping, 1)
open var abbping = mSoundPool.load(context, R.raw.bb233ping, 1)
open var abping = mSoundPool.load(context, R.raw.b247ping, 1)
[and others]
open fun loadPings(note: Int) {
println(note.toString())
if (note == 0) {}
if(note == 1)
mSoundPool.play(acping, 2.55f, 2.55f, 1, 0, 1f)
if(note == 2)
mSoundPool.play(adbping, 2.5f, 2.5f, 1, 0, 1f)
if(note == 3)
mSoundPool.play(adping, 2.45f, 2.45f, 1, 0, 1f)
if(note == 4)
mSoundPool.play(aebping, 2.4f, 2.4f, 1, 0, 1f)
[and so on]
}
Now I make this accessible within my activity:
companion object {
lateinit var pingSoundPool: PingSoundPool
}
And in onCreate I do pingSoundPool = PingSoundPool(this)
Like this, I should be able to play any of these sounds with FullscreenActivity.pingSoundPool.loadPings(note: Int) - as stated above, this sometimes works, sometimes it doesn't, even for repetitions of the same sound.
One observation is that println(note.toString()) prints the Int corresponding to the note that should be played, regardless of whether the note can actually be heard. However, every time the note is actually played, that number is followed by W/AudioTrack: AUDIO_OUTPUT_FLAG_FAST denied by client; transfer 4, track 44100 Hz, output 48000 Hz - All these come up in Android Studio's logcat.
This happens in the emulator as well as on real devices.
Any ideas?
The solution is this: the volume only accepts values from 0.0f to 1.0f. I tried setting them all to 1.0f and now it works fine.
if(note == 4) mSoundPool.play(aebping, 2.4f, 2.4f, 1, 0, 1f) // wrong
if(note == 4) mSoundPool.play(aebping, 1.0f, 1.0f, 1, 0, 1f) // right
I am using soundpool to play short audio files . Once I click the button it should play audio and second time it should pause stream . I used function like this detectPlayPause(sound2, activity!!.applicationContext)
The problem is it is not pausing and it is playing that sound again as a two stream
fun detectPlayPause(sound: Int, context: Context) {
val audioManager = context.getSystemService(AUDIO_SERVICE) as AudioManager
if (audioManager.isStreamMute(sound)) {
soundPool.play(sound, 1F, 1F, 0, -1, 1F)
} else {
soundPool.pause(sound)
}}
**
You're mis-using audioManager.isStreamMute(). That function takes an AudioManager constant, like STREAM_MUSIC. That is a different thing than the sound ID returned from SoundPool.load().
isStreamMute() won't tell you whether or not your sound is playing. That's more for detecting the device's mute settings; whether the user has selected mute/vibrate/silent, etc.
Instead, just track your play state using a boolean variable.
if (!playing) {
playing = true
soundPool.play(sound, 1F, 1F, 0, -1, 1F)
} else {
playing = false
soundPool.pause(sound)
}
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 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.)