App-Music-ChordPro
view release on metacpan or search on metacpan
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
n1 = t
t = d0 + a * d1
d0 = d1
d1 = t
}
return [n1, d1]
} // rat()
// compare pitches
// This function is used to sort the note pitches
abc2svg.pitcmp = function(n1, n2) { return n1.pit - n2.pit }
// start of the Abc object
abc2svg.Abc = function(user) {
"use strict";
// constants
var C = abc2svg.C;
// mask some unsafe functions
var require = empty_function,
system = empty_function,
write = empty_function,
XMLHttpRequest = empty_function,
std = null,
os = null
// -- constants --
// staff system
var OPEN_BRACE = 0x01,
CLOSE_BRACE = 0x02,
OPEN_BRACKET = 0x04,
CLOSE_BRACKET = 0x08,
OPEN_PARENTH = 0x10,
CLOSE_PARENTH = 0x20,
STOP_BAR = 0x40,
FL_VOICE = 0x80,
OPEN_BRACE2 = 0x0100,
CLOSE_BRACE2 = 0x0200,
OPEN_BRACKET2 = 0x0400,
CLOSE_BRACKET2 = 0x0800,
MASTER_VOICE = 0x1000,
IN = 96, // resolution 96 PPI
CM = 37.8, // 1 inch = 2.54 centimeter
YSTEP // number of steps for y offsets
// error texts
var errs = {
bad_char: "Bad character '$1'",
bad_grace: "Bad character in grace note sequence",
bad_transp: "Bad transpose value",
bad_val: "Bad value in $1",
bar_grace: "Cannot have a bar in grace notes",
ignored: "$1: inside tune - ignored",
misplaced: "Misplaced '$1' in %%score",
must_note: "!$1! must be on a note",
must_note_rest: "!$1! must be on a note or a rest",
nonote_vo: "No note in voice overlay",
not_ascii: "Not an ASCII character",
not_enough_n: 'Not enough notes/rests for %%repeat',
not_enough_m: 'Not enough measures for %%repeat',
not_enough_p: "Not enough parameters in %%map",
not_in_tune: "Cannot have '$1' inside a tune",
notransp: "Cannot transpose with a temperament"
}
var self = this, // needed for modules
glovar = {
meter: {
type: C.METER, // meter in tune header
wmeasure: 1, // no M:
a_meter: [] // default: none
},
},
info = {}, // information fields
parse = {
ctx: {},
prefix: '%',
state: 0,
ottava: [],
line: new scanBuf
},
tunes = [], // first time symbol and voice array per tune for playing
psvg // PostScript
// utilities
function clone(obj, lvl) {
if (!obj)
return obj
var tmp = new obj.constructor
for (var k in obj)
if (obj.hasOwnProperty(k)) {
if (lvl && typeof obj[k] == "object")
tmp[k] = clone(obj[k], lvl - 1)
else
tmp[k] = obj[k]
}
return tmp
}
function errbld(sev, txt, fn, idx) {
var i, j, l, c, h
if (user.errbld) {
switch (sev) {
case 0: sev = "warn"; break
case 1: sev = "error"; break
default: sev= "fatal"; break
}
user.errbld(sev, txt, fn, idx)
return
}
if (idx != undefined && idx >= 0) {
i = l = 0
while (1) {
j = parse.file.indexOf('\n', i)
if (j < 0 || j > idx)
break
l++;
i = j + 1
}
c = idx - i
}
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
case "partsspace":
case "staffsep":
case "subtitlespace":
case "sysstaffsep":
case "textspace":
case "titlespace":
case "topspace":
case "vocalspace":
case "wordsspace":
f = get_unit(param) // normally, unit in points - 72 DPI accepted
if (isNaN(f) || f < 0)
syntax(1, errs.bad_val, '%%' + cmd)
else
cfmt[cmd] = f
break
case "page-format":
user.page_format = get_bool(param)
break
case "print-leftmargin": // to remove
syntax(0, "$1 is deprecated - use %%printmargin instead", '%%' + cmd)
cmd = "printmargin"
// fall thru
case "printmargin":
// case "botmargin":
case "leftmargin":
// case "pageheight":
case "pagewidth":
case "rightmargin":
// case "topmargin":
f = get_unit(param) // normally unit in cm or in - 96 DPI
if (isNaN(f)) {
syntax(1, errs.bad_val, '%%' + cmd)
break
}
cfmt[cmd] = f;
img.chg = true
break
case "concert-score":
if (cfmt.sound != "play")
cfmt.sound = "concert"
break
case "writefields":
set_writefields(param)
break
case "volume":
cmd = "dynamic"
// fall thru
case "dynamic":
case "gchord":
case "gstemdir":
case "ornament":
case "stemdir":
case "vocal":
set_pos(cmd, param)
break
case "font":
get_font_scale(param)
break
case "fullsvg":
if (parse.state != 0) {
syntax(1, errs.not_in_tune, "%%fullsvg")
break
}
//fixme: should check only alpha, num and '_' characters
cfmt[cmd] = param
break
case "gracespace":
v = param.split(/\s+/)
for (i = 0; i < 3; i++)
if (isNaN(+v[i])) {
syntax(1, errs.bad_val, "%%gracespace")
break
}
if (parse.ufmt)
cfmt[cmd] = new Float32Array(3)
for (i = 0; i < 3; i++)
cfmt[cmd][i] = +v[i]
break
case "tuplets":
v = param.split(/\s+/)
f = v[3]
if (f) // if 'where'
f = posval[f] // translate the keyword
if (f)
v[3] = f
if (curvoice)
curvoice.tup = v
else
cfmt[cmd] = v
break
case "infoname":
case "partname":
set_infoname(cmd, param)
break
case "notespacingfactor":
v = param.match(/([.\d]+)[,\s]*(\d+)?/)
if (v) {
f = +v[1]
if (isNaN(f) || f < 1 || f > 2) {
f = 0
} else if (v[2]) {
f2 = +v[2]
if (isNaN(f))
f = 0
} else {
f2 = cfmt.spatab[5]
}
}
if (!f) {
syntax(1, errs.bad_val, "%%" + cmd)
break
}
cfmt[cmd] = param // (for dump)
// in the table 'spatab',
// the width of notes is indexed by log2(note_length)
cfmt.spatab = new Float32Array(10)
i = 5; // index of crotchet
do {
cfmt.spatab[i] = f2
f2 /= f
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
// pseudo-comments
if (pscom) {
pscom = false;
bol += 2 // skip %%/I:
text = file.slice(bol, eol)
a = text.match(/([^\s]+)\s*(.*)/)
if (!a || a[1][0] == '%')
continue
switch (a[1]) {
case "abcm2ps":
case "ss-pref":
parse.prefix = a[2] // may contain a '%'
continue
case "abc-include":
do_include(uncomment(a[2]))
continue
}
// beginxxx/endxxx
if (a[1].slice(0, 5) == 'begin') {
b = a[1].substr(5);
end = '\n' + line0 + line1 + "end" + b;
i = file.indexOf(end, eol)
if (i < 0) {
syntax(1, "No $1 after %%$2",
end.slice(1), a[1]);
parse.eol = eof
continue
}
self.do_begin_end(b, uncomment(a[2]),
file.slice(eol + 1, i)
.replace(/\n%[^%].*$/gm,'')
.replace(/^%%/gm,''))
parse.eol = file.indexOf('\n', i + 6)
if (parse.eol < 0)
parse.eol = eof
continue
}
switch (a[1]) {
case "show_source":
b = uncomment(a[2])
switch (b[0]) {
case '*':
i = file.indexOf('\n' + line0 + line1
+ "show_source", eol)
bol -= 2 // keep %%show_.. in the source
set_src(b, i)
user.img_out(sav.src)
// fall thru
case '0':
b = ""
// fall thru
default:
cfmt[a[1]] = b
// fall thru
}
continue
case "select":
if (parse.state != 0) {
syntax(1, errs.not_in_tune, "%%select")
continue
}
select = uncomment(a[2])
if (select[0] == '"')
select = select.slice(1, -1);
if (!select) {
delete parse.select
continue
}
select = select.replace(/\(/g, '\\(');
select = select.replace(/\)/g, '\\)');
// select = select.replace(/\|/g, '\\|');
parse.select = new RegExp(select, 'm')
continue
case "tune":
if (parse.state != 0) {
syntax(1, errs.not_in_tune, "%%tune")
continue
}
select = uncomment(a[2])
// if void %%tune, free all tune options
if (!select) {
parse.tune_opts = {}
continue
}
if (select == "end")
continue // end of previous %%tune
if (!parse.tune_opts)
parse.tune_opts = {};
parse.tune_opts[select] = opt = {
t_opts: []
// v_opts: {}
};
while (1) {
bol = eol
if (file[bol + 1] != '%')
break
eol = file.indexOf('\n', eol + 1)
if (file[bol + 2] != line1)
continue
text = file.slice(bol + 3,
eol < 0 ? undefined : eol)
a = text.match(/([^\s]+)\s*(.*)/)
switch (a[1]) {
case "tune":
break
case "voice":
do_voice(uncomment(a[2],
true), true)
continue
default:
opt.t_opts.push(
uncomment(text, true))
continue
}
break
}
if (parse.tune_v_opts) {
opt.v_opts = parse.tune_v_opts;
parse.tune_v_opts = null
}
parse.eol = bol
continue
case "voice":
if (parse.state != 0) {
syntax(1, errs.not_in_tune, "%%voice")
continue
}
select = uncomment(a[2])
/* if void %%voice, free all voice options */
if (!select) {
parse.voice_opts = null
continue
}
do_voice(select)
continue
}
self.do_pscom(uncomment(text, true))
continue
}
// music line (or free text)
if (line1 != ':' || !/[A-Za-z+]/.test(line0)) {
last_info = undefined;
if (parse.state < 2)
continue
parse.line.buffer = uncomment(file.slice(bol, eol))
if (parse.line.buffer)
parse_music_line()
continue
}
// information fields
bol += 2
while (1) {
switch (file[bol]) {
case ' ':
case '\t':
bol++
continue
}
break
}
if (line0 == '+') {
if (!last_info) {
syntax(1, "+: without previous info field")
continue
}
txt_add = ' '; // concatenate
line0 = last_info
}
text = uncomment(file.slice(bol, eol), line0)
switch (line0) {
case 'X': // start of tune
if (parse.state != 0) {
syntax(1, errs.ignored, line0)
continue
}
if (parse.select
&& !tune_selected()) { // skip to the next tune
eol = file.indexOf('\nX:', parse.eol)
if (eol < 0)
eol = eof;
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
} while (!s2.seqst)
}
if (stup)
set_sp_tup(stup, s2)
// let the chord symbols at the same offset
// and adjust the spacing due to the lyrics
if (s_chs)
set_w_chs(s_chs)
}
// insert a rest, this one replacing a sequence or a measure
function to_rest(so) {
var s = clone(so)
s.prev.next = so.ts_prev = so.prev = s.ts_prev.ts_next = s
s.next = s.ts_next = so
so.seqst = false
so.invis = so.play = true
s.type = C.REST
// just keep nl and seqst
delete s.in_tuplet
delete s.tp
delete s.a_dd
delete s.a_gch
delete s.sls
//fixme: what if chord / slur in notes / ... ?
/*fixme: should set many parameters for set_width*/
// set_width(s)
return s
}
/* -- set the repeat sequences / measures -- */
function set_repeat(s) { // first note
var s2, s3, i, j, dur,
n = s.repeat_n,
k = s.repeat_k,
st = s.st,
v = s.v
s.repeat_n = 0 // treated
/* treat the sequence repeat */
if (n < 0) { /* number of notes / measures */
n = -n;
i = n /* number of notes to repeat */
for (s3 = s.prev; s3; s3 = s3.prev) {
if (!s3.dur) {
if (s3.type == C.BAR) {
error(1, s3, "Bar in repeat sequence")
return
}
continue
}
if (--i <= 0)
break
}
if (!s3) {
error(1, s, errs.not_enough_n)
return
}
dur = s.time - s3.time;
i = k * n /* whole number of notes/rests to repeat */
for (s2 = s; s2; s2 = s2.next) {
if (!s2.dur) {
if (s2.type == C.BAR) {
error(1, s2, "Bar in repeat sequence")
return
}
continue
}
if (--i <= 0)
break
}
if (!s2
|| !s2.next) { /* should have some symbol */
error(1, s, errs.not_enough_n)
return
}
for (s2 = s.prev; s2 != s3; s2 = s2.prev) {
if (s2.type == C.NOTE) {
s2.beam_end = true
break
}
}
for (j = k; --j >= 0; ) {
i = n /* number of notes/rests */
if (s.dur)
i--;
s2 = s.ts_next
while (i > 0) {
if (s2.st == st) {
s2.invis = s2.play = true
if (s2.seqst && s2.ts_next.seqst)
s2.seqst = false
if (s2.v == v
&& s2.dur)
i--
}
s2 = s2.ts_next
}
s = to_rest(s)
s.dur = s.notes[0].dur = dur;
s.rep_nb = -1; // single repeat
s.beam_st = true;
self.set_width(s)
s.head = C.SQUARE;
for (s = s2; s; s = s.ts_next) {
if (s.st == st
&& s.v == v
&& s.dur)
break
}
}
return
}
/* check the measure repeat */
i = n /* number of measures to repeat */
for (s2 = s.prev.prev ; s2; s2 = s2.prev) {
if (s2.type == C.BAR
|| s2.time == tsfirst.time) {
if (--i <= 0)
break
}
}
if (!s2) {
error(1, s, errs.not_enough_m)
return
}
dur = s.time - s2.time /* repeat duration */
if (n == 1)
i = k /* repeat number */
else
i = n /* check only 2 measures */
for (s2 = s; s2; s2 = s2.next) {
if (s2.type == C.BAR) {
if (--i <= 0)
break
}
}
if (!s2) {
error(1, s, errs.not_enough_m)
return
}
/* if many 'repeat 2 measures'
* insert a new %%repeat after the next bar */
i = k /* repeat number */
if (n == 2 && i > 1) {
s2 = s2.next
if (!s2) {
error(1, s, errs.not_enough_m)
return
}
s2.repeat_n = n;
s2.repeat_k = --i
}
/* replace */
dur /= n
if (n == 2) { /* repeat 2 measures (once) */
s3 = s
for (s2 = s.ts_next; ; s2 = s2.ts_next) {
if (s2.st != st)
continue
if (s2.type == C.BAR) {
if (s2.v == v)
break
continue
}
s2.invis = s2.play = true
if (s2.seqst && s2.ts_next.seqst)
s2.seqst = false
}
s3 = to_rest(s3)
s3.dur = s3.notes[0].dur = dur;
s3.invis = true
s2.bar_mrep = 2
s3 = s2.next;
for (s2 = s3.ts_next; ; s2 = s2.ts_next) {
if (s2.st != st)
continue
if (s2.type == C.BAR) {
if (s2.v == v)
break
continue
}
if (!s2.dur)
continue
s2.invis = s2.play = true
if (s2.seqst && s2.ts_next.seqst)
s2.seqst = false
}
s3 = to_rest(s3)
s3.dur = s3.notes[0].dur = dur;
s3.invis = true;
self.set_width(s3)
return
}
/* repeat 1 measure */
s3 = s
for (j = k; --j >= 0; ) {
for (s2 = s3.ts_next; ; s2 = s2.ts_next) {
if (s2.st != st)
continue
if (s2.type == C.BAR) {
if (s2.v == v)
break
continue
}
if (!s2.dur)
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
n += d
break
}
nt.acc = [n, d]
return an
} // nt_trans()
// set the linebreak character
function set_linebreak(param) {
var i, item
for (i = 0; i < 128; i++) {
if (char_tb[i] == "\n")
char_tb[i] = nil // remove old definition
}
param = param.split(/\s+/)
for (i = 0; i < param.length; i++) {
item = param[i]
switch (item) {
case '!':
case '$':
case '*':
case ';':
case '?':
case '@':
break
case "<none>":
continue
case "<EOL>":
item = '\n'
break
default:
syntax(1, "Bad value '$1' in %%linebreak - ignored",
item)
continue
}
char_tb[item.charCodeAt(0)] = '\n'
}
}
// set a new user character (U: or %%user)
function set_user(parm) {
var k, c, v,
a = parm.match(/(.)[=\s]*(\[I:.+\]|".+"|!.+!)$/)
if (!a) {
syntax(1, 'Lack of starting [, ! or " in U: / %%user')
return
}
c = a[1];
v = a[2]
if (c[0] == '\\') {
if (c[1] == 't')
c = '\t'
else if (!c[1])
c = ' '
}
k = c.charCodeAt(0)
if (k >= 128) {
syntax(1, errs.not_ascii)
return
}
switch (char_tb[k][0]) {
case '0': // nil
case 'd':
case 'i':
case ' ':
break
case '"':
case '!':
case '[':
if (char_tb[k].length > 1)
break
// fall thru
default:
syntax(1, "Bad user character '$1'", c)
return
}
switch (v) {
case "!beambreak!":
v = " "
break
case "!ignore!":
v = "i"
break
case "!nil!":
case "!none!":
v = "d"
break
}
char_tb[k] = v
}
// get a stafflines value
function get_st_lines(param) {
if (!param)
return
if (/^[\]\[|.':-]+$/.test(param)) // '
return param.replace(/\]/g, '[')
var n = +param
switch (n) {
case 0: return "..."
case 1: return "..|"
case 2: return ".||"
case 3: return ".|||"
}
if (isNaN(n) || n < 0 || n > 16)
return //undefined
return "||||||||||||||||".slice(0, n)
}
// create a block symbol in the tune body
function new_block(subtype) {
var s = {
type: C.BLOCK,
subtype: subtype,
dur: 0
}
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
else
s.width = 10
if (tie_s) {
curvoice.tie_s = tie_s
tie_s = null
}
break
case 'x':
s.invis = true
case 'z':
s.type = C.REST;
line.index++;
nd = parse_dur(line);
s.dur_orig = ((curvoice.ulen < 0) ?
C.BLEN :
curvoice.ulen) * nd[0] / nd[1];
if (s.dur_orig < 12) {
error(0, s, "Bad note duration $1", s.dur_orig)
s.dur_orig = 12
}
s.dur = s.dur_orig * curvoice.dur_fact;
if (s.dur == curvoice.wmeasure)
s.fmr = 1 // full measure rest
s.notes = [{
pit: 18,
dur: s.dur_orig
}]
break
case '[': // chord
in_chord = true;
c = line.next_char()
i = line.buffer.indexOf(']', line.index)
if (i < 0) {
syntax(1, "No end of chord")
return
}
n = line.index // save the parser index
line.index = i + 1 // set the parser to the end of chord
nd = parse_dur(line)
chdur = nd[0] / nd[1] // length factor of the chord
in_chord = reg_dur.lastIndex // hack: index after the chord length
line.index = n // restore the parser index
// fall thru
default: // accidental, chord, note
if (curvoice.acc_tie) {
acc_tie = curvoice.acc_tie
curvoice.acc_tie = null
}
s.notes = []
// loop on the chord
while (1) {
// when in chord, get the slurs and decorations
if (in_chord) {
while (1) {
if (!c)
break
i = c.charCodeAt(0);
if (i >= 128) {
syntax(1, errs.not_ascii)
return //null
}
ty = char_tb[i]
switch (ty[0]) {
case '(':
sl1.push(parse_vpos());
c = line.char()
continue
case '!':
if (ty.length > 1)
a_dcn.push(ty.slice(1, -1))
else
get_deco() // line -> a_dcn
c = line.next_char()
continue
}
break
}
}
note = parse_basic_note(line,
s.grace ? C.BLEN / 4 :
curvoice.ulen < 0 ?
C.BLEN :
curvoice.ulen)
if (!note)
return //null
note.dur *= chdur // chord factor
if (note.dur < 12) {
error(0, s, "Bad note duration $1", note.dur)
note.dur = 12
}
if (curvoice.octave)
note.pit += curvoice.octave * 7
// get the real accidental
apit = note.pit + 19 // pitch from C-1
i = note.acc
if (!i) {
if (cfmt["propagate-accidentals"][0] == 'p')
i = curvoice.acc[apit % 7]
else
i = curvoice.acc[apit]
if (!i)
i = curvoice.ckey.k_map[apit % 7] || 0
}
if (i
&& !curvoice.ckey.k_drum) {
if (cfmt["propagate-accidentals"][0] == 'p')
curvoice.acc[apit % 7] = i
else if (cfmt["propagate-accidentals"][0] != 'n')
curvoice.acc[apit] = i
}
if (acc_tie && acc_tie[apit])
i = acc_tie[apit] // tied note
// set the MIDI pitch
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
}
}
curvoice.time = ti
s = curvoice.last_sym
parse.line = line = new scanBuf
parse.istart += line_sav.index
line.buffer = expand(m, b)
parse_seq(true)
if (curvoice.time != te)
syntax(1, "Bad length of the macro sequence")
if (!s)
s = curvoice.sym
for ( ; s; s = s.next)
s.invis = s.play = true
curvoice = curv
} else {
line.buffer = expand(m, b)
parse_seq(true)
}
parse.line = line = line_sav
parse.istart = istart_sav
} // parse_mac()
// parse a music sequence
function parse_seq(in_mac) {
var c, idx, type, k, s, dcn, i, n, text, note
while (1) {
c = line.char()
if (!c)
break
// check if start of a macro
if (!in_mac && maci[c]) {
n = undefined
for (k in mac) {
if (!mac.hasOwnProperty(k)
|| k[0] != c)
continue
if (k.indexOf('n') < 0) {
if (line.buffer.indexOf(k, line.index)
!= line.index)
continue
line.index += k.length
} else {
n = check_mac(k)
if (n == undefined)
continue
}
parse_mac(k, mac[k], n)
n = 1
break
}
if (n)
continue
}
idx = c.charCodeAt(0)
if (idx >= 128) {
syntax(1, errs.not_ascii)
line.index++
break
}
type = char_tb[idx]
switch (type[0]) {
case ' ': // beam break
s = curvoice.last_note
if (s) {
s.beam_end = true
if (grace)
grace.gr_shift = true
}
break
case '\n': // line break
if (cfmt.barsperstaff)
break
curvoice.eoln = true
break
case '&': // voice overlay
if (grace) {
syntax(1, errs.bad_grace)
break
}
c = line.next_char()
if (c == ')') {
get_vover(c) // full overlay stop
break
}
get_vover('&')
continue
case '(': // slur start - tuplet - vover
c = line.next_char()
if (c > '0' && c <= '9') { // tuplet
if (grace) {
syntax(1, errs.bad_grace)
break
}
var pplet = line.get_int(),
qplet = qplet_tb[pplet],
rplet = pplet
c = line.char()
if (c == ':') {
c = line.next_char()
if (c > '0' && c <= '9') {
qplet = line.get_int();
c = line.char()
}
if (c == ':') {
c = line.next_char()
if (c > '0' && c <= '9') {
rplet = line.get_int();
c = line.char()
} else {
syntax(1, "Invalid 'r' in tuplet")
continue
}
}
}
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
if (txt[0] == '1') {
if (!cfmt.contbarnb)
rep_tim = tim - bar_tim
if (!nu)
s.bar_num = n
} else {
if (!cfmt.contbarnb)
bar_tim = tim - rep_tim
n = bar_num + (tim - bar_tim) / wmeasure
if (n == (n | 0))
s.bar_num = n
}
} else if (n == (n | 0)) {
s.bar_num = n
}
if (!k)
ptim = tim
break
}
}
}
// convert a note to ABC
function not2abc(pit, acc) {
var i,
nn = ''
if (acc) {
if (typeof acc != "object") {
nn = ['__', '_', '', '^', '^^', '='][acc + 2]
} else {
i = acc[0]
if (i > 0) {
nn += '^'
} else {
nn += '_'
i = -i
}
nn += i + '/' + acc[1]
}
}
nn += ntb[(pit + 75) % 7]
for (i = pit; i >= 23; i -= 7)
nn += "'"
for (i = pit; i < 16; i += 7)
nn += ","
return nn
} // not2abc()
// note mapping
// %%map map_name note [print [note_head]] [param]*
function get_map(text) {
if (!text)
return
var i, note, notes, map, tmp, ns,
ty = '',
a = text.split(/\s+/)
if (a.length < 3) {
syntax(1, errs.not_enough_p)
return
}
ns = a[1]
if (ns != '*') {
if (ns.indexOf("octave,") == 0 // remove the octave part
|| ns.indexOf("key,") == 0
|| !ns.indexOf("tonic,")) {
ty = ns[0]
ns = ns.split(',')[1].toUpperCase()
}
tmp = new scanBuf
tmp.buffer = ns
note = parse_acc_pit(tmp)
if (!note) {
syntax(1, "Bad note in %%map")
return
}
ns = ty + not2abc(note.pit, note.acc)
}
notes = maps[a[0]]
if (!notes)
maps[a[0]] = notes = {}
map = notes[ns]
if (!map)
notes[ns] = map = []
// try the optional 'print' and 'heads' parameters
a.shift()
a.shift()
if (!a.length)
return
a = info_split(a.join(' '))
i = 0
if (a[0].indexOf('=') < 0) {
if (a[0][0] != '*') {
tmp = new scanBuf; // print
tmp.buffer = a[0];
map[1] = parse_acc_pit(tmp)
}
if (!a[1])
return
i++
if (a[1].indexOf('=') < 0) {
map[0] = a[1].split(',') // heads
i++
}
}
for (; i < a.length; i++) {
switch (a[i]) {
case "heads=":
if (!a[++i]) {
syntax(1, errs.not_enough_p)
break
}
map[0] = a[i].split(',')
break
case "print=":
case "play=":
case "print_notrp=":
if (!a[++i]) {
syntax(1, errs.not_enough_p)
break
}
tmp = new scanBuf;
tmp.buffer = a[i];
note = parse_acc_pit(tmp)
if (a[i - 1][5] == '_') // if print no transpose
note.notrp = 1 //true
if (a[i - 1][1] == 'r')
map[1] = note
else
map[3] = note
break
case "color=":
if (!a[++i]) {
syntax(1, errs.not_enough_p)
break
}
map[2] = a[i]
break
}
}
}
// get a abcm2ps/abcMIDI compatible transposition value as a base-40 interval
// The value may be
// - [+|-]<number of semitones>[s|f]
// - <note1>[<note2>] % <note2> default is 'c'
function get_transp(param) {
if (param[0] == '0')
return 0
if ("123456789-+".indexOf(param[0]) >= 0) { // by semi-tone
var val = parseInt(param)
if (isNaN(val) || val < -36 || val > 36) {
//fixme: no source reference...
syntax(1, errs.bad_transp)
return
}
val += 36
val = ((val / 12 | 0) - 3) * 40 + abc2svg.isb40[val % 12]
if (param.slice(-1) == 'b')
val += 4
return val
}
// return undefined
} // get_transp()
/* -- process a pseudo-comment (%% or I:) -- */
// (possible hook)
Abc.prototype.do_pscom = function(text) {
var h1, val, s, cmd, param, n, k, b
cmd = text.match(/[^\s]+/)
if (!cmd)
return
cmd = cmd[0];
// ignore the command if the voice is ignored,
// but not if %%score/%%staves!
if (curvoice && curvoice.ignore) {
switch (cmd) {
case "staves":
case "score":
break
default:
return
}
}
param = text.replace(cmd, '').trim()
if (param.slice(-5) == ' lock') {
fmt_lock[cmd] = true;
param = param.slice(0, -5).trim()
} else if (fmt_lock[cmd]) {
return
( run in 1.510 second using v1.01-cache-2.11-cpan-9581c071862 )