Skip to content

Commit

Permalink
Migrate data in XML to JSON for easier parsing
Browse files Browse the repository at this point in the history
I took the fret-heights.json file and divided it into separate
instrument files, re-encoded into JSON. Also, I did the same thing for
instrument_mapping.xml.
  • Loading branch information
wyskoj committed Jan 30, 2022
1 parent 7ae5a5b commit c935e26
Show file tree
Hide file tree
Showing 22 changed files with 2,634 additions and 2,038 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,86 +16,34 @@
*/
package org.wysko.midis2jam2.instrument.algorithmic

import org.w3c.dom.Element
import org.wysko.midis2jam2.Midis2jam2
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import org.wysko.midis2jam2.instrument.Instrument
import org.wysko.midis2jam2.instrument.algorithmic.HandPositionFingeringManager.Hands
import org.wysko.midis2jam2.util.Utils.exceptionToLines
import org.wysko.midis2jam2.util.Utils.instantiateXmlParser
import org.xml.sax.SAXException
import java.io.IOException
import javax.xml.parsers.ParserConfigurationException
import org.wysko.midis2jam2.util.Utils

/** Handles fingering that uses hands. */
@Serializable
open class HandPositionFingeringManager : FingeringManager<Hands> {

/** The table of fingerings. */
private val table = HashMap<Int, Hands>()

override fun fingering(midiNote: Int): Hands? {
return table[midiNote]
}
override fun fingering(midiNote: Int): Hands? = table[midiNote]

/** A pair of indices. */
@Serializable
data class Hands(
/** Left hand index. */
/** Left-hand index. */
val left: Int,

/** Right hand index. */
val right: Int
/** Right-hand index. */
val right: Int,
)

companion object {
/**
* Loads the fingering manager from XML given the class
*
* @param clazz the class of the instrument
* @return the hand position fingering manager
*/
@JvmStatic
fun from(clazz: Class<out Instrument>): HandPositionFingeringManager {
val className = clazz.simpleName
val manager = HandPositionFingeringManager()
/* XML Parsing */
try {
val xmlDoc = instantiateXmlParser("/instrument_mapping.xml")
val instrumentList = xmlDoc.documentElement.getElementsByTagName("instrument")

/* For each instrument */
for (i in 0 until instrumentList.length) {
val instrument = instrumentList.item(i)
val instrumentAttributes = instrument.attributes
/* Find instrument with matching name */
if (instrumentAttributes.getNamedItem("name").textContent == className) {
val mappingType = instrumentAttributes.getNamedItem("mapping-type").textContent
if ("hands" != mappingType) {
Midis2jam2.LOGGER.severe { "XML has a mapping type of $mappingType." }
return manager
}

/* Get key mapping */
val mapping = (instrument as Element).getElementsByTagName("mapping").item(0)
val maps = (mapping as Element).getElementsByTagName("map")
val mapSize = maps.length
/* For each defined note */
for (j in 0 until mapSize) {
val attributes = maps.item(j).attributes
val note = attributes.getNamedItem("note").textContent.toInt()
val leftHand = attributes.getNamedItem("lh").textContent.toInt()
val rightHand = attributes.getNamedItem("rh").textContent.toInt()
manager.table[note] = Hands(leftHand, rightHand)
}
break
}
}
} catch (e: SAXException) {
Midis2jam2.LOGGER.severe(exceptionToLines(e))
} catch (e: IOException) {
Midis2jam2.LOGGER.severe(exceptionToLines(e))
} catch (e: ParserConfigurationException) {
Midis2jam2.LOGGER.severe(exceptionToLines(e))
}
return manager
}
/** Loads the hand position manager from a file based on the class name. */
fun from(`class`: Class<out Instrument>): HandPositionFingeringManager =
Json.decodeFromString(Utils.resourceToString("/instrument/${`class`.simpleName}.json"))
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,78 +16,27 @@
*/
package org.wysko.midis2jam2.instrument.algorithmic

import org.w3c.dom.Element
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import org.wysko.midis2jam2.instrument.Instrument
import org.wysko.midis2jam2.util.Utils.instantiateXmlParser
import org.xml.sax.SAXException
import java.io.IOException
import javax.xml.parsers.ParserConfigurationException
import org.wysko.midis2jam2.util.Utils.resourceToString

/**
* Handles fingering for instruments that play by defining which arrangement of keys are pressed (e.g., saxophone,
* trumpet, tuba)
*/
@Serializable
class PressedKeysFingeringManager private constructor() : FingeringManager<Array<Int>> {

/** Stores the fingering table. */
private val fingerTable = HashMap<Int, Array<Int>>()

override fun fingering(midiNote: Int): Array<Int>? {
return fingerTable[midiNote]
}
override fun fingering(midiNote: Int): Array<Int>? = fingerTable[midiNote]

companion object {
/**
* Instantiates a new pressed keys fingering manager.
*
* @param clazz the class who correlates the instrument in the XML file
*/
fun from(clazz: Class<out Instrument>): PressedKeysFingeringManager {
val className = clazz.simpleName
val manager = PressedKeysFingeringManager()
/* XML Parsing */
try {
val xmlDoc = instantiateXmlParser("/instrument_mapping.xml")
val instrumentList = xmlDoc.documentElement.getElementsByTagName("instrument")

/* For each instrument */
for (i in 0 until instrumentList.length) {
val instrument = instrumentList.item(i)
val instrumentAttributes = instrument.attributes
/* Find instrument with matching name */
if (instrumentAttributes.getNamedItem("name").textContent == className) {
val mappingType = instrumentAttributes.getNamedItem("mapping-type").textContent
if (mappingType != "pressed_keys") throw InvalidMappingType(
"XML has a mapping type of $mappingType."
)

/* Get key mapping */
val mapping = (instrument as Element).getElementsByTagName("mapping").item(0)
val maps = (mapping as Element).getElementsByTagName("map")
val mapSize = maps.length

/* For each defined note */
for (j in 0 until mapSize) {
val note = maps.item(j)
val keys = (note as Element).getElementsByTagName("key")
val keyInts = Array(keys.length) {
keys.item(it).textContent.toInt()
}
manager.fingerTable[note.getAttribute("note").toInt()] = keyInts
}
break
}
}
} catch (e: SAXException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: ParserConfigurationException) {
e.printStackTrace()
} catch (e: InvalidMappingType) {
e.printStackTrace()
}
return manager
}
/** Loads the fingering manager from a file based on the class name. */
fun from(`class`: Class<out Instrument>): PressedKeysFingeringManager =
Json.decodeFromString(resourceToString("/instrument/${`class`.simpleName}.json"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,79 +16,27 @@
*/
package org.wysko.midis2jam2.instrument.algorithmic

import org.w3c.dom.Element
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import org.wysko.midis2jam2.instrument.Instrument
import org.wysko.midis2jam2.instrument.family.brass.Trombone
import org.wysko.midis2jam2.util.Utils.instantiateXmlParser
import org.xml.sax.SAXException
import java.io.IOException
import javax.xml.parsers.ParserConfigurationException
import org.wysko.midis2jam2.util.Utils

/**
* Manages and defines the position of the [Trombone] slide for each note.
*/
@Serializable
class SlidePositionManager private constructor() : FingeringManager<List<Int>> {

/** Stores the slide table. */
private val slideTable = HashMap<Int, List<Int>>()

override fun fingering(midiNote: Int): List<Int>? {
return slideTable[midiNote]
}
override fun fingering(midiNote: Int): List<Int>? = slideTable[midiNote]

companion object {
/**
* Instantiates a new slide position manager.
*
* @param clazz the class who correlates the instrument in the XML file
*/
fun from(clazz: Class<out Instrument>): SlidePositionManager {
val className = clazz.simpleName
val manager = SlidePositionManager()

/* XML Parsing */
try {
val instrumentList = instantiateXmlParser("/instrument_mapping.xml")
.documentElement.getElementsByTagName("instrument")

/* For each instrument */
for (i in 0 until instrumentList.length) {
val instrument = instrumentList.item(i)
val instrumentAttributes = instrument.attributes

/* Find instrument with matching name */
if (instrumentAttributes.getNamedItem("name").textContent == className) {

/* Ensure the mapping type is correct */
val mappingType = instrumentAttributes.getNamedItem("mapping-type").textContent
if (mappingType != "slide_position")
throw InvalidMappingType("XML has a mapping type of $mappingType.")

/* Get key mapping */
val mapping = (instrument as Element).getElementsByTagName("mapping").item(0)
val maps = (mapping as Element).getElementsByTagName("map")

for (j in 0 until maps.length) {
val note = maps.item(j)
val noteValue = note.attributes.getNamedItem("note").textContent.toInt()
val validPositions = (note as Element).getElementsByTagName("pos")
val validPosList: MutableList<Int> = ArrayList()
(0 until validPositions.length).mapTo(validPosList) { validPositions.item(it).textContent.toInt() }
manager.slideTable[noteValue] = validPosList
}
break
}
}
} catch (e: SAXException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: ParserConfigurationException) {
e.printStackTrace()
} catch (e: InvalidMappingType) {
e.printStackTrace()
}
return manager
}
/** Loads the slide position manager from a file based on the class name. */
fun from(`class`: Class<out Instrument>): SlidePositionManager =
Json.decodeFromString(Utils.resourceToString("/instrument/${`class`.simpleName}.json"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import org.wysko.midis2jam2.util.Utils.resourceToString

/** Calculates fret heights using a lookup table. */
class FretHeightByTable private constructor(
private val instrument: Instrument
private val instrument: Instrument,
) : FretHeightCalculator {

@Contract(pure = true)
Expand All @@ -37,15 +37,13 @@ class FretHeightByTable private constructor(
* Retrieves the fret height table by the name of the instrument.
*/
fun fromJson(name: String): FretHeightByTable =
FretHeightByTable(
Json.decodeFromString<List<Instrument>>(resourceToString("/fret-heights.json"))
.first { it.name == name })
FretHeightByTable(Json.decodeFromString(resourceToString("/instrument/$name.json")))
}
}

/* For parsing JSON file */
@Serializable
private data class Instrument(val name: String, val frets: List<Fret>)
private data class Instrument(val frets: List<Fret>)

@Serializable
private data class Fret(val fret: Int, val scale: Double)

0 comments on commit c935e26

Please sign in to comment.