Android:如何为我的应用程序播放的任何音乐文件创建淡入/淡出音效?

发布于 2024-11-27 06:27:43 字数 90 浏览 4 评论 0原文

我正在开发的应用程序播放音乐文件。如果计时器到期,我希望音乐淡出。我该怎么做呢。我正在使用 MediaPlayer 播放音乐,音乐文件位于我的应用程序的原始文件夹中。

The application that I am working on plays music files. If a timer expires I want the music to fade out. How do I do that. I am using MediaPlayer to play music and music files are present in raw folder of my application.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

忘你却要生生世世 2024-12-04 06:27:43

这是我的 Android MediaPlayer 的整个处理程序类。查看 play() 和pause() 函数。两者都具有褪色或不褪色的能力。 updateVolume()函数是让声音线性增加/减少的关键。

package com.stackoverflow.utilities;

import java.io.File;
import java.util.Timer;
import java.util.TimerTask;

import android.content.Context;
import android.media.MediaPlayer;
import android.net.Uri;

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

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.

package com.stackoverflow.utilities;

import java.io.File;
import java.util.Timer;
import java.util.TimerTask;

import android.content.Context;
import android.media.MediaPlayer;
import android.net.Uri;

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);
    }
}
末骤雨初歇 2024-12-04 06:27:43

一种方法是使用 MediaPlayer.setVolume(right, left) 并让这些值在每次迭代后递减。这是一个粗略的想法

float volume = 1;
float speed = 0.05f;

public void FadeOut(float deltaTime)
{
    mediaPlayer.setVolume(volume, volume);
    volume -= speed* deltaTime

}
public void FadeIn(float deltaTime)
{
    mediaPlayer.setVolume(volume, volume);
    volume += speed* deltaTime

}

FadeIn() 或一旦您的计时器到期,就应该调用FadeOut()。该方法不需要采用 deltaTime,但它更好,因为它会在所有设备上以相同的速率降低音量。

One way to do it is to use MediaPlayer.setVolume(right, left) and have these values decrement after every iteration..here is a rough idea

float volume = 1;
float speed = 0.05f;

public void FadeOut(float deltaTime)
{
    mediaPlayer.setVolume(volume, volume);
    volume -= speed* deltaTime

}
public void FadeIn(float deltaTime)
{
    mediaPlayer.setVolume(volume, volume);
    volume += speed* deltaTime

}

The FadeIn() or FadeOut() should be called once this timer of yours has expired. The method doesn't need to take the deltaTime, but it's better as it will lower the volume at the same rate across all devices.

傲影 2024-12-04 06:27:43

这是一个非常好的班级 sngreco。

为了使其更完整,我将添加 stop() 函数来停止播放器的淡入淡出,以及 stopAndRelease() 来停止播放器并安全地释放资源,这对于当您调用 Activity 方法(如 onStop() 或 onDestroy())时使用。

两种方法:

    public void stop(int fadeDuration)
{
    try {
        // 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
                        mediaPlayer.stop();
                        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);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

}

public void stopAndRelease(int fadeDuration) {
    try {
        final Timer timer = new Timer(true);
        TimerTask timerTask = new TimerTask()
        {
            @Override
            public void run()
            {
                updateVolume(-1);
                if (iVolume == INT_VOLUME_MIN)
                {
                    // Stop and Release player after Pause music
                    mediaPlayer.stop();
                    mediaPlayer.release();
                    timer.cancel();
                    timer.purge();
                }
            }
        };

        timer.schedule(timerTask, fadeDuration);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

It is a very good class sngreco.

To make it more complete I will add stop() function to stop the player with fade, and stopAndRelease() to stop the player and release the resources securely, very useful to use when you call Activity methods like onStop() or onDestroy().

The two methods:

    public void stop(int fadeDuration)
{
    try {
        // 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
                        mediaPlayer.stop();
                        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);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

}

public void stopAndRelease(int fadeDuration) {
    try {
        final Timer timer = new Timer(true);
        TimerTask timerTask = new TimerTask()
        {
            @Override
            public void run()
            {
                updateVolume(-1);
                if (iVolume == INT_VOLUME_MIN)
                {
                    // Stop and Release player after Pause music
                    mediaPlayer.stop();
                    mediaPlayer.release();
                    timer.cancel();
                    timer.purge();
                }
            }
        };

        timer.schedule(timerTask, fadeDuration);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
烟─花易冷 2024-12-04 06:27:43

我一直在研究这个问题,希望它能有所帮助:D:

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

I have been working on this I hope it helps :D :

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;
}
つ可否回来 2024-12-04 06:27:43

这是我对 Android 闹钟的淡入淡出实施的简化改编。

它不是定义步长/增量的数量,然后逐步增加音量(如该问题的其他答案),而是每 50 毫秒(可配置值)调整音量,计算出 -40dB 之间的步长/增量(接近静音)和0dB(最大;相对于流音量)基于:

  • 预设效果持续时间(可以硬编码或由用户设置)
  • 自播放开始以来经过的时间

请参阅下面的 computeVolume() 了解更多有趣的内容。

完整的原始代码可以在这里找到: Google 来源

private MediaPlayer mMediaPlayer;
private long mCrescendoDuration = 0;
private long mCrescendoStopTime = 0;

// Default settings
private static final boolean DEFAULT_CRESCENDO = true;
private static final int CRESCENDO_DURATION = 1;

// Internal message codes
private static final int EVENT_VOLUME = 3;


// Create a message Handler
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            ...

            case EVENT_VOLUME:
            if (adjustVolume()) {
                scheduleVolumeAdjustment();
            }
            break;

            ...
        }
    }
};


// Obtain user preferences
private void getPrefs() {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
    ...

    final boolean crescendo = prefs.getBoolean(SettingsActivity.KEY_CRESCENDO, DEFAULT_CRESCENDO);
    if (crescendo) {
        // Convert mins to millis
        mCrescendoDuration = CRESCENDO_DURATION * 1000 * 60;
    } else {
        mCrescendoDuration = 0;
    }

    ...
}


// Start the playback
private void play(Alarm alarm) {
    ...

    // Check to see if we are already playing
    stop();

    // Obtain user preferences
    getPrefs();

    // Check if crescendo is enabled. If it is, set alarm volume to 0.
    if (mCrescendoDuration > 0) {
        mMediaPlayer.setVolume(0, 0);
    }

    mMediaPlayer.setDataSource(this, alarm.alert);
    startAlarm(mMediaPlayer);

    ...
}


// Do the common stuff when starting the alarm.
private void startAlarm(MediaPlayer player) throws java.io.IOException, IllegalArgumentException, IllegalStateException {

    final AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);

    // Do not play alarms if stream volume is 0
    // (typically because ringer mode is silent).
    if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
        player.setAudioStreamType(AudioManager.STREAM_ALARM);
        player.setLooping(true);
        player.prepare();
        player.start();

        // Schedule volume adjustment
        if (mCrescendoDuration > 0) {
            mCrescendoStopTime = System.currentTimeMillis() + mCrescendoDuration;
            scheduleVolumeAdjustment();
        }
    }
}


// Stop the playback
public void stop() {
    ...

    if (mMediaPlayer != null) {
        mMediaPlayer.stop();
        mMediaPlayer.release();
        mMediaPlayer = null;
    }

    mCrescendoDuration = 0;
    mCrescendoStopTime = 0;

    ...
}


// Schedule volume adjustment 50ms in the future.
private void scheduleVolumeAdjustment() {
    // Ensure we never have more than one volume adjustment queued.
    mHandler.removeMessages(EVENT_VOLUME);
    // Queue the next volume adjustment.
    mHandler.sendMessageDelayed( mHandler.obtainMessage(EVENT_VOLUME, null), 50);
}


// Adjusts the volume of the ringtone being played to create a crescendo effect.
private boolean adjustVolume() {
    // If media player is absent or not playing, ignore volume adjustment.
    if (mMediaPlayer == null || !mMediaPlayer.isPlaying()) {
        mCrescendoDuration = 0;
        mCrescendoStopTime = 0;
        return false;
    }
    // If the crescendo is complete set the volume to the maximum; we're done.
    final long currentTime = System.currentTimeMillis();
    if (currentTime > mCrescendoStopTime) {
        mCrescendoDuration = 0;
        mCrescendoStopTime = 0;
        mMediaPlayer.setVolume(1, 1);
        return false;
    }
    // The current volume of the crescendo is the percentage of the crescendo completed.
    final float volume = computeVolume(currentTime, mCrescendoStopTime, mCrescendoDuration);
    mMediaPlayer.setVolume(volume, volume);

    // Schedule the next volume bump in the crescendo.
    return true;
}


/**
 * @param currentTime current time of the device
 * @param stopTime time at which the crescendo finishes
 * @param duration length of time over which the crescendo occurs
 * @return the scalar volume value that produces a linear increase in volume (in decibels)
 */
private static float computeVolume(long currentTime, long stopTime, long duration) {
    // Compute the percentage of the crescendo that has completed.
    final float elapsedCrescendoTime = stopTime - currentTime;
    final float fractionComplete = 1 - (elapsedCrescendoTime / duration);
    // Use the fraction to compute a target decibel between -40dB (near silent) and 0dB (max).
    final float gain = (fractionComplete * 40) - 40;
    // Convert the target gain (in decibels) into the corresponding volume scalar.
    final float volume = (float) Math.pow(10f, gain/20f);
    //LOGGER.v("Ringtone crescendo %,.2f%% complete (scalar: %f, volume: %f dB)", fractionComplete * 100, volume, gain);
    return volume;
}

Here is my simplified adaptation of stock Android Alarm Clock's fade in implementation.

Rather than defining the number of steps/increments and then increasing the volume step by step (as in other answers to this question), it adjusts volume every 50ms (configurable value) working out steps/increments on the scale between -40dB (near silent) and 0dB (max; relative to the stream volume) based on:

  • Preset effect duration (can be hard-coded or set by user)
  • Elapsed time since the playback started

See computeVolume() below for the juicy bits.

Full original code can be found here: Google Source

private MediaPlayer mMediaPlayer;
private long mCrescendoDuration = 0;
private long mCrescendoStopTime = 0;

// Default settings
private static final boolean DEFAULT_CRESCENDO = true;
private static final int CRESCENDO_DURATION = 1;

// Internal message codes
private static final int EVENT_VOLUME = 3;


// Create a message Handler
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            ...

            case EVENT_VOLUME:
            if (adjustVolume()) {
                scheduleVolumeAdjustment();
            }
            break;

            ...
        }
    }
};


// Obtain user preferences
private void getPrefs() {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
    ...

    final boolean crescendo = prefs.getBoolean(SettingsActivity.KEY_CRESCENDO, DEFAULT_CRESCENDO);
    if (crescendo) {
        // Convert mins to millis
        mCrescendoDuration = CRESCENDO_DURATION * 1000 * 60;
    } else {
        mCrescendoDuration = 0;
    }

    ...
}


// Start the playback
private void play(Alarm alarm) {
    ...

    // Check to see if we are already playing
    stop();

    // Obtain user preferences
    getPrefs();

    // Check if crescendo is enabled. If it is, set alarm volume to 0.
    if (mCrescendoDuration > 0) {
        mMediaPlayer.setVolume(0, 0);
    }

    mMediaPlayer.setDataSource(this, alarm.alert);
    startAlarm(mMediaPlayer);

    ...
}


// Do the common stuff when starting the alarm.
private void startAlarm(MediaPlayer player) throws java.io.IOException, IllegalArgumentException, IllegalStateException {

    final AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);

    // Do not play alarms if stream volume is 0
    // (typically because ringer mode is silent).
    if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
        player.setAudioStreamType(AudioManager.STREAM_ALARM);
        player.setLooping(true);
        player.prepare();
        player.start();

        // Schedule volume adjustment
        if (mCrescendoDuration > 0) {
            mCrescendoStopTime = System.currentTimeMillis() + mCrescendoDuration;
            scheduleVolumeAdjustment();
        }
    }
}


// Stop the playback
public void stop() {
    ...

    if (mMediaPlayer != null) {
        mMediaPlayer.stop();
        mMediaPlayer.release();
        mMediaPlayer = null;
    }

    mCrescendoDuration = 0;
    mCrescendoStopTime = 0;

    ...
}


// Schedule volume adjustment 50ms in the future.
private void scheduleVolumeAdjustment() {
    // Ensure we never have more than one volume adjustment queued.
    mHandler.removeMessages(EVENT_VOLUME);
    // Queue the next volume adjustment.
    mHandler.sendMessageDelayed( mHandler.obtainMessage(EVENT_VOLUME, null), 50);
}


// Adjusts the volume of the ringtone being played to create a crescendo effect.
private boolean adjustVolume() {
    // If media player is absent or not playing, ignore volume adjustment.
    if (mMediaPlayer == null || !mMediaPlayer.isPlaying()) {
        mCrescendoDuration = 0;
        mCrescendoStopTime = 0;
        return false;
    }
    // If the crescendo is complete set the volume to the maximum; we're done.
    final long currentTime = System.currentTimeMillis();
    if (currentTime > mCrescendoStopTime) {
        mCrescendoDuration = 0;
        mCrescendoStopTime = 0;
        mMediaPlayer.setVolume(1, 1);
        return false;
    }
    // The current volume of the crescendo is the percentage of the crescendo completed.
    final float volume = computeVolume(currentTime, mCrescendoStopTime, mCrescendoDuration);
    mMediaPlayer.setVolume(volume, volume);

    // Schedule the next volume bump in the crescendo.
    return true;
}


/**
 * @param currentTime current time of the device
 * @param stopTime time at which the crescendo finishes
 * @param duration length of time over which the crescendo occurs
 * @return the scalar volume value that produces a linear increase in volume (in decibels)
 */
private static float computeVolume(long currentTime, long stopTime, long duration) {
    // Compute the percentage of the crescendo that has completed.
    final float elapsedCrescendoTime = stopTime - currentTime;
    final float fractionComplete = 1 - (elapsedCrescendoTime / duration);
    // Use the fraction to compute a target decibel between -40dB (near silent) and 0dB (max).
    final float gain = (fractionComplete * 40) - 40;
    // Convert the target gain (in decibels) into the corresponding volume scalar.
    final float volume = (float) Math.pow(10f, gain/20f);
    //LOGGER.v("Ringtone crescendo %,.2f%% complete (scalar: %f, volume: %f dB)", fractionComplete * 100, volume, gain);
    return volume;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文