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

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

Solutions Collecting From Web of "Android:如何为我的应用播放的任何音乐文件创建淡入/淡出音效?"

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

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但是它的良好实践,因为它会在所有设备上以相同的速率降低音量

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

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

为了使它更完整,我将添加stop()函数来停止播放器的淡入淡出,并使用stopAndRelease()来停止播放器并安全地释放资源,当你调用onStop()或onDestroy()之类的Activity方法时非常有用。 。

这两种方法:

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

我一直在努力,希望它有所帮助: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; } 

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

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

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

有关多汁位,请参阅下面的computeVolume()

完整的原始代码可以在这里find: 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; }