Android: MediaPlayer setVolume function

AndroidAudioMedia PlayerVolume

Android Problem Overview


about the params Set what to make the player no sound and full sound

Thanks

Android Solutions


Solution 1 - Android

This function is actualy wonderful. Thanks to it you can create a volume scale with any number of steps!

Let's assume you want 50 steps:

int maxVolume = 50;

Then to set setVolume to any value in this range (0-49) you do this:

float log1=(float)(Math.log(maxVolume-currVolume)/Math.log(maxVolume));
yourMediaPlayer.setVolume(log1,log1); //set volume takes two paramater

Nice and easy! And DON'T use AudioManager to set volume! It will cause many side effects such as disabling silent mode, which will make your users mad!

Solution 2 - Android

Following user100858 solution I just post my exact code that works:

private final static int MAX_VOLUME = 100;
...
...
final float volume = (float) (1 - (Math.log(MAX_VOLUME - soundVolume) / Math.log(MAX_VOLUME)));
mediaPlayer.setVolume(volume, volume);

soundVolume is the volume you would like to set, between 0 and MAX_VOLUME. So between 0 and 100 in this example.

Solution 3 - Android

For Android MediaPlayer.setVolume, searching the web seems to show 0.0f for no sound, 1.0f for full sound.

Solution 4 - Android

The other answers here are not correct--or at least, they're not configured properly.

Perform the following test, using their code (e.g. that of Tomasz or ssuukk):

  1. Set 100 as the "max volume"/number of steps, and submit the volume 50.

It returns: 0.150514997831991

  1. Set 1000 as the "max volume"/number of steps, and submit the volume 500.

What does it return? The same value, 0.150514997831991, right?

Nope. Instead, it's: 0.100343331887994

In other words, the existing answers change how they scale the input volume-percent (i.e. the transformation curve) based on how many volume-steps you set.

I've spent the last few hours looking into this issue; enough that I don't feel like going into too much detail explaining the issue. Instead I'll just post the large code/comment block in my program concerning it. (it's in C#, for Xamarin Android, but the functionality should be the same for Java)

public enum VolumeScaleType
{
    //Energy, // what MediaPlayer possibly treats passed values as
    Amplitude, // what MediaPlayer most likely treats passed values as
    Loudness // what people treat everyday volume values as (as in "that sounded 2 times as loud")
}

// MediaPlayer
/*public static void SetVolume_IncorrectSOApproach(this MediaPlayer s, double volume, VolumeScaleType volumeType = VolumeScaleType.Loudness)
{
    const int maxVolume = 100;
    var volume_toScale = volume * maxVolume;
    double volume_scalar = volumeType == VolumeScaleType.Amplitude ? volume : (1 - (Math.Log(maxVolume - volume_toScale) / Math.Log(maxVolume)));
    s.SetVolume((float)volume_scalar, (float)volume_scalar);
}*/

