Skip to content

Instantly share code, notes, and snippets.

@c3r38r170
Last active August 3, 2019 14:50
Show Gist options
  • Save c3r38r170/a919d5042db42d7eaa6ed09ea1222de2 to your computer and use it in GitHub Desktop.
Save c3r38r170/a919d5042db42d7eaa6ed09ea1222de2 to your computer and use it in GitHub Desktop.
A little script to take parts from MusicXML files and turn them into a Pascal script that plays it. Lacks: || |: symbol (start of repetition, as far as I know) and multiple notes at the same time (yeah, can only play well simple songs, like kids classics or 8-bit OSTs). Free for anyone, tested in last version of Chrome as of today.
function checkTied(r,s){
r=r.querySelector('notations');
if(r){
r=r.querySelector('tied');
if(r)
return r.getAttribute('type')==s;
}
return false;
}
let a='',i=1,d={A:[0,0,0,220,440,880,1760],B:[0,0,0,247,494,988,1975],C:[0,0,0,131,262,523,1046,2093],D:[0,0,0,147,294,587,1175,2349],E:[0,0,0,165,330,659,1318,2637],F:[0,0,0,175,349,698,1397,2793],Es:[0,0,0,175,349,698,1397,2793],G:[0,0,0,196,392,784,1568,3136],As:[0,0,0,233,466,932,1865,3729],Cs:[0,0,0,139,277,554,1109,2217],Ds:[0,0,0,156,311,622,1244,2489],Fs:[0,0,0,185,370,740,1480,2960],Gs:[0,0,0,208,415,831,1661,3322]},f=['C','D','F','G','A'],h=[],tempo=0,tempAcc=[];
for(let b of document.querySelectorAll('#P1 note')){
let j=[];
if(b.querySelector('rest'))
j[0]=0;
else{
let c=b.querySelector('pitch'),e=b.querySelector('accidental');
if(e){
let k=[c.querySelector('step').innerHTML,+c.querySelector('octave').innerHTML,e.innerHTML],l=tempAcc.findIndex(function(e){return e[0]==k[0]&&e[1]==k[1]});
j[0]=d[k[0]+(k[2]=='sharp'?'s':'')][k[1]];
if(l==-1)
tempAcc.push(k);
else
tempAcc[l]=k;
}else{
let g=c.querySelector('step').innerHTML,n=(+c.querySelector('octave').innerHTML),m=tempAcc.findIndex(function(e){return e[0]==g&&e[1]==n});
j[0]=d[(m==-1?f.includes(g):tempAcc[m][2]=='sharp')?g+'s':g][n];
}
}
let q=(+b.querySelector('duration').innerHTML);
j[1]=Math.round(q/48*260);
if(h.length&&h[h.length-1][0]==j[0]&&(!j[0]||checkTied(b,'stop')))
h[h.length-1][1]+=j[1];
else
h.push(j);
let o=0,p=b.querySelector('type');
if(p)
switch(p.innerHTML){
case '16th':
o+=.125;
break;
case 'eighth':
o+=.25;
break;
case 'quarter':
o+=.5;
break;
case 'half':
o+=1;
break;
case 'whole':
o+=2;
break;
}
else
o+=q/24;
tempo+=b.querySelector('dot')?o*1.5:o;
if(!checkTied(b,'start')&&tempo>=2){
tempo-=2;
tempAcc=[];
}
}
for(let b of h){
a+=i+':begin\n getNext[1]:='+b[0]+';\n getNext[2]:='+b[1]+';\n end;';
i++;
}
console.log('program music;\nuses crt;\n\ntype nota=array[1..2]of integer;\n\nvar player:nota;\n i,j,k:integer;\n\nprocedure playSound(a,b:integer);\nbegin\n if a=0 then\n nosound()\n else\n sound(a);\n delay(b);\nend;\n\nfunction getNext(a:integer):nota;\nbegin\n case a of\n '+
a+
'else begin\n i:=22;\n getNext:=getNext(22);\n end;end;\nend;\n\nbegin\nclrscr();\nplayer:=getNext(1);\ni:=1;\nrepeat\n playSound(player[1],player[2]*5);\n i:=i+1;\n player:=getNext(i)\nuntil keypressed();\nnosound();\nclrscr();\nend.');
/* Customization:
Line 10, variable "f": Define the key as the notes that should be sharp by default
Line 11: #PX is the id of the part to be analyzed
Line 30: That 48 has to be the <duration> of a "whole" note in that sheet, 260 is a personal practical constant for the duration of a pascal delay on my computer
Line 55: That 24 has to be the <duration> of a "half" note in that sheet.
flat.io is a very good place to take MusicXML files from.*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment