MindMachine: track timeline model + parameter control helper

This commit is contained in:
Tretzi
2026-03-19 15:56:59 -05:00
parent a2669d6f59
commit aa0b51fbc4
2 changed files with 155 additions and 0 deletions

View File

@@ -0,0 +1,92 @@
package com.mindmachine.mvp.session
import com.mindmachine.mvp.domain.SessionConfig
import com.mindmachine.mvp.domain.SessionMode
import com.mindmachine.mvp.domain.SessionPreset
import kotlin.math.roundToInt
/**
* Lightweight model for the current (non-timeline) setup sliders.
*
* Note: Dana's spec introduces a full timeline editor; this model is just to keep
* the existing SetupScreen compiling while we wire the dedicated editor screen.
*/
data class TimelineModel(
val preset: SessionPreset,
val durationSeconds: Int,
val parameters: List<Parameter>
) {
data class Parameter(
val id: String,
val name: String,
val description: String,
val min: Float,
val max: Float,
val defaultValue: Float,
val value: Float,
val units: String = ""
)
companion object {
fun createForPreset(preset: SessionPreset, durationSeconds: Int): TimelineModel {
val flashSec = preset.flashIntervalMs.toFloat() / 1000f
val params = listOf(
Parameter(
id = "flash_interval",
name = "Flash Interval",
description = "Time between flashes in the visual pattern",
min = 0.05f,
max = 2.0f,
defaultValue = flashSec,
value = flashSec,
units = "s"
),
Parameter(
id = "carrier_frequency",
name = "Carrier Frequency",
description = "Base audio frequency for binaural beats",
min = 80f,
max = 400f,
defaultValue = preset.carrierFrequencyHz,
value = preset.carrierFrequencyHz,
units = "Hz"
),
Parameter(
id = "binaural_difference",
name = "Binaural Difference",
description = "Frequency difference between left/right audio channels",
min = 0.5f,
max = 20f,
defaultValue = preset.binauralDifferenceHz,
value = preset.binauralDifferenceHz,
units = "Hz"
)
)
return TimelineModel(preset = preset, durationSeconds = durationSeconds, parameters = params)
}
}
fun updateParameterValue(id: String, newValue: Float): TimelineModel {
return copy(parameters = parameters.map { if (it.id == id) it.copy(value = newValue) else it })
}
fun toSessionConfig(mode: SessionMode): SessionConfig {
val flashIntervalMs = ((parameters.firstOrNull { it.id == "flash_interval" }?.value
?: (preset.flashIntervalMs.toFloat() / 1000f)) * 1000f).roundToInt()
val carrier = parameters.firstOrNull { it.id == "carrier_frequency" }?.value ?: preset.carrierFrequencyHz
val diff = parameters.firstOrNull { it.id == "binaural_difference" }?.value ?: preset.binauralDifferenceHz
return SessionConfig(
presetId = preset.id,
durationSec = durationSeconds,
mode = mode,
visualPatternType = preset.visualPatternType,
flashIntervalMs = flashIntervalMs,
intensityPercent = preset.intensityPercent,
carrierFrequencyHz = carrier,
binauralDifferenceHz = diff
)
}
}

View File

@@ -0,0 +1,63 @@
package com.mindmachine.mvp.session
import androidx.compose.foundation.layout.*
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Slider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlin.math.roundToInt
/**
* Temporary parameter controls (sliders) to keep SetupScreen functional.
*
* The full timeline editor per spec is implemented separately in TimelineEditorScreen.
*/
@Composable
fun TimelineParameterControl(
model: TimelineModel,
onParameterChanged: (String, Float) -> Unit,
modifier: Modifier = Modifier,
showTimeline: Boolean = false,
onTimelineChanged: (Int) -> Unit = {}
) {
Column(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Text(
model.preset.name,
style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onBackground
)
model.parameters.forEach { p ->
Row(
Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Column(Modifier.weight(1f)) {
Text(p.name, color = MaterialTheme.colorScheme.onBackground)
Text(p.description, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onBackground)
}
Text(
when (p.units) {
"s" -> String.format("%.2f %s", p.value, p.units)
else -> "${p.value.roundToInt()} ${p.units}"
},
color = MaterialTheme.colorScheme.onBackground
)
}
Slider(
value = p.value,
onValueChange = { onParameterChanged(p.id, it) },
valueRange = p.min..p.max,
modifier = Modifier.fillMaxWidth()
)
}
}
}