public static void SetVolume_MyPossiblyCorrectApproach(this MediaPlayer s, double volume, VolumeScaleType volumeType = VolumeScaleType.Loudness)
{
    // Links:
    // 1) http://en.wikipedia.org/wiki/Decibel
    // 2) http://trace.wisc.edu/docs/2004-About-dB
    // 3) http://hyperphysics.phy-astr.gsu.edu/hbase/sound/loud.html
    // 4) http://www.animations.physics.unsw.edu.au/jw/dB.htm
    // 5) http://www.soundmaskingblog.com/2012/06/saved_by_the_bell
    // 6) http://www.campanellaacoustics.com/faq.html
    // 7) http://physics.stackexchange.com/questions/9113/how-sound-intensity-db-and-sound-pressure-level-db-are-related
    // 8) http://www.sengpielaudio.com/calculator-loudness.htm (note: page uses terms 'power/intensity' and 'pressure' differently; power/intensity: for whole shell at distance, pressure: field-quantity?)
    // basic idea: you can think of one decibel (of gain), + or -, as *translating into* the given changes-in/multipliers-for energy, amplitude, or loudness
    // (i.e. one decibel provides a specific amount to multiply energy, amplitude, and loudness values, such that they remain aligned realistically)
    // note: the 'one decibel' unit is set up to correspond roughly to a change in loudness just substantial enough to be noticeable
    // note: the 'quietest perceivable sound' example (standard) base has these absolute values: 'e' is 1 pico-watt per square-foot, 'a' is 20 micropascals, 'l' is the quietest-perceivable-loudness

    // references (for q.p.s. base)   | db (gain) | energy           | amplitude            | loudness
    // ===============================================================================================
    // actual silence                 | -inf      | 0                | 0                    | 0
    // (a seeming silence)            | -20       | e / 100          | a / 10               | 0 (would be l / 4, if 'l' weren't already for the quietest-perceivable-sound)
    // (a seeming silence)            | -10       | e / 10           | a / 3.16227/sqrt(10) | 0 (would be l / 2, if 'l' weren't already for the quietest-perceivable-sound)
    // quietest perceivable sound     | 0         | e                | a                    | l
    // ?                              | 1         | e * 1.258925     | a * 1.122018         | l * 1.071773
    // rustling leaves                | 10        | e * 10           | a * 3.16227/sqrt(10) | l * 2
    // whisper, or rural nighttime    | 20        | e * 100          | a * 10               | l * 4
    // watch ticking                  | 30        | e * 1000         | a * 31.622/sqrt(100) | l * 8
    // quiet speech, or rural daytime | 40        | e * 10000        | a * 100              | l * 16
    // dishwasher in next room        | 50        | e * 100000       | a * 316/sqrt(100000) | l * 32
    // ordinary conversation          | 60        | e * 1000000      | a * 1000             | l * 64
    // ===============================================================================================

    // assuming MediaPlayer.SetVolume treats passed values as Amplitude
    Func<double, double> convertLoudnessToAmplitude = loudness=>Math.Pow(10, Math.Log(loudness, 4));
    var volume_amplitude = volumeType == VolumeScaleType.Amplitude ? volume : convertLoudnessToAmplitude(volume);
    s.SetVolume((float)volume_amplitude, (float)volume_amplitude);
    // assuming MediaPlayer.SetVolume treats passed values as Energy
    //Func<double, double> convertLoudnessToEnergy = loudness=>Math.Pow(100, Math.Log(loudness, 4));
    //var volume_energy = volumeType == VolumeScaleType.Energy ? volume : convertLoudnessToEnergy(volume);
    //s.SetVolume((float)volume_energy, (float)volume_energy);
}

Conclusion

The documentation is sparse, so I can't know for sure if I have the right scaling-system/type-of-unit the SetVolume method expects.

Assuming it expects an Amplitude value, the code above may be the correct volume setting code for it. (taking desired Loudness, linear, as an input, and outputting/setting the Amplitude value needed for the built-in SetVolume method)

I'm not sure it's correct, though, and am too tired to confirm. If anyone has further thoughts, feel free to add them. (3+ hours is enough to spend on an issue like this, in one day)

Edit

After listening carefully, and comparing the loudness-fade effect by:

  1. Just submitting the desired loudness to the SetVolume method.
  2. Exponentiating (basically) the desired-loudness before sending it in, to make it an Amplitude (or the like) value that the SetVolume method says it expects.

I find that option 1 seems to be closer to a linear loudness fade-in! In other words... from actually listening and comparing the basic approach, with the various transformation approaches shown here, it seems the documentation is wrong and the SetVolume method does in fact just expect the loudness value on a linear scale. (perhaps they've updated it to work more intuitively in one of the recent API versions, but haven't updated the docs?)

If so, that sure makes it easy. That's what I'm going with for now. (though I'll keep the exponentiation/scale-fixing approach as a program setting, I suppose, just to have an excuse to keep some result of all that time invested!)

Solution 5 - Android

The recommended answer is wrong, as stated Venryx. Log math doesn't work that way (you have to subtract, not divide logs to make them work how you want).

No matter, it looks like Android Volume setting is now proportionate to Loudness linearly... so 0.5 is 50% as loud as 1.0, and 0.1 is 10%, etc. No need for complicated Log math to convert decibels to loudness. Just set it linearly as is intuitive to most people.

Solution 6 - Android

I have tried Android MediaPlayer.setVolume, but this function is useless.

I think we should use the function below

AudioManager mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, maxVolume * mLastProgress / 10, 0);

Solution 7 - Android

Everything I have seen here has fallen short of my expectations. The main problem I had was that on a scale of 0 to 50, 25 was never in the middle but rather much closer to the maximum sound. The log functions proposed here made almost no difference for me.

