audio: Use logarithmic dB curve for volume slider

A square curve still compresses too much at the top half of the range.
Map the slider linearly to -40 dB … 0 dB, then convert to amplitude
with 10^(dB/20). This makes each equal step of the slider produce an
equal perceived loudness change, so the full 0–100% range feels usable.
This commit is contained in:
Jeena 2026-03-10 02:24:50 +00:00
parent da3b760f43
commit 468657c374

View file

@ -1,6 +1,7 @@
package net.jeena.pacer package net.jeena.pacer
import android.media.AudioAttributes import android.media.AudioAttributes
import kotlin.math.pow
import android.media.AudioFormat import android.media.AudioFormat
import android.media.AudioTrack import android.media.AudioTrack
import android.os.Handler import android.os.Handler
@ -23,10 +24,16 @@ class AudioEngine {
private const val BEEP_DURATION_MS = 40 private const val BEEP_DURATION_MS = 40
private const val SILENCE_CHUNK_MS = 10 private const val SILENCE_CHUNK_MS = 10
// Apply a square curve so the slider feels linear to human hearing. // Map the linear 0-1 slider to a perceptually even loudness curve.
// AudioTrack.setVolume() takes a linear amplitude; our 0-1 slider // AudioTrack.setVolume() takes a linear amplitude, but human hearing
// value is perceived as "all the volume at the bottom" without this. // is logarithmic: equal dB steps sound like equal volume steps.
private fun toAmplitude(linear: Float): Float = linear * linear // We map the slider to a -40 dB … 0 dB range, so each 25% of travel
// changes perceived loudness by the same amount.
private fun toAmplitude(linear: Float): Float {
if (linear <= 0f) return 0f
val db = -40f * (1f - linear) // 0.0 → -40 dB, 1.0 → 0 dB
return 10f.pow(db / 20f)
}
} }
private val mainHandler = Handler(Looper.getMainLooper()) private val mainHandler = Handler(Looper.getMainLooper())