Définir le volume du clip Java
Existe-t-il un moyen de définir le volume respectif d'un Clip
dans Java
?
, j'ai cette méthode:
public static void play(Clip clip) {
if (Settings.getSettings().isVolumeOn()) {
FloatControl volume = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
volume.setValue(-1 * Settings.getSettings().getVolume());
clip.start();
}
}
Le Settings.getSettings().getVolume()
renvoie un Integer
dans la gamme de 0 - 100
Volumes:
- 0: Pas de son
- 40: Son optimal avec un casque
- 60: Son optimal
- 100: Son complet
Donc essentiellement cela devrait être comme l'échelle de VLC
(mais la moitié puisque VLC est de 0 to 200
).
J'ai trouvé que je peux réduire le décibel du clip en utilisant volume.setValue(-10f);
Mais je préférerais quelque chose du type volume.setValue(clip.getMaxVolume() * Settings.getSettings().getVolume()/100)
.
Où clip.getMaxVolume()
renverrait le volume maximum du clip.
4 answers
Selon Killer Game Programming par Andrew Davison, vous pouvez régler le volume aussi simple:
float range = gainControl.getMaximum() - gainControl.getMinimum();
float gain = (range * volume) + gainControl.getMinimum();
gainControl.setValue(gain);
volume
étant le volume souhaité en float (0.0 f signifie pas de son, 1.0 f signifie audio complet)
gainControl
est le FloatControl
J'espère que vous pouvez le faire fonctionner!
Le MASTER_GAIN FloatControl
la valeur est en décibels, ce qui signifie que c'est une échelle logarithmique, pas linéaire.
Alors que décibels est idéal pour les professionnels de l'audio, les programmeurs américains veulent généralement une belle échelle linéaire où 0.0
est silencieux, 0.5
est demi-volume, et 1.0
est plein volume; par ce que je veux dire le volume normal pour l'échantillon sonore. Lors de la lecture d'effets sonores, nous n'amplifions généralement pas les clips sonores, nous les atténuons simplement.
Décibel (dB) à Valeur Flottante Calculator explique les mathématiques derrière la conversion des décibels à une échelle linéaire, mais voici le code:
Dans Fantom:
using [java] javax.sound.sampled::Clip
using [java] javax.sound.sampled::FloatControl
using [java] javax.sound.sampled::FloatControl$Type as FType
...
private Clip clip
Float volume {
get {
gainControl := (FloatControl) clip.getControl(FType.MASTER_GAIN)
return 10f.pow(gainControl.getValue / 20f)
}
set {
if (it < 0f || it > 1f) throw ArgErr("Invalid volume: $it")
gainControl := (FloatControl) clip.getControl(FType.MASTER_GAIN)
gainControl.setValue(20f * it.log10)
}
}
Et converti en Java:
import javax.sound.sampled.Clip;
import javax.sound.sampled.FloatControl;
...
private Clip clip
public float getVolume() {
FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
return (float) Math.pow(10f, gainControl.getValue() / 20f);
}
public void setVolume(float volume) {
if (volume < 0f || volume > 1f)
throw new IllegalArgumentException("Volume not valid: " + volume);
FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
gainControl.setValue(20f * (float) Math.log10(volume));
}
Remarque il n'est pas nécessaire d'impliquer clip.getMaxVolume()
ou clip.getMinVolume()
, car un volume de 1.0
correspond 0 Db
(pas de changement) et un volume de 0.1
correspond -20 Db
(très, très calme).
Si vous vouliez amplifier le clip sonore, rien ne vous empêche de passer 2.0
à double le volume normal, a-la VLC.
Donc, après un peu d'essais et d'erreurs, j'ai trouvé ceci:
public static void play(Clip clip) {
if (Settings.getSettings().isVolumeOn()) {
FloatControl control = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
int volume = Settings.getSettings().getVolume();
float range = control.getMinimum();
float result = range * (1 - volume / 100.0f);
control.setValue(result);
clip.start();
}
}
Je crois que vous cherchez réellement le FloatControl.Type.Contrôle du VOLUME, plutôt que MASTER_GAIN. Essayez ceci:
public static void setVolume(Clip clip, int level) {
Objects.requireNonNull(clip);
FloatControl volume = (FloatControl) clip.getControl(FloatControl.Type.VOLUME);
if (volume != null) {
volume.setValue(level / 100.0);
}
}