To read more on the math, see this answer.

Variables

Linear input value   = x      // User-specified input value
Linear scale min,max = x1,x2  // My pre-determined range of 0-50 on my UI
Log scale min,max    = y1,y2  // Normalizes the log result to between 0-1
Log value result     = z      // The output to pass to the setVolume() method

Formula where change decelerates as value goes up (simplest form)

Problem with this approach is that this is the opposite of what we want with android because it seems to already be doing this by default. It's already incrementing too fast when the values are still low when you pass linear values and this accentuates this effect even further.

x1 + (log(x) - log(x1)) / (log(x2) - log(x1)) * (y2 - y1) = z

Results of this function

Formula where change accelerates as value goes up

This is the approach that works for me; flipping the input to keep the same rate of change, but inversed. With this, I get just about a perfect mid-volume at around 25 and it's a very smooth hearing experience from 0 all the way to 50.

y2 - (x1 + (log(x2 + x1 - x) - log(x1)) / (log(x2) - log(x1)) * (y2 - y1)) = z

Results of this function

Solution 8 - Android

This code breaks down volume into 10 equal sections and increase or descrease volume.

Button decreaseVolButton = (Button) findViewById(R.id.decrease_volumn);
Button increaseVolButton = (Button) findViewById(R.id.increase_volumn);

final MediaPlayer mediaPlayer = MediaPlayer.create(MainActivity.this, R.raw.sample);

decreaseVolButton.setOnClickListener(new View.OnClickListener() {
	@Override
	public void onClick(View v) {
		volume = (float) (volume - 0.1);
		mediaPlayer.setVolume(volume, volume);
	}
});
increaseVolButton.setOnClickListener(new View.OnClickListener() {
	@Override
	public void onClick(View v) {
		volume = (float) (volume + 0.1);
		mediaPlayer.setVolume(volume, volume);
	}
});

If you want to set the volume to no sound then pass (0f,0f)

If you want to set the volume to full sound then pass (1f,1f)

Solution 9 - Android

Why making it so complicated? I am using this simple formula:

public float getVolume() {
    float currVolume = (float) sp.getInt("volume", 10);
    float maxVolume = 15.0f;
    float result = currVolume / maxVolume;
    return result;
}

and setting this value in media player, like:

player.setVolume(getVolume(), getVolume());

Solution 10 - Android

Since volume scales linearly, needless for complicated log function. Adjust the maxVolume, it's 100 steps in the sample code below, accordingly to the step you prefer and it should work. Hope this would help.

MediaPlayer myPlayer = MediaPlayer.create(MainActivity.this, R.raw.myAudioResource);

final float maxVolume = 100.0f;
float currentVolume = 5.0f;

myPlayer.setVolume(currentVolume/maxVolume, currentVolume/maxVolume);
myPlayer.start();

Solution 11 - Android

Well, I made the following code and it slightly works:

public class MainActivity extends Activity {

    float volumeLevel = 0.5f;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        volumeUp = findViewById(R.id.volUp);
        volumeDown = findViewById(R.id.volDown);

        song = MediaPlayer.create(this, R.raw.audioFile);    

        volumeUp.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v){
                volumeLevel = volumeLevel + 0.1f;
                song.setVolume(volumeLevel,volumeLevel);
            }
        });

        volumeDown.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                volumeLevel = volumeLevel - 0.1f;
                song.setVolume(volumeLevel,volumeLevel);
            }
        });
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionQingView Question on Stackoverflow
Solution 1 - AndroidssuukkView Answer on Stackoverflow
Solution 2 - AndroidTomaszView Answer on Stackoverflow
Solution 3 - Androidtypo.plView Answer on Stackoverflow
Solution 4 - AndroidVenryxView Answer on Stackoverflow
Solution 5 - AndroidnajakView Answer on Stackoverflow
Solution 6 - AndroidAllen ZhangView Answer on Stackoverflow
Solution 7 - AndroidJon BView Answer on Stackoverflow
Solution 8 - Androidrakesh kumarView Answer on Stackoverflow
Solution 9 - AndroidJanView Answer on Stackoverflow
Solution 10 - Android1DDView Answer on Stackoverflow
Solution 11 - AndroidmQadryView Answer on Stackoverflow