Search code examples
javaandroidandroid-animationandroid-mediaplayersoundpool

How to Play 'Tick Tick' Sound with Android Animation (possibly with `Android MediaPlayer / SoundPool`)?


I have a custom view (PieView) that is has a rotating animation. Now I would like to play tick tick tick tick... sound synchronously with the rotation speed (that is, when the rotation speed is fast, the tick tick should be fast, when rotation is slow, the tick tick should be slow). To do this, first I created an mp3 file named magicbox_tick.mp3 that has only ONE (1) tick. Next I tried to play the sound with Animation.setUpdateListener().

First I tried to play music with MediaPlayer but after some 10 or 15 ticks, it stoped. So now I am trying SoundPool to play the music.

The relevant code segment looks like this:

public PieView extends View {
  // ... constructors, other methods etc
  private SoundPool soundPool;
  private int soundId;

  void init(){  // called inside those constructors
        SoundPool soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
        soundId = soundPool.load(getContext(), R.raw.magicbox_tick, 1);
  }

  public void rotateTo(){
    animate()..setInterpolator(new DecelerateInterpolator())
                .setDuration(mDuration)
                .setListener(someListener)
                .rotation(targetAngle)
                .setUpdateListener(animation -> {
                    myPlaySound();  // <----------------------- This is the sound playing code
                })
                .start();
  }

  void myPlaySound(){
          soundPool.play(soundId, 1, 1, 0, 0, 1); // this doesnot play the `tick` sound
          // previously I used MediaPlayer like this:
         /*
            MediaPlayer mp = new MediaPlayer.create(getContext(), R.raw.magicbox_tick);
            mp.play(); 
               // these 2 line, after some 10 ticks, stopped working. 
          */
  }

}

I have never done anything like this, and I don't know how to fix this. Can anyone help me? Please note that I am open to all answers as long as it works. You don't have to use SoundPool. So suppose if you can make it work with android MediaPlayer, I am ok with that.


Solution

  • Special thanks to Mr Mike M for his valuable comment. I was able to fix it using MediaPlayer. MediaPlayer.release() method should be called. And to make the sound synced with the angular motion, I kept an if block that checks if the rotation dTheta is greater than tolerance angle. So, if anyone needs it, the complete code looks like this:

    public PieView extends View{
         private float omega0; // holds the previous rotation
        /**
         * @brief: plays a music using mediaPlayer
         * @input:
         * @output: void, plays a music
         * */
        private void myPlayTick() {
            float omega1 = Math.abs(getRotation());
            float dOmeda = 0;
            if(omega1>omega0){
                dOmeda = omega1 - omega0;
            }else{
                dOmeda = omega0-omega1;
            }
            if(dOmeda > threshold){
                omega0 = omega1; // update previous rotation
                final MediaPlayer mp = MediaPlayer.create(getContext(), R.raw.magicbox_tick);
                mp.start();
                mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                    @Override
                    public void onCompletion(MediaPlayer mp) {
                        releaseMediaPlayer(mp);
                    }
                });
            }
        }
    
        /**
         * @brief: releases mediaPlayer resource so that other mediaPlayers can use sound hardware resources
         * @input: MediaPlayer object
         * @output: void
         * */
        private void releaseMediaPlayer(MediaPlayer mediaPlayer) {
            try {
                if (mediaPlayer != null) {
                    if (mediaPlayer.isPlaying())
                        mediaPlayer.stop();
                    mediaPlayer.release();
                    mediaPlayer = null;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
     public void rotateTo(){
        animate()..setInterpolator(new DecelerateInterpolator())
                    .setDuration(mDuration)
                    .setListener(someListener)
                    .rotation(targetAngle)
                    .setUpdateListener(animation -> {
                       myPlayTick();                  
                    })
                    .start();
      }
         // ... rest of the code, such as constructors, etc
    }