App-Music-ChordPro
view release on metacpan or search on metacpan
lib/ChordPro/res/abc/abc2svg/MIDI-1.js view on Meta::CPAN
// build the equal temperament as a b40 float array
function tb40(qs) {
// b40 C D E F G A B
// [ 2, 8, 14, 19, 25, 31, 37 ]
var i,
// C G D A E B ^F ^C ^G ^D ^A ^E ^B^^F^^C^^G^^D^^A^^E^^B
n1 = [2,25, 8,31,14,37,20, 3,26, 9,32,15,38,21, 4,27,10,33,16,39],
// C F _B _E _A _D _G _C _F__B__E__A__D__G__C__F
n2 = [0,19,36,13,30, 7,24, 1,18,35,12,29, 6,23, 0,17],
da = 21 - 3 * qs, // 21 = 12 (octave) + 9 (A)
b = new Float32Array(40)
for (i = 0; i < n1.length; i++)
b[n1[i]] = (qs * i + da) % 12
for (i = 1; i <= n2.length; i++)
b[n2[i]] = 12 - (qs * i - da) % 12
return b
} // tb40()
// do_midi()
var n, v, s, maps,
o, q, n, qs,
a = parm.split(/\s+/),
abc = this,
cfmt = abc.cfmt(),
curvoice = abc.get_curvoice(),
parse = abc.get_parse()
if (curvoice) {
if (curvoice.ignore)
return
if (curvoice.chn == undefined)
curvoice.chn = curvoice.v < 9 ?
curvoice.v :
curvoice.v + 1
}
switch (a[1]) {
// case "bassprog": // %%MIDI bassprog <#MIDI program> [octave=<n>]
// break
// case "bassvol": // %%MIDI bassvol <volume>
// break
// case "beatstring": // %%MIDI beatstring <string of fmp>
// break
case "chordname": // %%MIDI chordname <list of MIDI pitches>
// example: %%MIDI chordname m 0 3 7
if (!cfmt.chord)
cfmt.chord = {}
if (!cfmt.chord.names)
cfmt.chord.names = {}
cfmt.chord.names[a[2]] = a.slice(3)
break
case "chordprog": // %%MIDI chordprog <#MIDI program> [octave=<n>]
if (!cfmt.chord)
cfmt.chord = {}
cfmt.chord.prog = a[2]
if (a[3] && a[3].slice(0, 7) == "octave=")
cfmt.chord.trans = Number(a[3].slice(7))
break
case "chordvol": // %%MIDI chordvol <volume>
v = Number(a[2])
if (isNaN(v) || v < 0 || v > 127) {
abc.syntax(1, abc.errs.bad_val, "%%MIDI chordvol")
break
}
if (!cfmt.chord)
cfmt.chord = {}
cfmt.chord.vol = v
break
// case "drone": // %%MIDI drone <#prog> <pit_1> <pit_2> <vol_1> <vol_2>
// // default: 70 45 33 80 80
// break
// case "droneon": // %%MIDI droneon
// break
// case "droneoff": // %%MIDI droneoff
// break
case "gchord": // %%MIDI gchord <list of letters and repeat numbers>
// // z rest
// // c chord
// // f fundamental
// // b fundamental + chord
// // G/H/I/J/K individual notes starting
// // from the lowest note of the chord
// // g/h/i/j/k an octave above these
// // defaults:
// // M:2/4 or 4/4 fzczfzcz
// // M:3/4 fzczcz
// // M:6/8 fzcfzc
// // M:9/8 fzcfzcfzc
// fall thru
case "gchordbars": // %%MIDI gchordbars n
case "gchordon": // %%MIDI gchordon
case "gchordoff": // %%MIDI gchordoff
if (!cfmt.chord)
cfmt.chord = {}
if (parse.state >= 2
&& curvoice) {
s = abc.new_block("midigch")
s.play = s.invis = 1 //true
if (a[1][6] == 'o')
s.on = a[1][7] == 'n'
else if (a[1][6] == 'b')
s.gchnb = +a[2]
else
s.rhy = a[2] // chord rhythm
} else if (a[1][6] == 'o') {
cfmt.chord.gchon = a[1][7] == 'n'
} else if (a[1][6] == 'b') {
cfmt.chord.gchnb = +a[2]
} else {
cfmt.chord.rhy = a[2]
}
break
case "channel":
v = parseInt(a[2])
if (isNaN(v) || v <= 0 || v > 16) {
abc.syntax(1, abc.errs.bad_val, "%%MIDI channel")
break
}
v-- // channel range 1..16 => 0..15
if (parse.state >= 2) {
s = abc.new_block("midiprog")
s.play = s.invis = 1 //true
s.chn = v
} else {
abc.set_v_param("channel", v)
}
break
case "drummap":
//fixme: should have a 'MIDIdrum' per voice?
v = Number(a[3])
if (isNaN(v)) {
abc.syntax(1, abc.errs.bad_val, "%%MIDI drummap")
break
}
n = ["C","^C","D","_E","E","F","^F","G","^G","A","_B","B"][v % 12]
while (v < 60) {
n += ','
v += 12
}
while (v > 72) {
n += "'"
v -= 12
}
this.do_pscom("map MIDIdrum " + a[2] + " play=" + n)
abc.set_v_param("mididrum", "MIDIdrum")
break
case "program":
a.shift()
v = []
if (a[2]) {
v[0] = +a[2] // program
v[1] = +a[1] // channel
} else {
v[0] = +a[1]
v[1] = 0
}
if (isNaN(v[0]) || v[0] < 0 || v[0] > 127
|| (v[1]
&& (isNaN(v[1]) || v[1] <= 0 || v[1] > 16))) {
abc.syntax(1, abc.errs.bad_val, "%%MIDI program")
break
}
if (parse.state >= 2) {
s = abc.new_block("midiprog");
s.play = s.invis = 1 //true
s.instr = v[0]
s.chn = v[1] > 0
? (v[1] - 1)
: curvoice.v < 9 ? curvoice.v : curvoice.v + 1
} else {
abc.set_v_param("instr", a.slice(1).join(' '))
}
break
case "control":
n = parseInt(a[2])
if (isNaN(n) || n < 0 || n > 127) {
abc.syntax(1, "Bad controller number in %%MIDI")
break
}
v = parseInt(a[3])
if (isNaN(v) || v < 0 || v > 127) {
abc.syntax(1, "Bad controller value in %%MIDI")
break
}
if (parse.state >= 2) {
s = abc.new_block("midictl");
s.play = s.invis = 1 //true
s.ctrl = n;
s.val = v
} else {
abc.set_v_param("midictl", a[2] + ' ' + a[3])
}
break
case "temperamentequal":
n = parseInt(a[2])
if (isNaN(n) || n < 5 || n > 255) {
abc.syntax(1, abc.errs.bad_val, "%%MIDI " + a[1])
return
}
// define the Turkish accidentals (53-TET)
s = abc.get_glyphs()
if (n == 53
&& !s.acc12_53) { // do not redefine the glyphs
// #1
s.acc12_53 = '<text id="acc12_53" x="-1"></text>'
// #2
s.acc24_53 = '<text id="acc24_53" x="-1">\
<tspan x="0" y="-9" style="font-size:9px">2</tspan></text>'
// #3
s.acc36_53 = '<text id="acc36_53" x="-1">\
<tspan x="0" y="-9" style="font-size:9px">3</tspan></text>'
// #4
s.acc48_53 = '<text id="acc48_53" x="-1"></text>'
// #5
s.acc60_53 = '<g id="acc60_53">\n\
<text style="font-size:1.1em" x="-1"></text>\n\
<path class="stroke" stroke-width="1.6" d="M-2 1l7 -2.2"/>\n\
</g>'
// #8
s.acc96_53 = '<g id="acc96_53">\n\
<text style="font-size:1.1em" x="-2"></text>\n\
<path class="stroke" stroke-width="1.6" d="M-2.8 1.4l8.5 -2.8"/>\n\
</g>'
// #9
s.acc108_53 = '<text id="acc108_53" x="-3"></text>'
// b9
s["acc-108_53"] = '<text id="acc-108_53" x="-3"></text>'
// b8
s["acc-96_53"] = '<g id="acc-96_53">\n\
<text x="-1"></text>\n\
<path class="stroke" stroke-width="1.3" d="M-3 -7l5 -2m0 3l-5 2"/>\n\
</g>'
// b5
s["acc-60_53"] = '<text id="acc-60_53" x="-1"></text>'
// b4
s["acc-48_53"] = '<g id="acc-48_53">\n\
<text x="-1"></text>\n\
<path class="stroke" stroke-width="1.3" d="M-3 -5.5l5 -2"/>\n\
</g>'
// b3
s["acc-36_53"] = '<g id="acc-36_53">\n\
<text x="-1">\
<tspan x="0" y="-12" style="font-size:9px">3</tspan></text>\n\
<path class="stroke" stroke-width="1.3" d="M-3 -5.5l5 -2"/>\n\
( run in 0.517 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )