Use musical fonts for specific markers
This commit is contained in:
parent
9550ab0e3c
commit
90c7b40d84
10 changed files with 114 additions and 61 deletions
|
|
@ -102,6 +102,9 @@ kotlin {
|
|||
}
|
||||
}
|
||||
|
||||
compose.resources {
|
||||
publicResClass = true
|
||||
}
|
||||
android {
|
||||
namespace = "mg.dot.feufaro"
|
||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||
|
|
|
|||
|
|
@ -253,16 +253,22 @@ private fun drawNoteWithSubscript(
|
|||
text: String, x: Float, y: Float
|
||||
) {
|
||||
var curX = x
|
||||
var i = 0
|
||||
while (i < text.length) {
|
||||
val str = text[i].toString()
|
||||
val superscriptOffset = fontSize * 0.35f
|
||||
|
||||
for (char in text) {
|
||||
val str = char.toString().sanitize()
|
||||
val isSuperscript = char in setOf('¹', '²', '³')
|
||||
val isSubscript = char in setOf('₁', '₂', '₃')
|
||||
|
||||
val currentSize = if (isSuperscript || isSubscript) fontSize * 0.6f else fontSize
|
||||
val currentY = if (isSuperscript) y + superscriptOffset else y
|
||||
|
||||
cs.beginText()
|
||||
cs.setFont(font, fontSize)
|
||||
cs.newLineAtOffset(curX, y)
|
||||
cs.showText(str.sanitize())
|
||||
cs.setFont(font, currentSize)
|
||||
cs.newLineAtOffset(curX, currentY)
|
||||
cs.showText(str)
|
||||
cs.endText()
|
||||
curX += font.getStringWidth(str.sanitize()) / 1000f * fontSize
|
||||
i++
|
||||
curX += font.getStringWidth(str) / 1000f * currentSize + 0.5f
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -446,11 +452,11 @@ private suspend fun generatePdfToBytes(
|
|||
val customNbGrid = settings.nbGridOnMeasure
|
||||
|
||||
// ── Polices ────────────────────────────────────────────────────────────────
|
||||
val noteFontBytes = Res.readBytes("files/PTSerif-Regular.ttf")
|
||||
val lyricFontBytes = Res.readBytes("files/LinLibertine_R.ttf")
|
||||
val markerItalicBoldFontBytes = Res.readBytes("files/PT Serif Bold Italic.ttf")
|
||||
val markerBoldFontBytes = Res.readBytes("files/PTSerif-Bold.ttf")
|
||||
val emmentalerFontBytes = Res.readBytes("files/emmentaler-20.ttf")
|
||||
val noteFontBytes = Res.readBytes("font/PTSerif-Regular.ttf")
|
||||
val lyricFontBytes = Res.readBytes("font/LinLibertine_R.ttf")
|
||||
val markerItalicBoldFontBytes = Res.readBytes("font/PT_Serif_Bold_Italic.ttf")
|
||||
val markerBoldFontBytes = Res.readBytes("font/PTSerif_Bold.ttf")
|
||||
val emmentalerFontBytes = Res.readBytes("font/Emmentaler.ttf")
|
||||
|
||||
PDDocument().use { doc ->
|
||||
|
||||
|
|
@ -611,6 +617,15 @@ private suspend fun generatePdfToBytes(
|
|||
drawFermata(cs, colX + colWidth / 2 - 5f, markerY - 2f, 0.3f)
|
||||
}
|
||||
|
||||
if (markerText.contains("♩")) {
|
||||
val textPart = markerText.replace("♩", "BPM")
|
||||
cs.beginText()
|
||||
cs.setFont(italicBoldFont, fontSize)
|
||||
cs.newLineAtOffset(colX, markerY)
|
||||
cs.setFont(boldFont, fontSize-3f)
|
||||
cs.showText(textPart)
|
||||
cs.endText()
|
||||
}
|
||||
// Marqueur texte
|
||||
if (markerText.isNotBlank() && !markerText.contains("𝄐")) {
|
||||
val dsRegex = Regex("""D\.?S\.?""")
|
||||
|
|
|
|||
BIN
composeApp/src/commonMain/composeResources/font/Emmentaler.ttf
Normal file
BIN
composeApp/src/commonMain/composeResources/font/Emmentaler.ttf
Normal file
Binary file not shown.
BIN
composeApp/src/commonMain/composeResources/font/PTSerif_Bold.ttf
Normal file
BIN
composeApp/src/commonMain/composeResources/font/PTSerif_Bold.ttf
Normal file
Binary file not shown.
Binary file not shown.
|
|
@ -33,28 +33,28 @@ object HarmonicAnalyzer {
|
|||
)
|
||||
|
||||
private val chordDefinitions = listOf(
|
||||
ChordDef("maj7", setOf(0, 4, 7, 11), setOf(4, 11), 12),
|
||||
ChordDef("7", setOf(0, 4, 7, 10), setOf(4, 10), 12),
|
||||
ChordDef("m7", setOf(0, 3, 7, 10), setOf(3, 10), 12),
|
||||
ChordDef("dim7", setOf(0, 3, 6, 9), setOf(3, 6, 9), 12),
|
||||
ChordDef("m7b5", setOf(0, 3, 6, 10), setOf(3, 6, 10), 12),
|
||||
ChordDef("7sus4", setOf(0, 5, 7, 10), setOf(5, 10), 12),
|
||||
ChordDef("maj7sus2", setOf(0, 2, 7, 11), setOf(2, 11), 12),
|
||||
ChordDef("maj7#11", setOf(0, 4, 6, 7), setOf(4, 6), 12),
|
||||
ChordDef("add9", setOf(0, 2, 4, 7), setOf(2, 4), 11),
|
||||
ChordDef("madd9", setOf(0, 2, 3, 7), setOf(2, 3), 11),
|
||||
ChordDef("add11", setOf(0, 4, 5, 7), setOf(4, 5), 11),
|
||||
ChordDef("maj⁷", setOf(0, 4, 7, 11), setOf(4, 11), 12),
|
||||
ChordDef("⁷", setOf(0, 4, 7, 10), setOf(4, 10), 12),
|
||||
ChordDef("ₘ⁷", setOf(0, 3, 7, 10), setOf(3, 10), 12),
|
||||
ChordDef("dim⁷", setOf(0, 3, 6, 9), setOf(3, 6, 9), 12),
|
||||
ChordDef("ₘ⁷b⁵", setOf(0, 3, 6, 10), setOf(3, 6, 10), 12),
|
||||
ChordDef("⁷sus⁴", setOf(0, 5, 7, 10), setOf(5, 10), 12),
|
||||
ChordDef("maj⁷sus²", setOf(0, 2, 7, 11), setOf(2, 11), 12),
|
||||
ChordDef("maj⁷#¹¹", setOf(0, 4, 6, 7), setOf(4, 6), 12),
|
||||
ChordDef("add⁹", setOf(0, 2, 4, 7), setOf(2, 4), 11),
|
||||
ChordDef("ₘadd⁹", setOf(0, 2, 3, 7), setOf(2, 3), 11),
|
||||
ChordDef("add¹¹", setOf(0, 4, 5, 7), setOf(4, 5), 11),
|
||||
|
||||
ChordDef("", setOf(0, 4, 7), setOf(4), 8),
|
||||
ChordDef("m", setOf(0, 3, 7), setOf(3), 8),
|
||||
ChordDef("ₘ", setOf(0, 3, 7), setOf(3), 8),
|
||||
ChordDef("dim", setOf(0, 3, 6), setOf(3, 6), 8),
|
||||
ChordDef("aug", setOf(0, 4, 8), setOf(4, 8), 8),
|
||||
ChordDef("sus2", setOf(0, 2, 7), setOf(2), 8),
|
||||
ChordDef("sus4", setOf(0, 5, 7), setOf(5), 8),
|
||||
ChordDef("sus²", setOf(0, 2, 7), setOf(2), 8),
|
||||
ChordDef("sus⁴", setOf(0, 5, 7), setOf(5), 8),
|
||||
|
||||
ChordDef("5", setOf(0, 7), setOf(7), 5),
|
||||
ChordDef("⁵", setOf(0, 7), setOf(7), 5),
|
||||
ChordDef("", setOf(0, 4), setOf(4), 5),
|
||||
ChordDef("m", setOf(0, 3), setOf(3), 5),
|
||||
ChordDef("ₘ", setOf(0, 3), setOf(3), 5),
|
||||
|
||||
ChordDef("", setOf(0), setOf(), 3)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@ import androidx.compose.ui.text.style.BaselineShift
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.*
|
||||
import androidx.compose.ui.window.Popup
|
||||
import feufaro.composeapp.generated.resources.Emmentaler
|
||||
import feufaro.composeapp.generated.resources.PTSerif_Bold
|
||||
import feufaro.composeapp.generated.resources.PT_Serif_Bold_Italic
|
||||
import feufaro.composeapp.generated.resources.Res
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
@ -54,6 +58,7 @@ import mg.dot.feufaro.getPathValidator
|
|||
import mg.dot.feufaro.ui.rememberFileSaveLauncher
|
||||
import mg.dot.feufaro.viewmodel.MidiMarkers
|
||||
import mg.dot.feufaro.viewmodel.SolfaScreenModel
|
||||
import org.jetbrains.compose.resources.Font
|
||||
import java.io.File
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
|
|
@ -689,6 +694,11 @@ fun LazyVerticalGridTUO(
|
|||
val totalSyllables = sharedScreenModel.synchronizedSyllables.value.size
|
||||
//println("Sync complète effectuée SUR stz: ${sharedScreenModel.stanza.value}! Total colonnes : $totalSyllables")
|
||||
}
|
||||
var emmentaler = FontFamily(Font(Res.font.Emmentaler))
|
||||
var ptSerifBoldItalic = FontFamily(Font(Res.font.PT_Serif_Bold_Italic))
|
||||
var ptSerif = FontFamily(Font(Res.font.PTSerif_Bold))
|
||||
var markerFontFamily: FontFamily = FontFamily.Default
|
||||
|
||||
val textMeasurer = rememberTextMeasurer()
|
||||
val containerWidthDp = gridWidthDp / gridColumnCount
|
||||
val REGEX_CLEAN_PREFIX = Regex("(\\d+\\.)+")
|
||||
|
|
@ -757,6 +767,7 @@ fun LazyVerticalGridTUO(
|
|||
val lineHeightDp : Dp = with(density) {
|
||||
lineHeight.toDp()
|
||||
}
|
||||
var markerFontSize: Float = MaterialTheme.typography.titleMedium.fontSize.value
|
||||
var fontStyle = FontStyle.Normal
|
||||
var fontWeight = FontWeight.Normal
|
||||
val hairPinSymbol = tuo.hasHairPin()
|
||||
|
|
@ -811,11 +822,21 @@ fun LazyVerticalGridTUO(
|
|||
// problème si template = $QD:,-$QD
|
||||
tuo.pTemplate.resetCalledMarker()
|
||||
val text = tuo.pTemplate.markerToString()
|
||||
if (text.contains(Regex("^([mfp]+|[rR]it.*)$"))) {
|
||||
fontStyle = FontStyle.Italic
|
||||
}
|
||||
if (text.contains(Regex("^\\s*(ppp|pp|p|mp|mf|f|ff|fff)\\s*$"))) {
|
||||
fontWeight = FontWeight.Bold
|
||||
val musicForPtSerifBIRegex = Regex("""^(Largh\.|Grave|Largo|Lento|Adagio|And\.|Andantino|Mod\.|Moderato|Alleg\.|All\.|Viv\.|Vivacissimo|Presto|Prestiss\.|accel\.|rit\.|rall\.|riten\.|string\.|allarg\.|a tempo|Tempo I|rubato|meno mosso|più mosso|cres\.|<|decresc\.|dim\.|>|rfz|fp|pf|sub\.p|sub\.f)""", RegexOption.IGNORE_CASE)
|
||||
val musicForEmmentRegex = Regex("""\b(ppp|pp|mp|mf|fff|ff|p|f|sfz|sf|fz|rfz|fp|pf)\b""", RegexOption.IGNORE_CASE)
|
||||
|
||||
when {
|
||||
musicForPtSerifBIRegex.containsMatchIn(text) -> {
|
||||
markerFontSize = MaterialTheme.typography.titleMedium.fontSize.value
|
||||
markerFontFamily = ptSerifBoldItalic
|
||||
}
|
||||
musicForEmmentRegex.containsMatchIn(text) -> {
|
||||
markerFontSize = MaterialTheme.typography.titleMedium.fontSize.value+11
|
||||
markerFontFamily = emmentaler
|
||||
}
|
||||
else -> {
|
||||
markerFontFamily = ptSerif
|
||||
}
|
||||
}
|
||||
Text(text = text,
|
||||
modifier = Modifier
|
||||
|
|
@ -823,10 +844,11 @@ fun LazyVerticalGridTUO(
|
|||
softWrap = false,
|
||||
maxLines = 1,
|
||||
fontStyle = fontStyle,
|
||||
fontWeight = fontWeight,
|
||||
style = TextStyle(
|
||||
fontWeight = FontWeight.Bold,
|
||||
style = MaterialTheme.typography.titleMedium.copy(
|
||||
color = MaterialTheme.colorScheme.onSecondary,
|
||||
fontSize = MaterialTheme.typography.titleMedium.fontSize
|
||||
fontSize = markerFontSize.sp,
|
||||
fontFamily = markerFontFamily
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -414,6 +414,10 @@ private fun drawNoteWithModulation(
|
|||
parts.forEachIndexed { index, part ->
|
||||
if (part.isEmpty()) return@forEachIndexed
|
||||
|
||||
val sanitizedPart = part
|
||||
.replace('\u2015', '-')
|
||||
.replace('\u2014', '-')
|
||||
.replace('\u2013', '-')
|
||||
// RÈGLE : Si c'est avant le dernier segment, c'est un exposant
|
||||
// Dans ">t>m", 't' est à l'index 1 (exposant), 'm' est à l'index 2 (normal)
|
||||
// ATTENTION : selon votre logique, si c'est ">t>m", t=exposant, m=normal ?
|
||||
|
|
@ -427,10 +431,10 @@ private fun drawNoteWithModulation(
|
|||
cs.beginText()
|
||||
cs.setTextMatrix(Matrix.getTranslateInstance(currentX, currentY))
|
||||
cs.setFont(font, currentSize)
|
||||
cs.showText(part)
|
||||
cs.showText(sanitizedPart)
|
||||
cs.endText()
|
||||
|
||||
currentX += textWidth(font, currentSize, part) + 0.5f
|
||||
currentX += textWidth(font, currentSize, sanitizedPart) + 0.5f
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -443,23 +447,22 @@ private fun drawNoteWithSubscript(
|
|||
y: Float
|
||||
) {
|
||||
var curX = x
|
||||
var i = 0
|
||||
while (i < text.length) {
|
||||
val ch = text[i]
|
||||
val str = ch.toString()
|
||||
val superscriptOffset = fontSize * 0.35f
|
||||
|
||||
for (char in text) {
|
||||
val str = char.toString().sanitize()
|
||||
val isSuperscript = char in setOf('¹', '²', '³')
|
||||
val isSubscript = char in setOf('₁', '₂', '₃')
|
||||
|
||||
val currentSize = if (isSuperscript || isSubscript) fontSize * 0.6f else fontSize
|
||||
val currentY = if (isSuperscript) y + superscriptOffset else y
|
||||
|
||||
cs.beginText()
|
||||
when(ch) {
|
||||
'₁', '₂', '₃', '¹', '²', '³' -> {
|
||||
cs.setFont(font, fontSize * 0.6f)
|
||||
} else -> {
|
||||
cs.setFont(font, fontSize)
|
||||
}
|
||||
}
|
||||
cs.newLineAtOffset(curX, y)
|
||||
cs.showText(str.sanitize())
|
||||
cs.setFont(font, currentSize)
|
||||
cs.newLineAtOffset(curX, currentY)
|
||||
cs.showText(str)
|
||||
cs.endText()
|
||||
curX += font.getStringWidth(str.sanitize()) / 1000f * fontSize
|
||||
i++
|
||||
curX += font.getStringWidth(str) / 1000f * currentSize + 0.5f
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -647,11 +650,11 @@ private suspend fun generatePdfToBytes(
|
|||
val customNbGrid = settings.nbGridOnMeasure
|
||||
|
||||
// ── Polices ────────────────────────────────────────────────────
|
||||
val noteFontBytes = Res.readBytes("files/PTSerif-Regular.ttf")
|
||||
val lyricFontBytes = Res.readBytes("files/LinLibertine_R.ttf")
|
||||
val markerItalicBoldFontBytes = Res.readBytes("files/PT Serif Bold Italic.ttf")
|
||||
val markerBoldFontBytes = Res.readBytes("files/PTSerif-Bold.ttf")
|
||||
val emmentalerFontBytes = Res.readBytes("files/emmentaler-20.ttf")
|
||||
val noteFontBytes = Res.readBytes("font/PTSerif-Regular.ttf")
|
||||
val lyricFontBytes = Res.readBytes("font/LinLibertine_R.ttf")
|
||||
val markerItalicBoldFontBytes = Res.readBytes("font/PT_Serif_Bold_Italic.ttf")
|
||||
val markerBoldFontBytes = Res.readBytes("font/PTSerif_Bold.ttf")
|
||||
val emmentalerFontBytes = Res.readBytes("font/Emmentaler.ttf")
|
||||
|
||||
PDDocument().use { doc ->
|
||||
|
||||
|
|
@ -831,13 +834,23 @@ private suspend fun generatePdfToBytes(
|
|||
)
|
||||
}
|
||||
|
||||
if (markerText.contains("♩")) {
|
||||
val textPart = markerText.replace("♩", "BPM")
|
||||
cs.beginText()
|
||||
cs.setFont(italicBoldFont, fontSize)
|
||||
cs.newLineAtOffset(colX, markerY)
|
||||
cs.setFont(boldFont, fontSize-3f)
|
||||
cs.showText(textPart)
|
||||
cs.endText()
|
||||
}
|
||||
|
||||
// marqueur
|
||||
if (markerText.isNotBlank() && !markerText.contains("𝄐")) {
|
||||
if (markerText.isNotBlank() && !markerText.contains("𝄐") && !markerText.contains("♩")) {
|
||||
val dsRegex = Regex("""D\.?S\.?""")
|
||||
val dcRegex = Regex("""D\.?C\.?""")
|
||||
|
||||
cs.beginText()
|
||||
if(markerText.matches(Regex("^\\s*(ppp|pp|p|mp|mf|f|ff|fff)\\s*$"))) {
|
||||
if(markerText.matches(Regex("^\\s*(ppp|pp|mp|mf|fff|ff|p|f|sfz|sf|fz|rfz|fp|pf)\\s*$"))) {
|
||||
cs.setFont(emmentalerFont, fontSize+10f)
|
||||
}
|
||||
else if (markerText.contains(dsRegex) ||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue