Created
October 26, 2018 15:33
-
-
Save WizardOfArc/c1c03a96b48161db90286087ec3c8671 to your computer and use it in GitHub Desktop.
This builds an HTML table for a chart to find what chords contain a given note you are looking to play.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.io.FileWriter | |
| object NumberHelper { | |
| def safeMod(num: Int): Int = { | |
| val modded = num % 12 | |
| if (modded < 0){ | |
| modded + 12 | |
| } else { | |
| modded | |
| } | |
| } | |
| } | |
| case class Note(value: Int){ | |
| def -(other: Note) = { | |
| Notes.forInt(value - other.value) | |
| } | |
| def +(other: Note) = { | |
| Notes.forInt(value + other.value) | |
| } | |
| def show = s"$value" | |
| } | |
| object Notes { | |
| val One = Note(0) | |
| val FlatTwo = Note(1) | |
| val Two = Note(2) | |
| val FlatThree = Note(3) | |
| val Three = Note(4) | |
| val Four = Note(5) | |
| val Tritone = Note(6) | |
| val Five = Note(7) | |
| val FlatSix = Note(8) | |
| val Six = Note(9) | |
| val FlatSeven = Note(10) | |
| val Seven = Note(11) | |
| val allNotes = List( | |
| One, FlatTwo, Two, FlatThree, | |
| Three, Four, Tritone, Five, | |
| FlatSix, Six, FlatSeven, Seven | |
| ) | |
| val diatonicNotes = List(One, Two, Three, Four, Five, Six, Seven) | |
| val simpleChordTones = List(One, FlatThree, Three, Five) | |
| def forInt(num: Int) = { | |
| allNotes(NumberHelper.safeMod(num)) | |
| } | |
| } | |
| case class Root ( | |
| val name: String, | |
| val value: Note | |
| ) | |
| object Roots { | |
| val One = Root("I", Notes.forInt(0)) | |
| val FlatTwo = Root("bII", Notes.forInt(1)) | |
| val Two = Root("II", Notes.forInt(2)) | |
| val FlatThree = Root("bIII", Notes.forInt(3)) | |
| val Three = Root("III", Notes.forInt(4)) | |
| val Four = Root("IV", Notes.forInt(5)) | |
| val Tritone = Root("bV", Notes.forInt(6)) | |
| val Five = Root("V", Notes.forInt(7)) | |
| val FlatSix = Root("bVI", Notes.forInt(8)) | |
| val Six = Root("VI", Notes.forInt(9)) | |
| val FlatSeven = Root("bVII", Notes.forInt(10)) | |
| val Seven = Root("VII", Notes.forInt(11)) | |
| val allRoots = List( | |
| One, FlatTwo, Two, FlatThree, | |
| Three, Four, Tritone, Five, | |
| FlatSix, Six, FlatSeven, Seven | |
| ) | |
| def forInt(num: Int): Root = allRoots(NumberHelper.safeMod(num)) | |
| def forNote(note: Note): Root = forInt(note.value) | |
| } | |
| case class Quality ( | |
| val name: String, | |
| val value: Note | |
| ) | |
| object Qualities { | |
| val All = Quality("all", Notes.forInt(0)) | |
| val FlatNine = Quality("b9", Notes.forInt(1)) | |
| val Sus2 = Quality("sus2", Notes.forInt(2)) | |
| val Minor = Quality("minor", Notes.forInt(3)) | |
| val Major = Quality("major", Notes.forInt(4)) | |
| val Sus4 = Quality("sus4", Notes.forInt(5)) | |
| val Dim = Quality("dim or #4", Notes.forInt(6)) | |
| val MajorOrMinor = Quality("major or minor", Notes.forInt(7)) | |
| val Flat6 = Quality("b6", Notes.forInt(8)) | |
| val Six = Quality("6", Notes.forInt(9)) | |
| val Dom7 = Quality("7", Notes.forInt(10)) | |
| val Major7 = Quality("major7", Notes.forInt(11)) | |
| val allQualities = List( | |
| All, FlatNine, Sus2, Minor, | |
| Major, Sus4, Dim, MajorOrMinor, | |
| Flat6, Six, Dom7, Major7 | |
| ) | |
| def forInt(num: Int) = allQualities(NumberHelper.safeMod(num)) | |
| def forNote(note: Note) = forInt(note.value) | |
| } | |
| case class Chord(root: Root, quality: Quality){ | |
| def isDiatonic: Boolean = { | |
| Notes.diatonicNotes.contains(root.value) && | |
| Notes.diatonicNotes.contains(root.value + quality.value ) | |
| } | |
| def isSimple: Boolean = { | |
| Notes.simpleChordTones.contains(quality.value) | |
| } | |
| def display: String = s"${root.name} ${quality.name}" | |
| } | |
| object HTMLHelper { | |
| def style = """ | |
| | <style> | |
| | th { | |
| | background-color: #afafaf; | |
| | } | |
| | td { | |
| | border: solid black 1px; | |
| | padding: 5px; | |
| | } | |
| | .diatonic { | |
| | font-weight: bold; | |
| | border: solid black 4px; | |
| | } | |
| | .simple { | |
| | background-color: #7faf7f; | |
| | } | |
| | </style> | |
| """.stripMargin | |
| def makePage(content: String): String = { | |
| s""" | |
| |<!DOCTYPE HTML> | |
| |<html> | |
| | <head> | |
| | $style | |
| | </head> | |
| | <body> | |
| | ${content} | |
| | </body> | |
| |</html> | |
| """.stripMargin | |
| } | |
| def makeTable(rows: Seq[String]): String = { | |
| s"""<table cellspacing="0" cellpadding="0"> | |
| | ${rows.mkString("\n")} | |
| </table> | |
| """.stripMargin | |
| } | |
| } | |
| object ChordFinderChartBuilder { | |
| def toRow(entry: (Note, Seq[(Note, Chord)])): String = { | |
| val (note,cells) = entry | |
| s"""<tr> | |
| | <th>${note.show}</th> | |
| | ${cells.map{toCell }.mkString("\n")} | |
| |</tr>""".stripMargin | |
| } | |
| def toCell(value: (Note, Chord)): String = { | |
| val (_, chord) = value | |
| val simpleOption = if(chord.isSimple){ | |
| Some("simple") | |
| } else { None } | |
| val diatonicOption = if(chord.isDiatonic){ | |
| Some("diatonic") | |
| } else { None } | |
| val classlist = List(simpleOption, diatonicOption).flatten.mkString(" ") | |
| val simple = if(classlist.nonEmpty){ | |
| s""" class="$classlist" """ | |
| } else { "" } | |
| s"""<td$simple>${chord.display}</td>""" | |
| } | |
| def baseChart = { | |
| for { | |
| a <- Notes.allNotes | |
| b <- Qualities.allQualities | |
| } yield (a, Chord(Roots.forNote(a - b.value), b)) | |
| } | |
| def main(args: Array[String]): Unit = { | |
| val grouped = baseChart.groupBy(_._1).toList.sortBy(_._1.value) | |
| val rows = grouped map toRow | |
| val contents = HTMLHelper.makePage(HTMLHelper.makeTable(rows ) ) | |
| val fw = new FileWriter("chart.html") | |
| fw.write(contents) | |
| fw.close() | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment