Midi generation enhancements
This commit is contained in:
parent
a35d7c38ff
commit
3867dbc855
6 changed files with 109 additions and 27 deletions
|
|
@ -1,5 +1,6 @@
|
|||
package mg.dot.feufaro.midi
|
||||
|
||||
import mg.dot.feufaro.solfa.ParseULine
|
||||
import mg.dot.feufaro.solfa.Transpose
|
||||
|
||||
|
||||
|
|
@ -10,7 +11,10 @@ data class MidiPitch (
|
|||
var alter: String = "",
|
||||
var duration: Int = 0,
|
||||
var markers: List<String> = listOf(),
|
||||
var tick : Int = 0
|
||||
var tick : Int = 0,
|
||||
var metaBytes: String = "",
|
||||
var metaByteSize: Int = 0,
|
||||
var metaType : Int = -1
|
||||
) {
|
||||
var velocity: Int = 96
|
||||
companion object {
|
||||
|
|
@ -18,18 +22,25 @@ data class MidiPitch (
|
|||
var curVoiceNumber: Int = 0
|
||||
var nextTick : MutableList<Int> = mutableListOf()
|
||||
}
|
||||
fun setMeta(type: Int, tickMeta: Int, nb: Int, data0: Int, data1: Int = 0, data2: Int = 0, data3: Int = 0, data4: Int = 0) {
|
||||
metaBytes = ""+ data0.toChar() + data1.toChar() + data2.toChar() + data3.toChar() + data4.toChar()
|
||||
tick = tickMeta
|
||||
metaByteSize = nb
|
||||
metaType = type
|
||||
}
|
||||
fun setNote(note: String, theDuration: Int) {
|
||||
val midiPitch = Transpose.transposeToMidi(note, key, "C")
|
||||
if (midiPitch < 0) {
|
||||
velocity = 0
|
||||
velocity = if (midiPitch < 0) {
|
||||
0
|
||||
} else {
|
||||
velocity = 99
|
||||
99
|
||||
}
|
||||
pitch = midiPitch.toString()
|
||||
duration = theDuration
|
||||
tick = nextTick[voiceNumber]
|
||||
tick = nextTick.getOrNull(voiceNumber) ?: 0
|
||||
nextTick[voiceNumber] = theDuration + tick
|
||||
voiceNumber = curVoiceNumber
|
||||
metaType = -1
|
||||
}
|
||||
fun setMarker(theMarkers : MutableList<String>) {
|
||||
if (theMarkers.isNotEmpty()) {
|
||||
|
|
@ -46,6 +57,27 @@ data class MidiPitch (
|
|||
}
|
||||
fun initKey(theKey: String) {
|
||||
key = theKey
|
||||
val armature = Transpose.toArmature(key)
|
||||
val tickMeta = nextTick.getOrNull(0) ?: 0
|
||||
setMeta(0x59, tickMeta, 2, armature)
|
||||
}
|
||||
fun initMeasure(theMeasure: String): Boolean {
|
||||
val numerator = theMeasure.replace(Regex("/.*"), "").toIntOrNull()
|
||||
val denominator = theMeasure.replace(Regex("^[^/]*/(\\d+).*$"), "$1").toIntOrNull() ?: 4
|
||||
val data1 = when (denominator) {
|
||||
1 -> 0
|
||||
2 -> 1
|
||||
4 -> 2
|
||||
8 -> 3
|
||||
16 -> 4
|
||||
else -> 5
|
||||
}
|
||||
val blankDuration = (4 * (numerator ?: 4) - ParseULine.blankDuration) * 15
|
||||
if (numerator != null) {
|
||||
setMeta(0x58, blankDuration, 4, numerator, data1, 60, 20)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
fun reset() {
|
||||
tick = 0
|
||||
|
|
|
|||
|
|
@ -14,13 +14,18 @@ class MidiWriterKotlin (private val fileRepository: FileRepository) {
|
|||
private val noteOn = ShortMessage()
|
||||
private val noteOff = ShortMessage()
|
||||
private val lastPitch : MutableList<Int> = mutableListOf()
|
||||
private val useChord : Boolean = true
|
||||
fun addNote( voiceNumber: Int, note: Int, velocity: Int, tick: Long) {
|
||||
var channel: Int = voiceNumber - 1
|
||||
if (useChord) {
|
||||
channel = channel / 2
|
||||
}
|
||||
var note = note
|
||||
if (voiceNumber == 3 || voiceNumber == 4) {
|
||||
note -= 12
|
||||
}
|
||||
if (lastPitch.size > voiceNumber && lastPitch[voiceNumber] > 0) {
|
||||
noteOff.setMessage(ShortMessage.NOTE_OFF, voiceNumber - 1, lastPitch[voiceNumber], 0)
|
||||
noteOff.setMessage(ShortMessage.NOTE_OFF, channel, lastPitch[voiceNumber], 0)
|
||||
val n2 = noteOff.clone() as MidiMessage
|
||||
track.add(MidiEvent(n2, tick))
|
||||
}
|
||||
|
|
@ -29,7 +34,7 @@ class MidiWriterKotlin (private val fileRepository: FileRepository) {
|
|||
note = 40
|
||||
velocity = 0
|
||||
}
|
||||
noteOn.setMessage(ShortMessage.NOTE_ON, voiceNumber - 1, note, velocity)
|
||||
noteOn.setMessage(ShortMessage.NOTE_ON, channel, note, velocity)
|
||||
val n1: MidiMessage = noteOn.clone() as MidiMessage
|
||||
track.add(MidiEvent(n1, tick))
|
||||
while(lastPitch.size <= voiceNumber) {
|
||||
|
|
@ -45,12 +50,22 @@ class MidiWriterKotlin (private val fileRepository: FileRepository) {
|
|||
out.close()
|
||||
}
|
||||
}
|
||||
fun addMetaMessage(type: Int, tick: Int, nbData: Int, metaByteString: String) {
|
||||
val byteArray = metaByteString.toByteArray()
|
||||
val metaMessage = MetaMessage(type, byteArray, nbData)
|
||||
track.add(MidiEvent(metaMessage, tick.toLong()))
|
||||
}
|
||||
fun process(pitches: List<MidiPitch>) {
|
||||
val lastTick = 0
|
||||
nextTick.clear()
|
||||
// addMetaMessage(0x59, 4, 2, 2,0)
|
||||
tick = 0
|
||||
pitches.forEach {
|
||||
if (it.metaType > 0) {
|
||||
addMetaMessage(it.metaType, it.tick, it.metaByteSize, it.metaBytes)
|
||||
} else if (it.pitch != "") {
|
||||
addNote(it.voiceNumber, it.pitch.toInt(), 100, it.tick.toLong())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -80,7 +80,7 @@ class MusicXML(private val fileRepository: FileRepository) {
|
|||
}
|
||||
}
|
||||
suspend fun load() {
|
||||
val xmlContent = fileRepository.readFileContent("assets://31.xml")
|
||||
val xmlContent = fileRepository.readFileContent("assets://ews-89.xml")
|
||||
val xslContent = fileRepository.readFileContent("assets://timepart.xsl")
|
||||
xmlString = performXsltTransformation(xmlContent, xslContent)
|
||||
val solfaXML = SolfaXML()
|
||||
|
|
@ -215,7 +215,7 @@ class MusicXML(private val fileRepository: FileRepository) {
|
|||
init {
|
||||
val parseScope = CoroutineScope(Dispatchers.Default)
|
||||
parseScope.launch {
|
||||
if (true)
|
||||
if (false)
|
||||
load()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ class ParseULine (var line: String, var measure: Int) {
|
|||
'y' to listOf(".,D:", ".-,:D,", ":,D.", ":-,.D,"),
|
||||
't' to listOf("DD", "DD", "DD", "DD")
|
||||
)
|
||||
var blankDuration: Int = 0
|
||||
}
|
||||
|
||||
fun parsed() : String {
|
||||
|
|
@ -28,6 +29,7 @@ class ParseULine (var line: String, var measure: Int) {
|
|||
"O" -> 24
|
||||
else -> capturedChar.toInt()
|
||||
}
|
||||
blankDuration = cursorX
|
||||
line = matchResult.groups[2]!!.value
|
||||
parsedString = ":"
|
||||
if (capturedChar == "0") {
|
||||
|
|
|
|||
|
|
@ -166,9 +166,9 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
|
|||
println("Erreur parseScope Solfa:150 : ${e.message} iter: ${TimeUnitObject.nbBlock}")
|
||||
}
|
||||
val pitches = pitches.sortedWith( compareBy({it.tick}, {it.voiceNumber}))
|
||||
val k = MidiWriterKotlin(fileRepository)
|
||||
k.process(pitches)
|
||||
k.save("whawyd3.mid")
|
||||
val midiWriter = MidiWriterKotlin(fileRepository)
|
||||
midiWriter.process(pitches)
|
||||
midiWriter.save("whawyd3.mid")
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -363,12 +363,51 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
|
|||
sharedScreenModel.setSongRhythm(meta["r"] ?: "")
|
||||
}
|
||||
private fun loadN(voiceNumber: Int, line: String, templateComments: MutableList<String>) {
|
||||
val midiPitch = MidiPitch(voiceNumber)
|
||||
midiPitch.currentVoiceNumber(voiceNumber)
|
||||
midiPitch.initKey(meta["C"] ?: "C")
|
||||
var midiDuration = 0
|
||||
var nextDuration = 0
|
||||
var lastNoteString = ""
|
||||
val midiPitch = MidiPitch(voiceNumber)
|
||||
var nextComment: MutableList<String> = mutableListOf()
|
||||
fun pushMidi(typeBlock: String = "note") {
|
||||
if (typeBlock == "measure") {
|
||||
val z = midiPitch.copy()
|
||||
if (z.tick != 0) {
|
||||
val tickMeta = midiPitch.tick
|
||||
val numerator = midiPitch.metaBytes.toByteArray()[0].toInt()
|
||||
val denominatorPower = midiPitch.metaBytes.toByteArray()[1].toInt()
|
||||
val denominator = 1 shl denominatorPower
|
||||
z.tick = 0
|
||||
val newNumerator = tickMeta / 15 / denominator
|
||||
z.metaBytes = "" + newNumerator.toChar() + denominatorPower.toChar() + 60.toChar() + 20.toChar()
|
||||
|
||||
pitches.add(z)
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (midiDuration > 0 && typeBlock == "note") {
|
||||
midiPitch.setNote(lastNoteString, midiDuration)
|
||||
pitches.add(midiPitch.copy())
|
||||
midiPitch.setMarker(nextComment)
|
||||
} else if (typeBlock == "meta") {
|
||||
pitches.add(midiPitch.copy())
|
||||
}
|
||||
midiPitch.metaBytes = ""
|
||||
midiPitch.metaType = -1
|
||||
midiPitch.duration = 0
|
||||
lastNoteString = ""
|
||||
midiDuration = 0
|
||||
nextComment = mutableListOf()
|
||||
}
|
||||
|
||||
midiPitch.currentVoiceNumber(voiceNumber)
|
||||
if (voiceNumber == 1) {
|
||||
midiPitch.initKey(meta["C"] ?: "C")
|
||||
pushMidi("meta")
|
||||
if (midiPitch.initMeasure(meta["m"] ?: "4/4")) {
|
||||
pushMidi("measure")
|
||||
pushMidi("meta")
|
||||
}
|
||||
}
|
||||
var lastIt = ' '
|
||||
val newN = POneVoiceNote()
|
||||
val lineRepeated = REGEX_REPETITION.replace(line) { matchResult ->
|
||||
|
|
@ -377,17 +416,6 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
|
|||
charIterated.repeat(nTimes)
|
||||
}
|
||||
var commentNumber = -1
|
||||
var nextComment: MutableList<String> = mutableListOf()
|
||||
fun pushMidi() {
|
||||
if (midiDuration > 0) {
|
||||
midiPitch.setNote(lastNoteString, midiDuration)
|
||||
pitches.add(midiPitch.copy())
|
||||
midiPitch.setMarker(nextComment)
|
||||
}
|
||||
lastNoteString = ""
|
||||
midiDuration = 0
|
||||
nextComment = mutableListOf()
|
||||
}
|
||||
val lineChar = lineRepeated.toCharArray()
|
||||
lineChar.forEach {
|
||||
when (it) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ class Transpose {
|
|||
val octaveSigns = listOf("₄", "₃", "₂", "₁", "", "¹", "²", "³", "⁴")
|
||||
val noteToNumber = listOf("d", "di", "r", "ri", "m", "f", "fi", "s", "si", "l", "ta", "t")
|
||||
val keyToNumber = listOf("C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B" )
|
||||
val keyToArmature = listOf(0, -7, 2, -3, 4, -1, -6, 1, -4, 3, -2, 5 )
|
||||
fun compareNotes(note1: String, note2: String): Int {
|
||||
val found1 = REGEX_ONE_NOTE.find(note1)
|
||||
val found2 = REGEX_ONE_NOTE.find(note2)
|
||||
|
|
@ -46,6 +47,10 @@ class Transpose {
|
|||
}
|
||||
}
|
||||
}
|
||||
fun toArmature(note: String): Int {
|
||||
val index = keyToNumber.indexOf(note)
|
||||
return keyToArmature.getOrNull(index) ?: 0
|
||||
}
|
||||
fun transposeMidi(note: String, fromKey: String) : Pair<String, Int> {
|
||||
return Pair(note, 4)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue