diff --git a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/PNotes.kt b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/PNotes.kt index 6aaaf30..fecdea8 100644 --- a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/PNotes.kt +++ b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/PNotes.kt @@ -1,6 +1,6 @@ package mg.dot.feufaro.solfa -class PNotes (var note: String, private var markers: MutableList = mutableListOf("")) { +class PNotes (var note: String, var noteSplit: MutableList = mutableListOf(), private var markers: MutableList = mutableListOf()) { fun addMarker(newMarker: String) { markers.add(newMarker) } @@ -8,7 +8,20 @@ class PNotes (var note: String, private var markers: MutableList = mutab return markers.contains(marker) } fun toNote(): Note { - val newNote = Note(note) + val validSplits = noteSplit.filter { it.isNotBlank() } + + val finalNoteStr = if (validSplits.isNotEmpty()) { + val formattedSplits = if (validSplits.size > 1) { + validSplits.joinToString("|") + } else { + validSplits.joinToString("") + } + "$note>{$formattedSplits}" + } else { + note + } + + val newNote = Note(finalNoteStr) newNote.setMarkers(markers) return newNote } @@ -16,4 +29,12 @@ class PNotes (var note: String, private var markers: MutableList = mutab fun appendNote(noteSuffix: Char) { note += noteSuffix } + fun addSplitNote(splitNote: String) { + noteSplit.add(splitNote) + } + fun appendSplitNote(suffix: Char) { + if (noteSplit.isNotEmpty()) { + noteSplit[noteSplit.lastIndex] += suffix + } + } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/POneVoiceNote.kt b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/POneVoiceNote.kt index 3269a0d..8af0378 100644 --- a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/POneVoiceNote.kt +++ b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/POneVoiceNote.kt @@ -16,9 +16,15 @@ class POneVoiceNote { oneVoiceNote.lastOrNull()?.addMarker(marker.toString()) } fun addItem(noteString: String = "") { - val newNote: PNotes = PNotes(noteString, nextMarkers) + val newNote: PNotes = PNotes(note = noteString, noteSplit = mutableListOf(), markers = nextMarkers) oneVoiceNote.add(newNote) nextNote = "" nextMarkers = mutableListOf() } + fun appendLastSplitNote(splitNote: String) { + oneVoiceNote.lastOrNull()?.addSplitNote(splitNote) + } + fun appendLastSplitNoteSuffix(suffix: Char) { + oneVoiceNote.lastOrNull()?.appendSplitNote(suffix) + } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/Solfa.kt b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/Solfa.kt index dcb8447..ea016fd 100644 --- a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/Solfa.kt +++ b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/Solfa.kt @@ -20,7 +20,6 @@ import java.util.prefs.Preferences import kotlin.getValue import kotlin.math.min -//@todo: split voices (ffpm19/ews22) ${S:mfs} in N4:, idem ffpm-212 //@todo: ffpm-164.txt O10:s3:mflswss // alternative notes for stanza 3 only //@todo: ews-47.txt DS/$ + [12][3] //@todo: ffpm-99-2.txt triolet.mid + triolet (m--)-- @@ -67,8 +66,16 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository val REGEX_STRIP_DC = Regex("\\$\\{D[^:]*:[^\\}]*\\}") val REGEX_NOTE_TOADD = Regex("([drmfsltz][ia]?|[―])([₄₃₂₁¹²³⁴',]*)>([drmfsltz][ia]?|[―])([₄₃₂₁¹²³⁴',]*)") val REGEX_NOTE_TODROP = Regex("([drmfsltz][ia]?|[―])([₄₃₂₁¹²³⁴',]*)<") + val REGEX_NOTE_SPLIT = Regex("\\$\\{[Ss]:([^\\}]+)\\}([drmfsltDRFSTz][,']*)") } + fun parseNoteSplit(input: String): String { + return REGEX_NOTE_SPLIT.replace(input) { matchResult -> + val splitValues = matchResult.groupValues[1].chunked(1).joinToString("") + val mainNote = matchResult.groupValues[2] + "$mainNote<{$splitValues}" + } + } var nextTIndex: Int = -1 var nextNIndex: Int = -1 var nextLIndex: Int = -1 @@ -1806,11 +1813,19 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository private fun preloadN(noteLine: String) { val voiceNumber = noteLine.substring(0, 1).toInt() + val parsedNoteLine = parseNoteSplit(noteLine) val templateComments = mutableListOf() val templateStripped = REGEX_TEMPLATE_COMMENT.replace(templateString) { matchResult -> templateComments.add(matchResult.value) "&" } + val splitBlocks = mutableListOf() + val noteLineWithoutSplits = parsedNoteLine + .replace(REGEX_TEMPLATE_COMMENT, "") + .replace(Regex("<\\s*\\{[^\\}]*\\}")) { matchResult -> + splitBlocks.add(matchResult.value) + "§" + } fun insertZToCharArray(input: String): CharArray { val delim = "/:!|" val reDelim = "[$delim](?=[$delim])".toRegex() @@ -1818,9 +1833,9 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository return insertedZ.toCharArray() } val templateCharArray = insertZToCharArray(templateStripped) - val noteLine = noteLine.replace(REGEX_TEMPLATE_COMMENT, "") + val cleanNoteLine = noteLineWithoutSplits.replace(REGEX_TEMPLATE_COMMENT, "") .replace(" ", "") - val lineRepeated = REGEX_REPETITION.replace(noteLine.substring(1)) { matchResult -> + val lineRepeated = REGEX_REPETITION.replace(cleanNoteLine.substring(1)) { matchResult -> val (charIterated, iteration) = matchResult.destructured val nTimes = iteration.toInt() charIterated.repeat(nTimes) @@ -1830,6 +1845,10 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository var inAnchor = false var anchorNote = ' ' lineRepeated.toCharArray().forEach { + if (it == '§') { + noteChar2 += "§" + return@forEach + } if (inAnchor) { if (anchor.isEmpty()) { anchorNote = it @@ -1877,16 +1896,34 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository 'd', 'r', 'm', 'f', 's', 'l', 't', -> { if (firstInLoop) { - replacement = if (noteCharIterator.hasNext()) noteCharIterator.next() else 'd' + val nextChar = if (noteCharIterator.hasNext()) noteCharIterator.next() else 'd' + if (nextChar == '§') { + result += splitBlocks.removeAt(0) + replacement = if (noteCharIterator.hasNext()) noteCharIterator.next() else 'd' + } else { + replacement = nextChar + } firstInLoop = false } if (replacement == '(') { result += replacement - replacement = if (noteCharIterator.hasNext()) noteCharIterator.next() else 'd' + val nextChar = if (noteCharIterator.hasNext()) noteCharIterator.next() else 'd' + if (nextChar == '§') { + result += splitBlocks.removeAt(0) + replacement = if (noteCharIterator.hasNext()) noteCharIterator.next() else 'd' + } else { + replacement = nextChar + } } for (repetition in 0 until 6) { result += replacement - replacement = if (noteCharIterator.hasNext()) noteCharIterator.next() else 'd' + val nextChar = if (noteCharIterator.hasNext()) noteCharIterator.next() else 'd' + if (nextChar == '§') { + result += splitBlocks.removeAt(0) + replacement = if (noteCharIterator.hasNext()) noteCharIterator.next() else 'd' + break + } + replacement = nextChar if (replacement in setOf( 'd', 'r', 'm', 'f', 's', 'l', 't', 'z', '(', 'D', 'R', 'M', 'F', 'S', 'L', 'T', '-', 'w', 'Z' @@ -2067,17 +2104,29 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository charIterated.repeat(nTimes) } var commentNumber = -1 + var inSplit = false val lineChar = lineRepeated.toCharArray() lineChar.forEach { when (it) { - '|', ':', '!', '/' -> { - if (lastIt == '|' || lastIt == ':' || lastIt == '!' || lastIt == '/') { + '|', ':', '!', '/', '&' -> { + if (it == '|' && lastIt == '[') { + // le séparateur split + } else if (lastIt == '|' || lastIt == ':' || lastIt == '!' || lastIt == '/') { } else { midiDuration += nextDuration nextDuration = 60 } } + // blocs de split <[...] + '<' -> { } + '{' -> { + inSplit = true + } + '}' -> { + inSplit = false + } + '.' -> { if (lastIt == ';') { pushMidi() @@ -2106,8 +2155,12 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository } '\'', ',' -> { - newN.appendLastNote(it) - lastNoteString += it + if(!inSplit ){ + newN.appendLastNote(it) + lastNoteString += it + } else { + newN.appendLastSplitNoteSuffix(it) + } } '(', '[' -> newN.addNextMarker(it) @@ -2135,40 +2188,46 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository if (it == 'T') { noteString += "a" } - newN.addItem(noteString) - when (noteString) { - "-" -> { - midiDuration += nextDuration - nextDuration = 0 - } - - "z", "@" -> { - if (lastNoteString == "z") { + if(inSplit) { + newN.appendLastSplitNote(noteString) + } else { + newN.addItem(noteString) + when (noteString) { + "-" -> { midiDuration += nextDuration nextDuration = 0 - } else { - pushMidi() - //noteString = } - lastNoteString = "z" - } - "'", "(", ")", "[", "]", "," -> {} - else -> { - pushMidi() - lastNoteString = noteString + "z", "@" -> { + if (lastNoteString == "z") { + midiDuration += nextDuration + nextDuration = 0 + } else { + pushMidi() + //noteString = + } + lastNoteString = "z" + } + + "'", "(", ")", "{", "}", "," -> {} + else -> { + pushMidi() + lastNoteString = noteString + } } } } '@' -> { - if (lastNoteString == "z") { - midiDuration += nextDuration - nextDuration = 0 - } else { - pushMidi() + if(!inSplit) { + if (lastNoteString == "z") { + midiDuration += nextDuration + nextDuration = 0 + } else { + pushMidi() + } + lastNoteString = "z" } - lastNoteString = "z" } 'i', 'a' -> diff --git a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/TimeUnitObject.kt b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/TimeUnitObject.kt index 0e28039..c65b2ba 100644 --- a/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/TimeUnitObject.kt +++ b/composeApp/src/commonMain/kotlin/mg/dot/feufaro/solfa/TimeUnitObject.kt @@ -471,21 +471,26 @@ fun TimeUnitComposable( ){ val annotatedText = remember(multiLineText, MaterialTheme.colorScheme.primary) { buildAnnotatedString { - multiLineText.split(">").mapIndexed { index, text -> - if (index %2 == 0) { - append(text) - } else { - withStyle( - style = SpanStyle( - fontSize = 10.sp, - baselineShift = BaselineShift.Superscript, - //fontStyle = FontStyle.Italic, - /*color = MaterialTheme.colorScheme.primary*/ - )) { + val lines = multiLineText.lines() + lines.forEachIndexed { lineIndex, line -> + if (lineIndex > 0) { + append("\n") + } + line.split(">").mapIndexed { index, text -> + if (index % 2 == 0) { + append(text) + } else { + withStyle( + style = SpanStyle( + fontSize = 10.sp, + baselineShift = BaselineShift.Superscript, + //fontStyle = FontStyle.Italic, + /*color = MaterialTheme.colorScheme.primary*/ + )) { append(text+" ") } + } } - } } }