//mmlparser.ck //a simple, hacked, library for ChucK for parsing mml into sound. //paste this into the top of any file that will contain mml. //you can write your code after the ending boundary of this file. //begin parser public class mmlparser { mmlstruct@ inputs[0]; fun void input(mmlstruct@ inp) { inputs << inp; <<< "struct added. ",inputs.cap()>>>; } int played; fun void play() { <<<"playing ",inputs.cap()," channels. Go!">>>; inputs.cap()=>played; for(0=>int p; p0) {1::samp=>now;} <<<"done!">>>; } fun void play_channel(int index) { <<< "playing channel ",index>>>; inputs[index]@=>mmlstruct inp; 4=>float deflength; 4=>int oct; 8=>float quant; 120=>float tempo; 100=>int vol; string commands[0]; StringTokenizer cmdparser; cmdparser.set(inp.code()); while(cmdparser.more()) { commands<int i; istring fcmd; fcmd.substring(0,1)=>string cmd; if(cmd=="l") { fcmd.erase(0,1); fcmd=>Std.atoi=>deflength; } if(cmd=="o") { fcmd.erase(0,1); fcmd=>Std.atoi=>oct; } if(cmd=="<") {oct--;} if(cmd==">") {oct++;} if(cmd=="v") { fcmd.erase(0,1); fcmd=>Std.atoi=>vol; } if(cmd=="q") { fcmd.erase(0,1); fcmd=>Std.atoi=>quant; } if(cmd=="t") { fcmd.erase(0,1); fcmd=>Std.atoi=>tempo; } if(cmd=="c"||cmd=="d"||cmd=="e"||cmd=="f"||cmd=="g"||cmd=="a"||cmd=="b"||cmd=="r") { int accident; fcmd=>string nl; if(nl.charAt(1)=='+') 1=>accident; if(nl.charAt(1)=='-') -1=>accident; if(accident!=0) nl.erase(1,1); nl.erase(0,1); 0=>int dots; if(nl.find('.')>=0) { nl.find('.')=>int dotpos; for(dotpos=>int j; jint j; jnl;} 4.0/Std.atof(nl)=>float beats; if(dots>0) { for(1=>int d; d<=dots; d++) { beats*1.5=>beats; } } 60000/tempo*beats=>float length; dur notetime,qtime; if(Math.isinf(length)) { <<<"error! Infinity!">>>; me.exit(); } length::ms=>dur fulltime; if(quant==8) { fulltime=>notetime; 0::samp=>qtime; } else if(quant>0&&quant<8) { fulltime/8=>dur iquant; iquant*quant=>notetime; fulltime-notetime=>qtime; } float volume; int note; if(cmd!="r") { "c+d+ef+g+a+b"=>string notes; cmd=>string n; n.lower(); notes.find(n)=>int index; oct=>int octave; if(notes.substring(index,1).upper()==cmd) octave++; 12+12*octave+index+accident=>note; vol/100.0=>volume; } else { 0=>note; 0=>volume; } inp.play(Std.mtof(note),notetime,qtime,volume); } } played--; inp.play(0,0::ms,0::ms,0); } } class mmlstruct { fun string code() { return "please define!"; } fun void play(float freq, dur nlength, dur qlength, float vol) { //do something here, this is meant to be extended anyway. } } //end of mml parsing code SinOsc s1=>dac.left; SinOsc s2=>dac.right; class mml2 extends mmlstruct { fun string code() { return "o4 l8 c8 g8 e8 g8 c8 g8 e8 g8 d8 g8 f8 g8 c8 g8 e8 g8"; } fun void play(float freq, dur nlength, dur qlength, float vol) { vol=>s1.gain; freq=>s1.freq; nlength=>now; qlength=>now; } } class mml1 extends mmlstruct { fun string code() { return "o5 l8 c2 e4 g4 < b4. > c16 d16 c2"; } fun void play(float freq, dur nlength, dur qlength, float vol) { vol=>s2.gain; freq=>s2.freq; nlength=>now; qlength=>now; } } Machine.add("rec.ck:mmltest")=>int rec; 0.5=>dac.gain; mml1 m1; mml2 m2; mmlparser p; p.input(m1); p.input(m2); p.play(); Machine.remove(rec);