diff --git a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/midi/Dynamic.kt b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/midi/Dynamic.kt index c2d6e04..5cbb74a 100644 --- a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/midi/Dynamic.kt +++ b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/midi/Dynamic.kt @@ -5,14 +5,15 @@ import mg.dot.feufaro.provideSettings import java.util.prefs.Preferences enum class Dynamic(val velocity: Int, val label: String, val defaultFactor: Float) { - PPP(16, "ppp", 0.80f), - PP (32, "pp", 0.85f), - P (48, "p", 0.90f), - MP (64, "mp", 0.95f), - MF (80, "mf", 1.00f), - F (96, "f", 1.05f), - FF (112, "ff", 1.10f), - FFF(127, "fff", 1.15f); + PPP(16, "ppp", 0.60f), + PP (32, "pp", 0.70f), + P (48, "p", 0.80f), + MP (64, "mp", 0.90f), + ZERO(72, "z", 1.00f), + MF (80, "mf", 1.10f), + F (96, "f", 1.20f), + FF (112, "ff", 1.30f), + FFF(127, "fff", 1.40f); private val prefs: Settings = provideSettings() var savedFactor: Float = prefs.getFloat("dynamic_${name.lowercase()}", defaultFactor) set(value) { diff --git a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/ui/Settings.kt b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/ui/Settings.kt index d5ac74f..3bc2508 100644 --- a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/ui/Settings.kt +++ b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/ui/Settings.kt @@ -467,10 +467,10 @@ fun Settings( key(refreshTrigger) { val dynamicEntries = Dynamic.entries - val minF = 0.20f - val maxF = 1.59f + val minF = 0.10f + val maxF = 2.50f 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( modifier = Modifier @@ -497,7 +497,7 @@ fun Settings( if (isDynamicEnabled) { val deltaGap = gapStep 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 maintainsOrder = projected.zipWithNext().all { (a, b) -> a < b } @@ -537,14 +537,14 @@ fun Settings( Slider( value = dynamicItem.savedFactor, onValueChange = { newValue -> - if (isDynamicEnabled) { + if (isDynamicEnabled && dynamicItem != Dynamic.ZERO) { val oldValue = dynamicItem.savedFactor val delta = newValue - oldValue if (delta != 0f) { val deltaGap = delta 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 maintainsOrder = projected.zipWithNext().all { (a, b) -> a < b } @@ -559,13 +559,13 @@ fun Settings( } }, valueRange = minF..maxF, - enabled = isDynamicEnabled, + enabled = isDynamicEnabled && dynamicItem != Dynamic.ZERO, track = { sliderState -> SliderDefaults.Track( sliderState = sliderState, - enabled = isDynamicEnabled, + enabled = isDynamicEnabled && dynamicItem != Dynamic.ZERO, 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 ), modifier = Modifier.height(6.dp) @@ -575,7 +575,7 @@ fun Settings( SliderDefaults.Thumb( interactionSource = remember { MutableInteractionSource() }, 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), ) @@ -609,7 +609,7 @@ fun Settings( if (isDynamicEnabled) { val deltaGap = -gapStep 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 maintainsOrder = projected.zipWithNext().all { (a, b) -> a < b } diff --git a/composeApp/src/desktopMain/kotlin/mg/dot/feufaro/midi/MidiPlayer.kt b/composeApp/src/desktopMain/kotlin/mg/dot/feufaro/midi/MidiPlayer.kt index 5afbc06..8b7f301 100644 --- a/composeApp/src/desktopMain/kotlin/mg/dot/feufaro/midi/MidiPlayer.kt +++ b/composeApp/src/desktopMain/kotlin/mg/dot/feufaro/midi/MidiPlayer.kt @@ -32,8 +32,8 @@ actual class FMediaPlayer actual constructor( private val voiceVolumes = FloatArray(4) { 127f } private var currentGlobalVolume: Float = 0.8f - private var currentDynamicVelocity: Int = Dynamic.MF.velocity - private var currentDynamicFactor: Float = Dynamic.MF.factor + private var currentDynamicVelocity: Int = Dynamic.ZERO.velocity + private var currentDynamicFactor: Float = Dynamic.ZERO.factor private var targetBpm: 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) { - val targetFactor = when (dynamic) { - Dynamic.MF -> 1.0f - else -> dynamic.factor - } + val targetFactor = dynamic.factor println("applyDynamic → ${dynamic.label} | ${currentDynamicFactor} → $targetFactor") applyDynamicSmooth(targetFactor, durationMs = 300L) } @@ -170,7 +167,7 @@ actual class FMediaPlayer actual constructor( val clean = marker.trim().removeSuffix("=").trim() 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 { val current = factorToDynamic(currentFactor) val index = Dynamic.entries.indexOf(current) @@ -243,7 +240,7 @@ actual class FMediaPlayer actual constructor( val metadataList = sharedScreenModel.getFullMarkers() navigationSteps.clear() var lastSegno = 0 - var lastFactor = Dynamic.MF.factor + var lastFactor = Dynamic.ZERO.factor val ritRegex = Regex("""rit\.?|ritard\.?|ritenuto\.?|ritardando""", 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) @@ -446,7 +443,7 @@ actual class FMediaPlayer actual constructor( extractDynamic(marker) != null && mTrim != "=" -> { val dyn = extractDynamic(marker) ?: return@forEach lastFactor = when (dyn) { - Dynamic.MF -> 1.0f + Dynamic.ZERO -> 1.0f else -> dyn.factor } navigationSteps.add( @@ -473,7 +470,7 @@ actual class FMediaPlayer actual constructor( val dynBefore = navigationSteps .filter { it.dynamic != null && it.gridIndex <= currentIndex } - .maxByOrNull { it.gridIndex }?.dynamic ?: Dynamic.MF + .maxByOrNull { it.gridIndex }?.dynamic ?: Dynamic.ZERO val dynAfter = metadataList .filter { m -> (m.gridIndex ?: 0) >= pair.endGrid } @@ -720,7 +717,7 @@ actual class FMediaPlayer actual constructor( val lastDynamic = navigationSteps .filter { it.dynamic != null && it.gridIndex <= gridIndex } .maxByOrNull { it.gridIndex } - ?.dynamic ?: Dynamic.MF + ?.dynamic ?: Dynamic.ZERO currentDynamicFactor = lastDynamic.factor applyVoiceStates() sharedScreenModel.updateActiveIndexByIndex(-1) @@ -891,7 +888,7 @@ actual class FMediaPlayer actual constructor( sequencer?.tempoInBPM = initialBpm boundModel?.setBpmFlow(initialBpm) clearLoop() - currentDynamicFactor = Dynamic.MF.factor + currentDynamicFactor = Dynamic.ZERO.factor resetTempoToNormal() // release() }