The MASTER_GAIN FloatControl
value is in decibels, meaning it's a logarithmic scale, not a linear one.
While decibels is great for audio professionals, us programmers usually want a nice linear scale where 0.0
is silent, 0.5
is half volume, and 1.0
is full volume; by which I mean normal volume for the sound sample. When playing sound effects, we don't usually amplify sound clips, just attenuate them.
Decibel (dB) to Float Value Calculator explains the maths behind converting decibels to a linear scale, but here is the code:
In 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)
}
}
And converted to 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));
}
Note there is no need to involve clip.getMaxVolume()
or clip.getMinVolume()
because using the code above, a volume of 1.0
corresponds to 0 Db
(no change) and a volume of 0.1
corresponds to -20 Db
(very, very quiet).
If you did want to amplify the sound clip, then there's nothing stopping you from passing in 2.0
to double the normal volume, a-la VLC.
And as a shameless plug, to see what I've used this knowledge for - see Escape the Mainframe - a mini jump game that runs in the Browser and as a desktop Java application. Written in Fantom - have fun!
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…