I am starting to play (pun intended) with jMusic. I am just learning the basics of music composition. jMusic is quite cool, but having the usual Java overhead makes things oh so boring! Therefore I am starting developing a DSL in Groovy to write some scores. Score is exactly the first class that was DSLed. Something of a trivial nature. Just replacing this
score = new Score("My new Score")
with:
score = score(name: "My new Score")
and the same to Note and Phrase. Furthermore I would like to avoid all the usual “import everything”.
Solution? Create a class with a static method that accepts an environment to which I add the necessary functions. So, in an external file I have class Music to do just this:
1 2 3 4 5 6 7 8 9 10 11 12 13 | class Music implements JMC { static init(env){ env.score = { Map args -> Score score = new Score(args["name"]) return score } ProgramChanges.fields.each {env."$it.name"=ProgramChanges."$it.name"} Durations.fields.each {env."$it.name"=Durations."$it.name"} Pitches.fields.each {env."$it.name"=Pitches."$it.name"} ... |
So, lines 4-7 I am creating a new property with a closure. The property accepts a map of parameters and creates a new Score object that is returned. Similar things exist with Note and Phrase.
Now look at lines 9-11. I am importing all fields of those classes into the environment namespace. “That is namespace polution”, I hear you say. Well, maybe, but it happens to be a jMusic design philosophy (you will find that in many classes of jMusic), and, at least for now it is pretty manageable. If it becomes problematic, this can always be changed. Writing CLARINET sounds better than writing ProgramChanges.CLARINET or even creating an INSTRUMENT property/class in the environment to hold all instruments. This is particularly useful with Pitches and Durations (because we tend to write A LOT of these). A simple script looks like this for now:
Music.init(this) score = score(name:"Row Your Boat") flute = part(title: "Flute", instrument: FLUTE, channel: 0) trumpet = part(title: "Trumpet", instrument: TRUMPET, channel: 1) clarinet = part(title: "Clarinet", instrument: CLARINET, channel: 2) int[] pitchArray = [C4,C4,C4,D4,E4,E4,D4,E4,F4,G4, C5,C5,C5,G4,G4,G4,E4,E4,E4, C4,C4,C4,G4,F4,E4,D4,C4] double[] rhythmArray = [ C, C,CT,QT, C,CT,QT,CT,QT, M, QT,QT,QT,QT,QT,QT,QT,QT,QT,QT, QT,QT,CT,QT,CT,QT, M] phrase1 = phrase(startTime: 0.0) phrase1.addNoteList pitchArray, rhythmArray ...
Nothing particularly fantastic, but somewhat less clutter.
This is version 0.0.0.0.0.1 pre-pre-pre-alpha. ![]()
Watch this space for newer versions (more useful).
For now this serves to show two very basic DSL techniques with Groovy: adding methods to the environment and inspecting classes to copy fields.











