Android Studio中MediaPlayer如何实现淡入淡出效果

12

我正在使用Android Studio中的MediaPlayer类。我只想淡出一个声音并淡入另一个声音,而不是使用setVolume(0,0)和setVolume(1,1)。

我为此创建了两个MediaPlayer,并在此线程中找到了解决方案:Android:如何为应用程序播放的任何音乐文件创建淡入/淡出音效? ,但我不知道如何使用deltaTime。

还有一些其他解决方案,但我几乎无法理解。难道没有一种简单的方法可以交叉淡化两个MediaPlayer吗? 我无法想象没有人需要这样做或者每个人都使用繁琐的代码来实现它。 deltaTime应该如何使用?

4个回答

20

查看示例,您需要在循环中调用fadeIn()/fadeOut(),以在一段时间内增加/减小音量。 deltaTime 是循环每次迭代之间的时间。

您必须在与主UI线程分开的线程中执行此操作,以便不会阻塞它并导致应用程序崩溃。您可以通过将此循环放入新的Thread/Runnable/Timer来实现。

这是我的淡入示例(您可以为淡出做类似的事情):

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;

}

在您的情况下,我建议使用一个MediaPlayer对象并在淡入淡出之间切换音轨,而不是使用两个单独的MediaPlayer对象。

**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**
希望这能解决你的问题。

希望这能解决你的问题。


谢谢,这很有帮助,因为我还没有找到其他可行的解决方案!同时,在新线程上运行的提示也非常有用!谢谢! - olop01
1
这对我来说完美无缺。非常感谢这个惊人的解决方案。现在就进一步开发而言,是否可能在两首歌曲交叉淡出时重叠它们?! - Varun Barve
遗憾的是我已经有一段时间没使用Android了,但你可以尝试在不同的顺序中使用以上代码:setup1、start1、setup2、start2、fadeout1和fadein2、stop1... 但你肯定需要为每首歌使用一个单独的MediaPlayer对象。试一下,让我们知道你发现了什么。 - ak93
非常感谢!我有不同的活动,它们使用自己的相同声音类的实例,并且与Ben提供的淡出效果一起,有一个完美的交叉淡化。 - Danny E.K. van der Kolk

2

以下是淡出代码,以防节省他人的时间。

这还包括一个stopPlayer()函数来释放MediaPlayer的内存。这是一个好习惯。

"Original Answer"翻译成中文是 "最初的回答"。

// 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;
    }
}

谢谢你的帮助,Ben。我有不同的活动,它们使用自己的相同声音类实例,并且与ak93提供的淡入淡出一起,可以完美地交叉淡入淡出。 - Danny E.K. van der Kolk

2
在API Level 26中添加了一个VolumeShaper类(https://developer.android.com/guide/topics/media/volumeshaper)。 以下是音量输出和输入的示例,您可以通过向times和volumes数组添加更多点来形成淡入或淡出速度(ramp)。 时间点必须从0开始,以1结束,并且它们是音量斜坡的相对时间。
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)
}

0
private void fadeOut() {

    final long steps = 30;
    final double stepWidth = (double) 1 / steps;

    mFadeOutCriteria = 1;

    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            mFadeOutCriteria -= stepWidth;
            mediaPlayer.setVolume(mFadeOutCriteria, mFadeOutCriteria);

            if (mFadeOutCriteria <= 0) {
                mediaPlayer.stop();
                nextrunq();
                mFadeOutCriteria = 0;
                handler.removeCallbacks(this);
            } else
                handler.postDelayed(this, 100);
        }
    }, 100);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接