Dev.to · 3 min read

Representing Music with Code

Representing Music with Code

Chordal: a Scala DSL for music theory Another post about my previous DSL experiments. This time, the target was a different hobby of mine: music. Chordal is another DSL experiment in Scala to represent music elements; working with Notes to create Chords, and then using those same Chords to build Progressions. I thought "Chordal" was an original name until I found plenty of repos with the same one. Oh well. Some of the challenges I faced came from building the AST. Music theory is a huge world with a lot of inherent structure and composition rules baked in. The atomic unit could be considered the pitch, which gains meaning once paired or grouped: two or three of them become a note, then a triad. Add one more and you've got a tetrachord. Keep stacking and you're into extended chords, which open up a lot of contexts that are genuinely hard to represent cleanly. Then there's the diatonic vs. chromatic scale problem. The chromatic scale is useful for movement/transposition (going from one note to another by some number of steps), but that convenience comes with a catch: correct representation. Enter enharmonics, the fact that a note or chord can be spelled in different ways and still be "the same" pitch, but not the same note in context. Db and C# are a good example: same pitch, different note depending on what's around it. What a rant. There are probably some errors, both in theory and in code, but I can live with that for now. It was a ride. Features Working enharmonics. Extension methods to work with strings as notes. Useful rendering of notes. Harmony Chord creation Triads. Tetrachords (subject to model changes, partial support). Add chords. Power chords. Suspended chords. Partial extension support. Progressions Generic list-like implementation. Quick default methods for building common progressions. Usage DSL package org.aranadedoros.chordal import chords.* import dsl.* import dsl.Notes.{A, D, E, G} import extensions.Ninth import notes.{dim, major, note, pow, Note} import scala.language.postfixOps // work in progress, subject to change val C = Note("C") val chord1 = chord { root(C) quality(MajorTriad) withExtensions(Ninth) } println(chord1) val chord2 = chord { root("D".note) sus(Sus4) } println(chord2) val chord3 = chord { root(E) } println(chord3) val dMajor: Triad = D major println(dMajor) val eMajorWithBassOnG: SlashChord = E.major / G println(eMajorWithBassOnG) val g5: PowerChord = G pow println(g5.name) val adim7 = A.dim withSeventh MinorSeventh println(adim7) Output C9 Dsus4 E5 (D,F#,A) (E,G#,B)/G G5 (A,C,Eb,G) Overall, this project turned out really satisfying. It scratched my DSL itch for a good long while. I don't think I'll be doing another one anytime soon. https://github.com/AranaDeDoros/Chordal

This is a summary aggregated from Dev.to. Read the complete article on the original site:

Read full article at Dev.to

More Programming & Dev News