Sync grid on tick position sequence & implement "$ DS" & resync when setting tempo

This commit is contained in:
hasinarak3@gmail.com 2026-03-10 16:09:54 +03:00
parent 1a928ab4b0
commit cfa381d3c0
4 changed files with 32 additions and 34 deletions

View file

@ -15,6 +15,7 @@ expect class FMediaPlayer(filename: String, onFinished: () -> Unit) {
fun changeInstru(noInstru: Int) fun changeInstru(noInstru: Int)
fun getCurrentPosition(): Long fun getCurrentPosition(): Long
fun seekTo(position: Long) fun seekTo(position: Long)
fun seekToGrid(gridIndex: Int)
fun setVolume(level: Float) fun setVolume(level: Float)
fun setPointA() fun setPointA()
fun setPointB() fun setPointB()

View file

@ -576,22 +576,9 @@ fun LazyVerticalGridTUO(
val currentStanza = viewModel.stanza val currentStanza = viewModel.stanza
val currentPos by sharedScreenModel.currentPos.collectAsState()
val duration by sharedScreenModel.duration.collectAsState()
val isPlay by sharedScreenModel.isPlay.collectAsState()
val tuoTimestamps by sharedScreenModel.tuoTimestamps.collectAsState() val tuoTimestamps by sharedScreenModel.tuoTimestamps.collectAsState()
val displayedList = tuoList.drop(1) val activeRowIndex by sharedScreenModel.activeIndex.collectAsState()
val nbTotalDesRow = (displayedList.size-1)
val activeRowIndex = remember(currentPos, tuoTimestamps) {
val currentPosMicros = (currentPos * 1000).toLong()
val index = tuoTimestamps.indexOfLast { it <= currentPosMicros }
index.coerceIn(-1, nbTotalDesRow)
}
/*val activeRowIndex = if (duration > 0f) {
((currentPos / duration) * nbTotalDesRow).toInt().coerceIn(0, nbTotalDesRow - 1)
} else {
-1
}*/
val measures = tuoList.drop(1).chunked(gridColumnCount) val measures = tuoList.drop(1).chunked(gridColumnCount)
// Avant column affichage: // Avant column affichage:
val metadataList = remember(tuoList) { val metadataList = remember(tuoList) {
@ -729,10 +716,8 @@ fun LazyVerticalGridTUO(
Box(modifier = Modifier.weight(1f) Box(modifier = Modifier.weight(1f)
.combinedClickable( .combinedClickable(
onClick = { onClick = {
val targetMicros = tuoTimestamps.getOrNull(globalIndex) ?: 0L // println("je suis sur grille no: $globalIndex")
sharedScreenModel.seekToTimestamp(targetMicros) sharedScreenModel.seekToGrid(globalIndex)
// sharedScreenModel.updatePositionFromPartition(globalIndex, nbTotalDesRow)
// println("tempNum ${oneTUO.numBlock} mesasindex ${measureIndex} & indexinM $indexInMeasure gridCount $gridColumnCount")
} , } ,
onDoubleClick = { onDoubleClick = {
val m = sharedScreenModel.getFullMarkers() val m = sharedScreenModel.getFullMarkers()

View file

@ -152,6 +152,15 @@ class SharedScreenModel(private val fileRepository: FileRepository) : ScreenMode
_activeIndex.value = index.coerceAtLeast(0) _activeIndex.value = index.coerceAtLeast(0)
} }
} }
fun updateActiveIndexByIndex(index: Int) {
val clamped = index.coerceAtLeast(0)
if (_activeIndex.value != clamped) {
_activeIndex.value = clamped
}
}
fun seekToGrid(gridIndex: Int) {
_mediaPlayer?.seekToGrid(gridIndex)
}
fun getFullMarkers(): List<MidiMarkers> { fun getFullMarkers(): List<MidiMarkers> {
return _midiMarkersList.value return _midiMarkersList.value

View file

@ -150,7 +150,7 @@ actual class FMediaPlayer actual constructor(
) )
println("Point d'orgue (\uD834\uDD10) mémorisée au grille n° $gridIndex") println("Point d'orgue (\uD834\uDD10) mémorisée au grille n° $gridIndex")
} }
/*// DS // DS
dsGPattern.matches(marker.trim())-> { dsGPattern.matches(marker.trim())-> {
val target = if (lastSegno > 0) lastSegno else 0 val target = if (lastSegno > 0) lastSegno else 0
var indx = if((last_grid - currentIndex) <= 0) { var indx = if((last_grid - currentIndex) <= 0) {
@ -175,7 +175,7 @@ actual class FMediaPlayer actual constructor(
targetGrid = target targetGrid = target
)) ))
println("Lien DS créé : Saut immédiat à $gridIndex vers Segno $target") println("Lien DS créé : Saut immédiat à $gridIndex vers Segno $target")
}*/ }
// DC // DC
dcGPattern.matches(marker.trim()) -> { dcGPattern.matches(marker.trim()) -> {
@ -217,8 +217,8 @@ actual class FMediaPlayer actual constructor(
sharedScreenModel.activeIndex.collect { currentIndex -> sharedScreenModel.activeIndex.collect { currentIndex ->
val availableIndices = navigationSteps.map { it.gridIndex } val availableIndices = navigationSteps.map { it.gridIndex }
println("bpm:$targetBpm _ ${sequencer?.tempoInBPM}") // println("bpm:$targetBpm _ ${sequencer?.tempoInBPM}")
println("MONITOR : Reçu Index $currentIndex | Index en mémoire : $availableIndices ") // println("MONITOR : Reçu Index $currentIndex | Index en mémoire : $availableIndices ")
if (sequencer?.isRunning == true) { if (sequencer?.isRunning == true) {
if (Math.abs(sequencer!!.tempoInBPM - targetBpm) > 0.1) { if (Math.abs(sequencer!!.tempoInBPM - targetBpm) > 0.1) {
@ -282,22 +282,20 @@ actual class FMediaPlayer actual constructor(
syncJob = playerScope.launch(Dispatchers.Default) { syncJob = playerScope.launch(Dispatchers.Default) {
while (isActive) { while (isActive) {
if (sequencer?.isRunning == true) { if (sequencer?.isRunning == true) {
val posMs = (sequencer?.microsecondPosition ?: 0L) / 1000 val resolution = sequencer?.sequence?.resolution?.toLong() ?: 480L
sharedScreenModel.updateActiveIndex(posMs) val gridIndex = (sequencer!!.tickPosition / resolution).toInt()
sharedScreenModel.updateActiveIndexByIndex(gridIndex)
} }
delay(20) delay(20)
} }
} }
} }
private fun seekToGrid(gridIndex: Int) { actual fun seekToGrid(gridIndex: Int) {
val resolution = sequencer?.sequence?.resolution?.toDouble() ?: 480.0 val resolution = sequencer?.sequence?.resolution?.toDouble() ?: 480.0
val tick = gridIndex.toDouble() * resolution val tick = (gridIndex.toDouble() * resolution).toLong()
sequencer?.tickPosition = tick
val bpm = sequencer?.tempoInBPM ?: targetBpm applyBpm()
val usPerTick = (60_000_000.0 / bpm) / resolution
val targetMicros = (tick * usPerTick).toLong()
sequencer?.microsecondPosition = targetMicros
} }
actual fun play(){ actual fun play(){
@ -337,7 +335,7 @@ actual class FMediaPlayer actual constructor(
for (tick in 0..totalTicks step step) { for (tick in 0..totalTicks step step) {
val microsecond = (tick * usPerTick).toLong() val microsecond = (tick * usPerTick).toLong()
timestamps.add(microsecond) timestamps.add(microsecond)
// println("Note detectée au Tick: ${tick} -> Temps: ${microsecond / 1000} ms") // println("Note detectée au grille: ${tick/60} -> Temps: ${microsecond / 1000} ms")
} }
// Détection de tous les note y compris les /2 /4 temps // Détection de tous les note y compris les /2 /4 temps
@ -359,6 +357,7 @@ actual class FMediaPlayer actual constructor(
}*/ }*/
val sortedList = timestamps.sorted() val sortedList = timestamps.sorted()
sharedScreenModel.updateTimestamps(sortedList) sharedScreenModel.updateTimestamps(sortedList)
// println("SUR tempo $targetBpm Synchronization terminer et mis à jour")
} }
actual fun stop(){ actual fun stop(){
@ -497,6 +496,10 @@ actual class FMediaPlayer actual constructor(
this.targetBpm = bpm this.targetBpm = bpm
sequencer?.tempoInBPM = bpm sequencer?.tempoInBPM = bpm
boundModel?.let { modele -> boundModel?.let { modele ->
val seq = sequencer?.sequence
if (seq != null) {
syncTuoWithMidi(seq, modele)
}
prepareNavigation(modele) prepareNavigation(modele)
} }
println("Tempo réglé à : $bpm BPM") println("Tempo réglé à : $bpm BPM")