Compare commits

...

3 commits

Author SHA1 Message Date
d4174635c4 Fix: DC Farany DC 2026-03-17 10:12:16 +03:00
15d5674dfa Merge remote-tracking branch 'origin/master'
# Conflicts:
#	composeApp/src/desktopMain/kotlin/mg/dot/feufaro/midi/MidiPlayer.kt
2026-03-17 10:10:59 +03:00
df5e8567cd Fix: DC Farany DC 2026-03-17 10:01:33 +03:00

View file

@ -59,6 +59,8 @@ actual class FMediaPlayer actual constructor(
val hairPinEndGrid: Int = -1,
val hairPinFromFactor: Float = 1.0f,
val hairPinToFactor: Float = 1.0f,
val isFin: Boolean = false, // Farany D.C.
var finActive: Boolean =false,
)
private val navigationSteps = mutableListOf<NavigationStep>()
@ -84,9 +86,13 @@ actual class FMediaPlayer actual constructor(
applyVoiceStates()
sequencer?.addMetaEventListener { meta ->
if(meta.type == 47){
val totalGrids = (sequencer!!.sequence.tickLength / sequencer!!.sequence.resolution).toInt()
val currentGrid = (sequencer!!.tickPosition / sequencer!!.sequence.resolution).toInt()
val pendingDc = getPendingDcStep()
if (pendingDc != null) {
val isDcNearEnd = pendingDc != null && (totalGrids - pendingDc.gridIndex) <= 2
if (isDcNearEnd && pendingDc != null) {
println("onFinished : DC pending → saut direct vers ${pendingDc.targetGrid}")
pendingDc.alreadyDone = true
seekToGrid(pendingDc.targetGrid)
@ -244,10 +250,10 @@ actual class FMediaPlayer actual constructor(
navigationSteps.add(
NavigationStep(
marker,
currentIndex,
targetGrid = target
))
marker,
currentIndex,
targetGrid = target
))
println("Lien DS créé : Saut immédiat à $gridIndex vers Segno $target")
}
@ -281,6 +287,26 @@ actual class FMediaPlayer actual constructor(
println("Lien DC créé : $marker à $indx vers le début")
}
// Farany
marker.trim().equals("Farany_GROUP_PART", ignoreCase = true) -> {
val hasDcAfter = metadataList.any { (_, gi, _, _, mk, _, _, _) ->
(gi ?: 0) > currentIndex &&
(dcGPattern.matches(mk.trim()) ||
dcRegex.matches(mk.trim()))
}
if (hasDcAfter) {
navigationSteps.add(
NavigationStep(
marker = marker,
gridIndex = currentIndex,
targetGrid = last_grid,
isFin = true,
finActive = false
)
)
println("Farany mémorisé à la grille $currentIndex")
}
}
// velocité
extractDynamic(marker) != null && marker.trim() != "=" -> {
val dyn = extractDynamic(marker) ?: return@forEach
@ -299,8 +325,8 @@ actual class FMediaPlayer actual constructor(
}
// Soufflet
marker.trim() == "<" || marker.trim() == ">" ||
marker.trim().contains("cres", ignoreCase = true) ||
marker.trim().contains("dim", ignoreCase = true) -> {
marker.trim().contains("cres", ignoreCase = true) ||
marker.trim().contains("dim", ignoreCase = true) -> {
val symbol = when {
marker.trim() == "<" -> '<'
marker.trim() == ">" -> '>'
@ -324,7 +350,7 @@ actual class FMediaPlayer actual constructor(
val explicitDynAfter = metadataList
.filter { (_, gi, _, _, mk, _, _, _) ->
(gi ?: 0) >= pair.endGrid &&
extractDynamic(mk) != null
extractDynamic(mk) != null
}
.minByOrNull { it.gridIndex ?: 0 }
?.let { m -> extractDynamic(m.marker) }
@ -362,6 +388,7 @@ actual class FMediaPlayer actual constructor(
step.hairPin == null &&
step.dynamic == null &&
!step.isHold
&& !step.isFin
}
}
private fun startNavigationMonitor(sharedScreenModel: SharedScreenModel) {
@ -384,11 +411,24 @@ actual class FMediaPlayer actual constructor(
val step = navigationSteps.find {
it.gridIndex == currentIndex &&
!it.alreadyDone
!it.alreadyDone
}
if (step != null) {
when {
step.isFin -> {
if(step.finActive) {
step.alreadyDone = true
// println("Farany passage → FIN à grille $currentIndex")
sequencer?.stop()
sequencer?.tempoFactor = 1f
synthetizer?.channels?.forEach {
it?.controlChange(64, 0)
it?.controlChange(123, 0)
}
onFinished()
}
}
// Point d'orgue
step.isHold -> {
val currentBpm = sequencer?.tempoInBPM ?: targetBpm
@ -439,15 +479,21 @@ actual class FMediaPlayer actual constructor(
sequencer?.tempoFactor = 0.0001f
delay(beatDuration)
// println("et là je saut vers ${step.targetGrid}")
// println("et là je saut vers ${step.targetGrid}")
seekToGrid(step.targetGrid)
synthetizer?.channels?.forEach { it?.controlChange(64, 0) }
sequencer?.tempoFactor = 1f
navigationSteps.filter { it.isFin && step.gridIndex > it.gridIndex }
.forEach {
it.finActive = true
it.alreadyDone = false
}
if (sequencer?.isRunning == false) {
sequencer?.tempoInBPM = targetBpm
sequencer?.start()
}
// println("Après de sauter bpm=$targetBpm")
// println("Après de sauter bpm=$targetBpm")
}
}
}
@ -651,17 +697,17 @@ actual class FMediaPlayer actual constructor(
synthetizer?.channels?.let { channels ->
for (i in 0 until 4) {
if (i < channels.size) {
val userVol = voiceVolumes[i] / 127f
val globalVol = currentGlobalVolume
val userVol = voiceVolumes[i] / 127f
val globalVol = currentGlobalVolume
val finalVol = (127f * userVol * globalVol * currentDynamicFactor).toInt().coerceIn(0, 127)
val finalVol = (127f * userVol * globalVol * currentDynamicFactor).toInt().coerceIn(0, 127)
// println("Voice[$i] user=${voiceVolumes[i]} global=$currentGlobalVolume dynFactor=$currentDynamicFactor → finalVol=$finalVol")
channels[i].controlChange(7, finalVol)
channels[i].controlChange(11, finalVol)
channels[i].controlChange(7, finalVol)
channels[i].controlChange(11, finalVol)
if (finalVol == 0) channels[i].controlChange(123, 0)
if (finalVol == 0) channels[i].controlChange(123, 0)
/*val targetVolume = voiceVolumes[i].toInt()
channels[i].controlChange(7, targetVolume)
@ -682,7 +728,7 @@ actual class FMediaPlayer actual constructor(
actual fun changeInstru(noInstru: Int) {
val pgm = noInstru
synthetizer?.channels?.let {
channels ->
channels ->
for (i in 0 until 4) {
channels[i].programChange(pgm)
}