Implements ${P:x} for tempo change marker

This commit is contained in:
Hasinjato 2026-09-16 14:12:57 +03:00
parent 5a39e1b79b
commit c1beaed257
8 changed files with 22 additions and 17 deletions

View file

@ -499,7 +499,7 @@ actual class FMediaPlayer actual constructor(
val finReg = Regex("""(fine|fin|farany|end)""", RegexOption.IGNORE_CASE) val finReg = Regex("""(fine|fin|farany|end)""", 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)
val tempoRegex = Regex("""^♩\s*=\s*(\d+)""", RegexOption.IGNORE_CASE) val tempoRegex = Regex("""^(?:♩|P)\s*[:=]\s*(\d+)""", RegexOption.IGNORE_CASE)
metadataList.forEach { midiMarker -> metadataList.forEach { midiMarker ->
val ci = midiMarker.gridIndex ?: 0 val ci = midiMarker.gridIndex ?: 0
val last_grid = sharedScreenModel.getTotalGridCount() val last_grid = sharedScreenModel.getTotalGridCount()

View file

@ -692,12 +692,12 @@ private suspend fun generatePdfToBytes(
drawFermata(cs, colX + colWidth / 2 - 5f, markerY - 2f, 0.3f) drawFermata(cs, colX + colWidth / 2 - 5f, markerY - 2f, 0.3f)
} }
if (markerText.contains("♩")) { if (markerText.contains("P:")) {
val textPart = markerText.replace("♩", "BPM") val textPart = markerText
cs.beginText() cs.beginText()
cs.setFont(italicBoldFont, fontSize) cs.setFont(italicBoldFont, fontSize)
cs.newLineAtOffset(colX, markerY) cs.newLineAtOffset(colX, markerY)
cs.setFont(boldFont, fontSize-3f) cs.setFont(boldFont, fontSize)
cs.showText(textPart) cs.showText(textPart)
cs.endText() cs.endText()
} }

View file

@ -94,7 +94,7 @@ class MidiWriterforEXport constructor(private val fileRepository: FileRepositor
var pendingHairpinStartTick: Long? = null var pendingHairpinStartTick: Long? = null
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)
val tempoRegex = Regex("""^♩\s*=\s*(\d+)""", RegexOption.IGNORE_CASE) val tempoRegex = Regex("""^(?:♩|P)\s*[:=]\s*(\d+)""", RegexOption.IGNORE_CASE)
markers.forEach { midiMarker -> markers.forEach { midiMarker ->
val gridIdx = (midiMarker.gridIndex ?: 0) * 480L val gridIdx = (midiMarker.gridIndex ?: 0) * 480L

View file

@ -43,7 +43,7 @@ fun getAllMarker(): List<String> {
return markerGroups return markerGroups
.flatMap { group -> group.markers } .flatMap { group -> group.markers }
.map { marker -> marker.abbr } .map { marker -> marker.abbr }
.filter { it != "♩=" && it != "Dô dia" } .filter { it != "♩:" && it != "Dô dia" }
.sortedByDescending { it.length } .sortedByDescending { it.length }
} }
private val markerGroups = listOf( private val markerGroups = listOf(
@ -100,7 +100,7 @@ private val markerGroups = listOf(
Marker("rall.", "Ralentir"), Marker("rall.", "Ralentir"),
Marker("riten.", "Retenir le tempo"), Marker("riten.", "Retenir le tempo"),
Marker("string.", "Presser le tempo"), Marker("string.", "Presser le tempo"),
Marker("♩=", "Changement tempo", canEditValue = true, defaultValue = "60"), Marker("♩:", "Changement tempo", canEditValue = true, defaultValue = "60"),
Marker("allarg.", "Élargir le tempo"), Marker("allarg.", "Élargir le tempo"),
Marker("a_tempo", "Retour au tempo initial"), Marker("a_tempo", "Retour au tempo initial"),
Marker("Tempo I", "Retour au premier tempo"), Marker("Tempo I", "Retour au premier tempo"),

View file

@ -68,7 +68,7 @@ fun parseMarkers(rawText: String): List<String> {
.replace(Regex("""(D\.?S\.?)\s*(al\s*Coda)""", RegexOption.IGNORE_CASE), "D.S.alCoda") .replace(Regex("""(D\.?S\.?)\s*(al\s*Coda)""", RegexOption.IGNORE_CASE), "D.S.alCoda")
val allStaticMarkers = getAllMarker().sortedByDescending { it.length } val allStaticMarkers = getAllMarker().sortedByDescending { it.length }
val tempoRegex = Regex("""^(♩\s*=\s*\d+)""", RegexOption.IGNORE_CASE) val tempoRegex = Regex("""^(?:♩|P)\s*[:=]\s*(\d+)""", 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)
val measureRegex = Regex("""^\d+\s*/\s*\d+""") val measureRegex = Regex("""^\d+\s*/\s*\d+""")
@ -78,7 +78,8 @@ fun parseMarkers(rawText: String): List<String> {
val tempoMatch = tempoRegex.find(remaining) val tempoMatch = tempoRegex.find(remaining)
if (tempoMatch != null) { if (tempoMatch != null) {
tokens.add(tempoMatch.value) val bpm = tempoMatch.groupValues[1]
tokens.add("♩=$bpm")
remaining = remaining.substring(tempoMatch.value.length) remaining = remaining.substring(tempoMatch.value.length)
continue continue
} }

View file

@ -482,9 +482,13 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
"\${c:$lettre}" "\${c:$lettre}"
} else { } else {
markerClean.split(Regex("\\s+")).filter { it.isNotEmpty() }.joinToString(" ") { part -> markerClean.split(Regex("\\s+")).filter { it.isNotEmpty() }.joinToString(" ") { part ->
when (part) { val trimmed = part.trim()
"𝄐" -> "\$Q" when {
else -> "\${$part}" trimmed == "𝄐" -> "\$Q"
else -> {
val formattedPart = trimmed.replace("♩", "P")
"\${$formattedPart}"
}
} }
} }
} }

View file

@ -260,7 +260,7 @@ actual class FMediaPlayer actual constructor(
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)
val tempoRegex = Regex("""^♩\s*=\s*(\d+)""", RegexOption.IGNORE_CASE) val tempoRegex = Regex("""^(?:♩|P)\s*[:=]\s*(\d+)""", RegexOption.IGNORE_CASE)
metadataList.forEach { midiMarker -> metadataList.forEach { midiMarker ->
val currentIndex = midiMarker.gridIndex ?: 0 val currentIndex = midiMarker.gridIndex ?: 0

View file

@ -908,18 +908,18 @@ private suspend fun generatePdfToBytes(
) )
} }
if (markerText.contains("♩")) { if (markerText.contains("P:")) {
val textPart = markerText.replace("♩", "BPM") val textPart = markerText
cs.beginText() cs.beginText()
cs.setFont(italicBoldFont, fontSize) cs.setFont(italicBoldFont, fontSize)
cs.newLineAtOffset(colX, markerY) cs.newLineAtOffset(colX, markerY)
cs.setFont(boldFont, fontSize-3f) cs.setFont(boldFont, fontSize)
cs.showText(textPart) cs.showText(textPart)
cs.endText() cs.endText()
} }
// marqueur // marqueur
if (markerText.isNotBlank() && !markerText.contains("𝄐") && !markerText.contains("♩")) { if (markerText.isNotBlank() && !markerText.contains("𝄐") && !markerText.contains("P:")) {
val dsRegex = Regex("""D\.?S\.?""") val dsRegex = Regex("""D\.?S\.?""")
val dcRegex = Regex("""D\.?C\.?""") val dcRegex = Regex("""D\.?C\.?""")