Update ui & Dynamic factor slider - Settings

This commit is contained in:
Hasinjato 2026-10-07 15:59:13 +03:00
parent 83a26110e6
commit 38edfe4834
3 changed files with 29 additions and 31 deletions

View file

@ -5,14 +5,15 @@ import mg.dot.feufaro.provideSettings
import java.util.prefs.Preferences import java.util.prefs.Preferences
enum class Dynamic(val velocity: Int, val label: String, val defaultFactor: Float) { enum class Dynamic(val velocity: Int, val label: String, val defaultFactor: Float) {
PPP(16, "ppp", 0.80f), PPP(16, "ppp", 0.60f),
PP (32, "pp", 0.85f), PP (32, "pp", 0.70f),
P (48, "p", 0.90f), P (48, "p", 0.80f),
MP (64, "mp", 0.95f), MP (64, "mp", 0.90f),
MF (80, "mf", 1.00f), ZERO(72, "z", 1.00f),
F (96, "f", 1.05f), MF (80, "mf", 1.10f),
FF (112, "ff", 1.10f), F (96, "f", 1.20f),
FFF(127, "fff", 1.15f); FF (112, "ff", 1.30f),
FFF(127, "fff", 1.40f);
private val prefs: Settings = provideSettings() private val prefs: Settings = provideSettings()
var savedFactor: Float = prefs.getFloat("dynamic_${name.lowercase()}", defaultFactor) var savedFactor: Float = prefs.getFloat("dynamic_${name.lowercase()}", defaultFactor)
set(value) { set(value) {

View file

@ -467,10 +467,10 @@ fun Settings(
key(refreshTrigger) { key(refreshTrigger) {
val dynamicEntries = Dynamic.entries val dynamicEntries = Dynamic.entries
val minF = 0.20f val minF = 0.10f
val maxF = 1.59f val maxF = 2.50f
val gapStep = 0.01f val gapStep = 0.01f
val mfIndex = dynamicEntries.indexOfFirst { it == Dynamic.MF }.let { if (it == -1) 4 else it } val zeroIndex = dynamicEntries.indexOfFirst { it == Dynamic.ZERO }.let { if (it == -1) 4 else it }
Box( Box(
modifier = Modifier modifier = Modifier
@ -497,7 +497,7 @@ fun Settings(
if (isDynamicEnabled) { if (isDynamicEnabled) {
val deltaGap = gapStep val deltaGap = gapStep
val projected = dynamicEntries.mapIndexed { i, item -> val projected = dynamicEntries.mapIndexed { i, item ->
item.savedFactor + ((i - mfIndex) * deltaGap) item.savedFactor + ((i - zeroIndex) * deltaGap)
} }
val insideBounds = projected.all { it in minF..maxF } val insideBounds = projected.all { it in minF..maxF }
val maintainsOrder = projected.zipWithNext().all { (a, b) -> a < b } val maintainsOrder = projected.zipWithNext().all { (a, b) -> a < b }
@ -537,14 +537,14 @@ fun Settings(
Slider( Slider(
value = dynamicItem.savedFactor, value = dynamicItem.savedFactor,
onValueChange = { newValue -> onValueChange = { newValue ->
if (isDynamicEnabled) { if (isDynamicEnabled && dynamicItem != Dynamic.ZERO) {
val oldValue = dynamicItem.savedFactor val oldValue = dynamicItem.savedFactor
val delta = newValue - oldValue val delta = newValue - oldValue
if (delta != 0f) { if (delta != 0f) {
val deltaGap = delta val deltaGap = delta
val projected = dynamicEntries.mapIndexed { i, item -> val projected = dynamicEntries.mapIndexed { i, item ->
item.savedFactor + ((i - mfIndex) * deltaGap) item.savedFactor + ((i - zeroIndex) * deltaGap)
} }
val insideBounds = projected.all { it in minF..maxF } val insideBounds = projected.all { it in minF..maxF }
val maintainsOrder = projected.zipWithNext().all { (a, b) -> a < b } val maintainsOrder = projected.zipWithNext().all { (a, b) -> a < b }
@ -559,13 +559,13 @@ fun Settings(
} }
}, },
valueRange = minF..maxF, valueRange = minF..maxF,
enabled = isDynamicEnabled, enabled = isDynamicEnabled && dynamicItem != Dynamic.ZERO,
track = { sliderState -> track = { sliderState ->
SliderDefaults.Track( SliderDefaults.Track(
sliderState = sliderState, sliderState = sliderState,
enabled = isDynamicEnabled, enabled = isDynamicEnabled && dynamicItem != Dynamic.ZERO,
colors = SliderDefaults.colors( colors = SliderDefaults.colors(
activeTrackColor = if (isDynamicEnabled) Color.Blue else Color.Gray, activeTrackColor = if (isDynamicEnabled && dynamicItem != Dynamic.ZERO) Color.Blue else Color.Gray,
inactiveTrackColor = Color.LightGray inactiveTrackColor = Color.LightGray
), ),
modifier = Modifier.height(6.dp) modifier = Modifier.height(6.dp)
@ -575,7 +575,7 @@ fun Settings(
SliderDefaults.Thumb( SliderDefaults.Thumb(
interactionSource = remember { MutableInteractionSource() }, interactionSource = remember { MutableInteractionSource() },
colors = SliderDefaults.colors( colors = SliderDefaults.colors(
thumbColor = if (isDynamicEnabled) Color(0xFFFF4081) else Color.LightGray thumbColor = if (isDynamicEnabled && dynamicItem != Dynamic.ZERO) Color(0xFFFF4081) else Color.LightGray
), ),
modifier = Modifier.size(12.dp), modifier = Modifier.size(12.dp),
) )
@ -609,7 +609,7 @@ fun Settings(
if (isDynamicEnabled) { if (isDynamicEnabled) {
val deltaGap = -gapStep val deltaGap = -gapStep
val projected = dynamicEntries.mapIndexed { i, item -> val projected = dynamicEntries.mapIndexed { i, item ->
item.savedFactor + ((i - mfIndex) * deltaGap) item.savedFactor + ((i - zeroIndex) * deltaGap)
} }
val insideBounds = projected.all { it in minF..maxF } val insideBounds = projected.all { it in minF..maxF }
val maintainsOrder = projected.zipWithNext().all { (a, b) -> a < b } val maintainsOrder = projected.zipWithNext().all { (a, b) -> a < b }

View file

@ -32,8 +32,8 @@ actual class FMediaPlayer actual constructor(
private val voiceVolumes = FloatArray(4) { 127f } private val voiceVolumes = FloatArray(4) { 127f }
private var currentGlobalVolume: Float = 0.8f private var currentGlobalVolume: Float = 0.8f
private var currentDynamicVelocity: Int = Dynamic.MF.velocity private var currentDynamicVelocity: Int = Dynamic.ZERO.velocity
private var currentDynamicFactor: Float = Dynamic.MF.factor private var currentDynamicFactor: Float = Dynamic.ZERO.factor
private var targetBpm: Float = sharedScreenModel.currentBpmFlow.value private var targetBpm: Float = sharedScreenModel.currentBpmFlow.value
private var initialBpm: Float = sharedScreenModel.currentBpmFlow.value private var initialBpm: Float = sharedScreenModel.currentBpmFlow.value
@ -159,10 +159,7 @@ actual class FMediaPlayer actual constructor(
} }
} }
private fun applyDynamic(dynamic: Dynamic) { private fun applyDynamic(dynamic: Dynamic) {
val targetFactor = when (dynamic) { val targetFactor = dynamic.factor
Dynamic.MF -> 1.0f
else -> dynamic.factor
}
println("applyDynamic → ${dynamic.label} | ${currentDynamicFactor} → $targetFactor") println("applyDynamic → ${dynamic.label} | ${currentDynamicFactor} → $targetFactor")
applyDynamicSmooth(targetFactor, durationMs = 300L) applyDynamicSmooth(targetFactor, durationMs = 300L)
} }
@ -170,7 +167,7 @@ actual class FMediaPlayer actual constructor(
val clean = marker.trim().removeSuffix("=").trim() val clean = marker.trim().removeSuffix("=").trim()
return Dynamic.entries.firstOrNull { it.label == clean } return Dynamic.entries.firstOrNull { it.label == clean }
} }
fun factorToDynamic(factor: Float): Dynamic = Dynamic.entries.minByOrNull { kotlin.math.abs(it.factor - factor) } ?: Dynamic.MF fun factorToDynamic(factor: Float): Dynamic = Dynamic.entries.minByOrNull { kotlin.math.abs(it.factor - factor) } ?: Dynamic.ZERO
fun nextDynamic(currentFactor: Float, symbol: Char): Float { fun nextDynamic(currentFactor: Float, symbol: Char): Float {
val current = factorToDynamic(currentFactor) val current = factorToDynamic(currentFactor)
val index = Dynamic.entries.indexOf(current) val index = Dynamic.entries.indexOf(current)
@ -243,7 +240,7 @@ actual class FMediaPlayer actual constructor(
val metadataList = sharedScreenModel.getFullMarkers() val metadataList = sharedScreenModel.getFullMarkers()
navigationSteps.clear() navigationSteps.clear()
var lastSegno = 0 var lastSegno = 0
var lastFactor = Dynamic.MF.factor var lastFactor = Dynamic.ZERO.factor
val ritRegex = Regex("""rit\.?|ritard\.?|ritenuto\.?|ritardando""", RegexOption.IGNORE_CASE) val ritRegex = Regex("""rit\.?|ritard\.?|ritenuto\.?|ritardando""", RegexOption.IGNORE_CASE)
val rallRegex = Regex("""rall\.?|rallent\.?|rallentando""", RegexOption.IGNORE_CASE) val rallRegex = Regex("""rall\.?|rallent\.?|rallentando""", RegexOption.IGNORE_CASE)
val modulaRegex = Regex("""D(ô|o)?\s*dia\s*(C|Db|D|Eb|E|F|Gb|G|Ab|A|Bb|B)""", RegexOption.IGNORE_CASE) val modulaRegex = Regex("""D(ô|o)?\s*dia\s*(C|Db|D|Eb|E|F|Gb|G|Ab|A|Bb|B)""", RegexOption.IGNORE_CASE)
@ -446,7 +443,7 @@ actual class FMediaPlayer actual constructor(
extractDynamic(marker) != null && mTrim != "=" -> { extractDynamic(marker) != null && mTrim != "=" -> {
val dyn = extractDynamic(marker) ?: return@forEach val dyn = extractDynamic(marker) ?: return@forEach
lastFactor = when (dyn) { lastFactor = when (dyn) {
Dynamic.MF -> 1.0f Dynamic.ZERO -> 1.0f
else -> dyn.factor else -> dyn.factor
} }
navigationSteps.add( navigationSteps.add(
@ -473,7 +470,7 @@ actual class FMediaPlayer actual constructor(
val dynBefore = navigationSteps val dynBefore = navigationSteps
.filter { it.dynamic != null && it.gridIndex <= currentIndex } .filter { it.dynamic != null && it.gridIndex <= currentIndex }
.maxByOrNull { it.gridIndex }?.dynamic ?: Dynamic.MF .maxByOrNull { it.gridIndex }?.dynamic ?: Dynamic.ZERO
val dynAfter = metadataList val dynAfter = metadataList
.filter { m -> (m.gridIndex ?: 0) >= pair.endGrid } .filter { m -> (m.gridIndex ?: 0) >= pair.endGrid }
@ -720,7 +717,7 @@ actual class FMediaPlayer actual constructor(
val lastDynamic = navigationSteps val lastDynamic = navigationSteps
.filter { it.dynamic != null && it.gridIndex <= gridIndex } .filter { it.dynamic != null && it.gridIndex <= gridIndex }
.maxByOrNull { it.gridIndex } .maxByOrNull { it.gridIndex }
?.dynamic ?: Dynamic.MF ?.dynamic ?: Dynamic.ZERO
currentDynamicFactor = lastDynamic.factor currentDynamicFactor = lastDynamic.factor
applyVoiceStates() applyVoiceStates()
sharedScreenModel.updateActiveIndexByIndex(-1) sharedScreenModel.updateActiveIndexByIndex(-1)
@ -891,7 +888,7 @@ actual class FMediaPlayer actual constructor(
sequencer?.tempoInBPM = initialBpm sequencer?.tempoInBPM = initialBpm
boundModel?.setBpmFlow(initialBpm) boundModel?.setBpmFlow(initialBpm)
clearLoop() clearLoop()
currentDynamicFactor = Dynamic.MF.factor currentDynamicFactor = Dynamic.ZERO.factor
resetTempoToNormal() resetTempoToNormal()
// release() // release()
} }