Android: MediaPlayer setVolume function
Asked Answered
T

11

65

About the params, what do I need to do to make the player make no sound and to make full sound.

Tetragonal answered 7/3, 2011 at 3:17 Comment(0)
S
129

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!

Sheedy answered 22/8, 2012 at 14:56 Comment(9)
+1000 I've been looking for this solution for some time. Fantastic. Thanks!Eccentricity
I have to use AudioManager when trying to mute in Text to Speech. Is there any better way to set mute in Text to Speech?Trichotomy
Have you tried manipulating AudioManager.STREAM_MUSIC stream?Sheedy
@Sheedy setVolume method has two parameters setVolume(float, float). How are you getting away with one?Fernandes
You're right. Maybe I've taken a shortcut writing this, maybe it's a code applying volume to some custom media player class. Note that if you've used Kotlin instead of Java you could write an extension function to MediaPlayer that does this: MediaPlayer.setVolume(x : Float) {...}Sheedy
log(maxVolume - currVolume) will return float infinity when (maxVolume == currVolum), so it's better to check thisGerundive
@Sheedy What is the formula if currVolume is a float varying between 0 and 1. I am using an animation to hide a view, and simultaneously lowers the volume on player. Animation is value animator (1F -> 0F), and I do not want to make a redundant conversion from animation value to integer volume mentioned in this answer.Chump
@Gerundive currVolume is an integer in the range [0,maxVolume-1] so it should not be possible for it to have the value of maxVolume. Note that for currVolume == maxVolume-1 you get log1 == 0 and setVolume(1) (or, using the current signature of the method: setVolume(1,1)), meaning full volume.Yes
Any way of getting the volume?Off
E
62

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.

Eccentricity answered 30/8, 2012 at 13:0 Comment(5)
what is soundVolume ? Where does it originate ?Saturday
@SomeoneSomewhere... It Comes from SomeWhere.. :PSpermatozoon
Dude that is the volume we want to set... :PSpermatozoon
To those of you wondering, soundVolume is the variable between 0-100 that you want the volume to be. If you want a finer adjusted tune, consider setting the maxVolume up to 1000 and of course keep the soundVolume between 0-1000 then.Kowatch
Note that even though you are denoting a max volume of 100. That this function actually returns a value between 0.0 and 1.0. If you manually want to reset the volume to max you can use mediaPlayer.setVolume(1.0, 1.0)Rage
T
44

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

Tribromoethanol answered 7/3, 2011 at 3:25 Comment(3)
This is not the correct solution. It does not scale the volume lineally. I mean the volume grows quickly between 0 and 0.5 but very slowly between 0.5 and 1.0. Check user100858 solution below, it works great.Eccentricity
1.0f is for full sound of the stream volume of AudioManager. For example, if the stream volume is set 20%, the MediaPlayer volume is set 1.0f, the volume will be 20% of max volume.Trudi
This answer is outdated. In newer versions of Android, 0.5 is 50% as loud as 1, which makes it easy. (the docs do appear to be outdated on this, but you can confirm it by doing careful by-ear testing/comparison -- which is what matters in the end anyway)Nudity
N
16

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

2) 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!)

Nudity answered 13/12, 2015 at 17:48 Comment(0)
P
10

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.

Potboiler answered 7/4, 2016 at 9:34 Comment(0)
B
6

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);
Bassarisk answered 14/8, 2012 at 8:7 Comment(2)
What made MediaPlayer.setVolume useless? What weren't you able to do?Henrieta
AudioManager will set the system volume, which you don't want to do. If the user has their phone on silent, and you suddenly blast out music, they won't appreciate it ;)Androclinium
A
2

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

Agrarian answered 2/11, 2018 at 2:36 Comment(0)
B
1

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)

Billiot answered 22/10, 2018 at 21:4 Comment(0)
G
0

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());
Granuloma answered 20/2, 2015 at 13:11 Comment(5)
What's sp in this code snippet above? SharedPreferences?Birthwort
MediaPlayer documentation recommends: "Note that the passed volume values are raw scalars in range 0.0 to 1.0. UI controls should be scaled logarithmically.".Selfoperating
FuzzyAmi , yes sp is shared preference.Granuloma
@PawełNadolski after dividing it with max volume , the result will be equal or less than 1.0.Granuloma
@Jan, yes, but it won't be scaled logarithmically :) So, your approach is correct, but not recommended by official documentation.Selfoperating
D
0

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();
Dockery answered 25/6, 2020 at 10:28 Comment(0)
H
-1

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);
            }
        });
    }
}
Hawger answered 14/5, 2019 at 3:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.