Android Studio Mediaplayer how to fade in and out

2020-08-17 03:07发布

问题:

I am working with the mediaplayer class in android studio. I simply want to fade out one sound and fade in the other sound instead of using setVolume(0,0) and setVolume(1,1).

I have created two mediaplayers for this and it seemed like I found a solution in this thread: Android: How to create fade-in/fade-out sound effects for any music file that my app plays? but I don't know how to use deltaTime.

There are also some other solutions to this, which I can barely understand. Isn't there an easy way to cross fade two mediaplayers, I can not imagine no one has needed this yet or everyone uses obsessive code to achieve it. And how should I use deltaTime?

回答1:

Looking at the linked example, you would have to call fadeIn()/fadeOut() in a loop, to increase/decrease the volume over a period of time. deltaTime would be the time between each iteration of the loop.

You'd have to do this in a separate thread from your main UI thread, so you don't block it and cause your app to crash. You can do this by either putting this loop inside a new Thread/Runnable/Timer.

Here is my example for fading in (you can do a similar thing for fading out):

float volume = 0;

private void startFadeIn(){
    final int FADE_DURATION = 3000; //The duration of the fade
    //The amount of time between volume changes. The smaller this is, the smoother the fade
    final int FADE_INTERVAL = 250;
    final int MAX_VOLUME = 1; //The volume will increase from 0 to 1
    int numberOfSteps = FADE_DURATION/FADE_INTERVAL; //Calculate the number of fade steps
    //Calculate by how much the volume changes each step
    final float deltaVolume = MAX_VOLUME / (float)numberOfSteps;

    //Create a new Timer and Timer task to run the fading outside the main UI thread
    final Timer timer = new Timer(true);
    TimerTask timerTask = new TimerTask() {
        @Override
        public void run() {
            fadeInStep(deltaVolume); //Do a fade step
            //Cancel and Purge the Timer if the desired volume has been reached
            if(volume>=1f){
                timer.cancel();
                timer.purge();
            }
        }
    };

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

private void fadeInStep(float deltaVolume){
    mediaPlayer.setVolume(volume, volume);
    volume += deltaVolume;

}

Instead of using two separate MediaPlayer objects, I would in your case use just one and swap the track between the fades. Example:

**Audio track #1 is playing but coming to the end**
startFadeOut();
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.setDataSource(context,audiofileUri);
mediaPlayer.prepare();
mediaPlayer.start();
startFadeIn();
**Audio track #2 has faded in and is now playing**

Hope this solves your problem.



回答2:

Here's the fade-out code in case it saves someone some time.

This also includes a stopPlayer() function to release the MediaPlayer from memory. It's a good practice to do so.

// Set to the volume of the MediaPlayer
float volume = 1;

private void startFadeOut(){

    // The duration of the fade
    final int FADE_DURATION = 3000;

    // The amount of time between volume changes. The smaller this is, the smoother the fade
    final int FADE_INTERVAL = 250;

    // Calculate the number of fade steps
    int numberOfSteps = FADE_DURATION / FADE_INTERVAL;

    // Calculate by how much the volume changes each step
    final float deltaVolume = volume / numberOfSteps;

    // Create a new Timer and Timer task to run the fading outside the main UI thread
    final Timer timer = new Timer(true);
    TimerTask timerTask = new TimerTask() {
        @Override
        public void run() {

            //Do a fade step
            fadeOutStep(deltaVolume);

            //Cancel and Purge the Timer if the desired volume has been reached
            if(volume <= 0){
                timer.cancel();
                timer.purge();
                stopPlayer();
            }
        }
    };

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

private void fadeOutStep(float deltaVolume){
    player.setVolume(volume, volume);
    volume -= deltaVolume;
}

// Release the player from memory
private void stopPlayer() {

    if (player != null) {

        player.release();
        player = null;
    }
}


回答3:

There's a VolumeShaper class added in API Level 26 (https://developer.android.com/guide/topics/media/volumeshaper). Here's an example of volume out and in, you can shape the fade in or out speed (ramp) adding more points to times and volumes arrays. Time points must start at 0 and end at 1 and they are relative times of volume ramping.

fun fadeOutConfig(duration: Long): VolumeShaper.Configuration {
        val times = floatArrayOf(0f, 1f) // can add more points, volume points must correspond to time points
        val volumes = floatArrayOf(1f, 0f)
        return VolumeShaper.Configuration.Builder()
            .setDuration(duration)
            .setCurve(times, volumes)
            .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_CUBIC)
            .build()
    }

fun fadeInConfig(duration: Long): VolumeShaper.Configuration {
    val times = floatArrayOf(0f, 1f) // can add more points, volume points must correspond to time points
    val volumes = floatArrayOf(0f, 1f)
    return VolumeShaper.Configuration.Builder()
        .setDuration(duration)
        .setCurve(times, volumes)
            .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_CUBIC)
            .build()
}

fun fadeInOrOutAudio(mediaPlayer: MediaPlayer, duration: Long, out: Boolean) {
    val config = if (out) fadeOutConfig(duration) else fadeInConfig(duration)
    val volumeShaper = mediaPlayer.createVolumeShaper(config)
    volumeShaper.apply(VolumeShaper.Operation.PLAY)
}