1

I am making an Android game where I need to implement lag-free sound effects when the player interacts with a game object. To keep it simple, the objects are moving around on the screen and the player must tap them in order to trigger a sound effect. The issue I am having is that when the player taps many objects in a short amount of time, there is a noticeable delay between each sound effect. So for example, the player taps object 1, sound plays, taps object 2, sound plays, and keeps going until the player taps object n, the sound plays but sounds a bit delayed from previous sound effects that played.

I tried to set my SoundPool objects to load different sounds from the same resource but it didn't seem to do much. So is there a way for each iterations of the sound effect to overlap or even stop the previous iteration of the sound effect to be replaced by the new one without experiencing a noticeable delay in sound? Below is my code:

protected SoundPool mSoundPool;
protected boolean mLoaded;
protected int mBalloonPopStreams = 5;
protected int[] mSoundIds;
protected int mSoundIdx = 0;

protected void initializeMedia() {
    this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
    mSoundPool = new SoundPool(mBalloonPopStreams, AudioManager.STREAM_MUSIC, 0);

    mSoundIds = new int[mBalloonPopStreams];
    for (int i = 0; i < mBalloonPopStreams; i++) {
        mSoundIds[i] = mSoundPool.load(this, R.raw.sound_effect, 1);
    }
    mSoundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
        @Override
        public void onLoadComplete(SoundPool soundPool, int sampleId,
                int status) {
            mLoaded = true;
        }
    });
}

protected OnTouchListener mTouchEvent = new OnTouchListener() {
    @Override
    public boolean onTouch(View arg0, MotionEvent arg1) {           
        int action = arg1.getAction();
        int actionCode = action & MotionEvent.ACTION_MASK;
        int pointerId = action >> MotionEvent.ACTION_POINTER_ID_SHIFT;
        int x;
        int y;

        x = (int)arg1.getX(pointerId);
        y = (int)arg1.getY(pointerId);
        if (actionCode == MotionEvent.ACTION_DOWN || actionCode == MotionEvent.ACTION_POINTER_DOWN) {
            // Check if the player tapped a game object
            playSound();
        }


        return true;
    }
};

public void playSound() {
    if (mLoaded) {
        synchronized(mSoundPool) {
            AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
            float actualVolume = (float) audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
            float maxVolume = (float) audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
            float volume = actualVolume / maxVolume;
            mSoundPool.play(mSoundIds[mSoundIdx], volume, volume, 1, 0, 1f);
            mSoundIdx = ++mSoundIdx % mBalloonPopStreams;   
        }
    }
}

To sum it up, the problem is that, let's say 5 "pop" sounds are to be played within 1 second. I hear the popping sounds play 5 times but they are delayed and out of sync with what's actually going on in the game. Could this be a limitation on hardware? If not, then have I implemented my code incorrectly? What are some workarounds to this problem?

Dan
  • 842
  • 3
  • 17
  • 29

2 Answers2

0

You may obtain better result using AudioTrack instead of SoundPool at the cost of more code on your side.

Aladin Q
  • 550
  • 5
  • 12
0

This answer to a similar question might help. The OP of that question was having their app crash if they tried to play multiple sounds with SoundPool, but it might be a different symptom of the same problem.

Community
  • 1
  • 1
MusiGenesis
  • 74,184
  • 40
  • 190
  • 334
  • That didn't quite solve my problems. The killable queue did not do anything meaningful as my sound effects are very short. My concern about the SoundPool object is whether it allows concurrent playback of audio tracks, i.e. are each sound effects played on separate threads? – Dan Dec 10 '11 at 22:35