开发者

Lower or fade sound in android

I'm making a simple trivia game, and running a looping ~1 min mp3 file when the user arrives at the main menu. The sound is 开发者_StackOverflow中文版set to stop when user clicks any of the buttons on the menu (i.e. Play Game).

My problem is that when the sound stops, its kind of a jarring cut off. Rather than do .pause() or .stop(), is there a way to make the sound slowly fade out after a button is pressed?

Thanks


EDIT (3/13/13): Updated with new QA'd code

This is my entire handler class for Android MediaPlayer. Look at the play() and pause() functions. Both contain the ability to either fade or not. The updateVolume() function was the key to let the sound increase/decrease linearly.

public class MusicHandler 
{
private MediaPlayer mediaPlayer;
private Context context;
private int iVolume;

private final static int INT_VOLUME_MAX = 100;
private final static int INT_VOLUME_MIN = 0;
private final static float FLOAT_VOLUME_MAX = 1;
private final static float FLOAT_VOLUME_MIN = 0;

public MusicHandler(Context context)
{
    this.context = context;
}

public void load(String path, boolean looping)
{
    mediaPlayer = MediaPlayer.create(context, Uri.fromFile(new File(path)));
    mediaPlayer.setLooping(looping);
}

public void load(int address, boolean looping)
{
    mediaPlayer = MediaPlayer.create(context, address);
    mediaPlayer.setLooping(looping);
}

public void play(int fadeDuration)
{
    //Set current volume, depending on fade or not
    if (fadeDuration > 0) 
        iVolume = INT_VOLUME_MIN;
    else 
        iVolume = INT_VOLUME_MAX;

    updateVolume(0);

    //Play music
    if(!mediaPlayer.isPlaying()) mediaPlayer.start();

    //Start increasing volume in increments
    if(fadeDuration > 0)
    {
        final Timer timer = new Timer(true);
        TimerTask timerTask = new TimerTask() 
        {
            @Override
            public void run() 
            {
                updateVolume(1);
                if (iVolume == INT_VOLUME_MAX)
                {
                    timer.cancel();
                    timer.purge();
                }
            }
        };

        // calculate delay, cannot be zero, set to 1 if zero
        int delay = fadeDuration/INT_VOLUME_MAX;
        if (delay == 0) delay = 1;

        timer.schedule(timerTask, delay, delay);
    }
}

public void pause(int fadeDuration)
{
    //Set current volume, depending on fade or not
    if (fadeDuration > 0) 
        iVolume = INT_VOLUME_MAX;
    else 
        iVolume = INT_VOLUME_MIN;

    updateVolume(0);

    //Start increasing volume in increments
    if(fadeDuration > 0)
    {
        final Timer timer = new Timer(true);
        TimerTask timerTask = new TimerTask() 
        {
            @Override
            public void run() 
            {   
                updateVolume(-1);
                if (iVolume == INT_VOLUME_MIN)
                {
                    //Pause music
                    if (mediaPlayer.isPlaying()) mediaPlayer.pause();
                    timer.cancel();
                    timer.purge();
                }
            }
        };

        // calculate delay, cannot be zero, set to 1 if zero
        int delay = fadeDuration/INT_VOLUME_MAX;
        if (delay == 0) delay = 1;

        timer.schedule(timerTask, delay, delay);
    }           
}

private void updateVolume(int change)
{
    //increment or decrement depending on type of fade
    iVolume = iVolume + change;

    //ensure iVolume within boundaries
    if (iVolume < INT_VOLUME_MIN)
        iVolume = INT_VOLUME_MIN;
    else if (iVolume > INT_VOLUME_MAX)
        iVolume = INT_VOLUME_MAX;

    //convert to float value
    float fVolume = 1 - ((float) Math.log(INT_VOLUME_MAX - iVolume) / (float) Math.log(INT_VOLUME_MAX));

    //ensure fVolume within boundaries
    if (fVolume < FLOAT_VOLUME_MIN)
        fVolume = FLOAT_VOLUME_MIN;
    else if (fVolume > FLOAT_VOLUME_MAX)
        fVolume = FLOAT_VOLUME_MAX;     

    mediaPlayer.setVolume(fVolume, fVolume);
}
}


https://stackoverflow.com/a/29246026/922514

private static void crossFade() {
    MediaPlayerManager.fadeOut(currentPlayer, 2000);
    MediaPlayerManager.fadeIn(auxPlayer, 2000);
    currentPlayer = auxPlayer;
    auxPlayer = null;
}

public static void fadeOut(final MediaPlayer _player, final int duration) {
    final float deviceVolume = getDeviceVolume();
    final Handler h = new Handler();
    h.postDelayed(new Runnable() {
        private float time = duration;
        private float volume = 0.0f;

        @Override
        public void run() {
            if (!_player.isPlaying())
                _player.start();
            // can call h again after work!
            time -= 100;
            volume = (deviceVolume * time) / duration;
            _player.setVolume(volume, volume);
            if (time > 0)
                h.postDelayed(this, 100);
            else {
                _player.stop();
                _player.release();
            }
        }
    }, 100); // 1 second delay (takes millis)


}

public static void fadeIn(final MediaPlayer _player, final int duration) {
    final float deviceVolume = getDeviceVolume();
    final Handler h = new Handler();
    h.postDelayed(new Runnable() {
        private float time = 0.0f;
        private float volume = 0.0f;

        @Override
        public void run() {
            if (!_player.isPlaying())
                _player.start();
            // can call h again after work!
            time += 100;
            volume = (deviceVolume * time) / duration;
            _player.setVolume(volume, volume);
            if (time < duration)
                h.postDelayed(this, 100);
        }
    }, 100); // 1 second delay (takes millis)

}
public static float getDeviceVolume() {
    int volumeLevel = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
    int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);

    return (float) volumeLevel / maxVolume;
}


You can use AudioManager:

public static final int STEP_DOWN = 5; // how far each step goes down
// later on, and in a backgroud thread like an AsyncTask
AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
int targetVol = 0; // or whatever you wanted.
int currentVol = am.getStreamVolume(AudioManager.STREAM_MUSIC);
while(currentVol > targetVol)
{
    am.setStreamVolume(AudioManager.STREAM_MUSIC, currentVol - STEP_DOWN, 0);
    currentVol = am.getStreamVolume(AudioManager.STREAM_MUSIC);
    thread.sleep(100);   
}

You probably also want to record the original volume they had media set to, and reset it to that after you fade out to mute and stop your music.

That code may not be exact, I don't currently have access to any way of testing it, but I hope it leads you in the right direction....

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