web-dev-qa-db-fra.com

Android: fonction setVolume de MediaPlayer

à propos des paramètres Définit quoi pour que le lecteur n’émette ni son ni son plein

Merci

50
Qing

Cette fonction est vraiment magnifique. Merci à cela, vous pouvez créer une échelle de volume avec un nombre quelconque d'étapes!

Supposons que vous souhaitiez 50 étapes:

int maxVolume = 50;

Ensuite, pour définir setVolume sur n’importe quelle valeur de cette plage (0 à 49), procédez comme suit:

float log1=(float)(Math.log(maxVolume-currVolume)/Math.log(maxVolume));
yourMediaPlayer.setVolume(1-log1);

Nice et facile! Et n'utilisez PAS AudioManager pour régler le volume! Cela provoquera de nombreux effets secondaires, tels que la désactivation du mode silencieux, ce qui rendra vos utilisateurs fous!

108
ssuukk

En suivant user100858 solution je poste juste mon code exact qui fonctionne:

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 est le volume que vous souhaitez définir, entre 0 et MAX_VOLUME . Donc entre 0 et 100 dans cet exemple.

47
Tomasz

Pour Android MediaPlayer.setVolume , La recherche sur le Web semble indiquer 0.0f sans son, 1.0f pour son complet. 

40
typo.pl

Les autres réponses ne sont pas correctes - ou du moins, elles ne sont pas configurées correctement.

Effectuez le test suivant en utilisant leur code (par exemple celui de Tomasz ou de ssuukk):

1) Définissez 100 comme "volume maximum"/nombre d'étapes et soumettez le volume 50.

Il retourne: 0.150514997831991

2) Définissez 1000 comme "volume maximum"/nombre d'étapes et soumettez le volume 500.

Que retourne-t-il? La même valeur, 0.150514997831991, non?

Nan. Au lieu de cela, c'est: 0.100343331887994

En d’autres termes, les réponses existantes changent l’échelle du pourcentage de volume d’entrée (c’est-à-dire la courbe de transformation) en fonction du nombre d’étapes de volume que vous avez définies .

J'ai passé les dernières heures à examiner cette question; assez pour que je n'aie pas envie d'entrer dans trop de détails pour expliquer le problème. Au lieu de cela, je vais simplement poster le bloc de code/commentaires volumineux dans mon programme le concernant. (c'est en C #, pour Xamarin Android, mais les fonctionnalités devraient être les mêmes pour 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

La documentation est rare, je ne peux donc pas savoir avec certitude si j'ai le bon système/type d'unité que la méthode SetVolume attend.

En supposant qu'il attend une valeur d'amplitude, le code ci-dessus peut être le code de réglage du volume correct pour elle. (en prenant la Loudness souhaitée, linéaire, en tant qu'entrée et en émettant/réglant la valeur d'amplitude nécessaire pour la méthode SetVolume intégrée)

Cependant, je ne suis pas sûr que ce soit correct et je suis trop fatigué pour le confirmer. Si quelqu'un a d'autres idées, n'hésitez pas à les ajouter. (3 heures et plus suffisent pour passer à une question comme celle-ci, en une journée)

Modifier

Après avoir écouté attentivement et comparé l’effet loudness-fade en:

  1. Il suffit de soumettre le volume souhaité à la méthode SetVolume.
  2. Exponentier (fondamentalement) la sonie souhaitée avant de l'envoyer, pour en faire une valeur d'amplitude (ou similaire) que la méthode SetVolume dit qu'elle attend.

Je trouve que l'option 1 semble être plus proche d'un fondu enchaîné d'intensité sonore! En d'autres termes ... en écoutant et en comparant l'approche de base, avec les différentes approches de transformation présentées ici, il semble que la documentation soit erronée et que la méthode SetVolume n'attende en fait que la valeur de la sonie sur une échelle linéaire. (Peut-être l'ont-ils mis à jour pour fonctionner de manière plus intuitive dans l'une des versions récentes de l'API, mais n'ont pas mis à jour la documentation?)

Si c'est le cas, cela facilite les choses. C'est ce que je vais avec pour l'instant. (Bien que je garde l’approche de l’exponentiation/de la correction d’échelle comme paramètre de programme, je suppose, pour avoir un prétexte pour garder un résultat de tout ce temps investi!)

11
Venryx

La réponse recommandée est fausse, comme le dit Venryx. Log math ne fonctionne pas de cette façon (vous devez soustraire, pas diviser les journaux pour les faire fonctionner comme vous le souhaitez).

Quoiqu'il en soit, il semble qu'Android Volume soit désormais proportionnel à Loudness linéairement ... 0,5 est donc 50% aussi puissant que 1,0, et 0,1 égal à 10%, etc. Aucun besoin de Log Log compliqué pour convertir les décibels en volume. Il suffit de le définir de manière linéaire, comme cela est intuitif pour la plupart des gens.

6
najak

J'ai essayé Android MediaPlayer.setVolume, mais cette fonction est inutile.

Je pense que nous devrions utiliser la fonction ci-dessous

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

Ce code décompose le volume en 10 sections égales et augmente ou diminue le 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);
    }
});

Si vous voulez régler le volume sur aucun son, passez (0f, 0f)

Si vous souhaitez régler le volume sur son intégral, passez (1f, 1f)

0
rakesh kumar

Pourquoi le rendre si compliqué? J'utilise cette formule simple:

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

et en définissant cette valeur dans le lecteur multimédia, comme:

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

Tout ce que j'ai vu ici n'a pas répondu à mes attentes. Le problème principal que j’avais était que sur une échelle de 0 à 50, 25 n’était jamais au milieu mais plutôt beaucoup plus proche du son maximum. Les fonctions de journal proposées ici ne font presque aucune différence pour moi.

Pour en savoir plus sur le calcul, voir cette réponse .

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

Formule où le changement décélère à mesure que la valeur augmente (forme la plus simple)

Le problème avec cette approche est qu’il s’agit du contraire de ce que nous voulons avec Android, car il semble que cela se fasse déjà par défaut. C’est déjà trop rapide lorsque les valeurs sont encore basses lorsque vous passez des valeurs linéaires, ce qui accentue cette effet encore plus loin.

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

Résultats de cette fonction

Formule où le changement s'accélère à mesure que la valeur augmente

C’est l’approche qui marche pour moi; inverser l’entrée pour conserver le même taux de changement, mais en l’inverse. Avec cela, je parviens à obtenir un volume moyen parfait autour de 25 et une expérience auditive très fluide de 0 jusqu'à 50.

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

Résultats de cette fonction

0
Jon B

Eh bien, j'ai fait le code suivant et cela fonctionne légèrement:

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