view release on metacpan or search on metacpan
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
n0 = n1
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
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
last_acc = a_acc[0].acc,
last_shift = 100,
s2 = {
st: st,
nhd: 0,
notes: [{}]
}
for (i = 0; i < a_acc.length; i++) {
acc = a_acc[i];
shift = (s.k_y_clef // clef shift
+ acc.pit - 18) * 3
while (shift < -3) // let the accidentals inside the staff
shift += 21
while (shift > 27)
shift -= 21
if (i != 0
&& (shift > last_shift + 18
|| shift < last_shift - 18))
x -= 5.5 // no clash
else if (acc.acc != last_acc)
x += 3;
last_acc = acc.acc;
s2.x = x
s2.notes[0].pit = shift / 3 + 18;
// is this useful?
// s2.head = C.FULL
// s2.notes[0].shhd = 0
// self.draw_hl(s2)
last_shift = shift;
draw_acc(x, staffb + shift, acc.acc)
x += 5.5
}
}
}
// output the measure repeat number
function nrep_out(x, y, n) {
y -= 3
if (n < 10) {
xygl(x - 4, y, "mtr" + n)
} else {
xygl(x - 10, y, "mtr" + ((n / 10) | 0))
xygl(x - 2, y, "mtr" + (n % 10))
}
} // nrep_out()
// if rest alone in the measure or measure repeat,
// change the head and center
function center_rest(s) {
var s2, x
if (s.dur < C.BLEN * 2)
s.nflags = -2 // semibreve / whole
else if (s.dur < C.BLEN * 4)
s.nflags = -3
else
s.nflags = -4
s.dots = 0
/* don't use next/prev: there is no bar in voice overlay */
s2 = s.ts_next
while (s2.time != s.time + s.dur
&& s2.ts_next)
s2 = s2.ts_next
x = s2.x - s2.wl
s2 = s
while (!s2.seqst)
s2 = s2.ts_prev
s2 = s2.ts_prev
x = (x + s2.x + s2.wr) / 2
/* center the associated decorations */
if (s.a_dd)
deco_update(s, x - s.x)
s.x = x
} // center_rest()
/* -- draw a rest -- */
/* (the staves are defined) */
var rest_tb = [
"r128", "r64", "r32", "r16", "r8",
"r4",
"r2", "r1", "r0", "r00"]
function draw_rest(s) {
var s2, i, j, y, bx,
p_staff = staff_tb[s.st],
yb = p_staff.y, // bottom of staff
x = s.x
if (s.notes[0].shhd)
x += s.notes[0].shhd * stv_g.scale
if (s.rep_nb) {
set_sscale(s.st);
anno_start(s);
if (p_staff.stafflines == '|||||')
yb += 12
else
yb += (p_staff.topbar + p_staff.botbar) / 2
if (s.rep_nb < 0) {
xygl(x, yb, "srep")
} else {
xygl(x, yb, "mrep")
if (s.rep_nb > 2 && s.v == cur_sy.top_voice
&& s.fmt.measrepnb > 0
&& !(s.rep_nb % s.fmt.measrepnb))
nrep_out(x, yb + p_staff.topbar, s.rep_nb)
}
anno_a.push(s)
return
}
set_scale(s);
anno_start(s);
if (s.notes[0].color)
set_color(s.notes[0].color);
y = s.y;
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
break
}
}
}
}
}
/* if number only, draw it */
if (nb_only) {
if (tp.f[2] == 1) /* if 'which' == none */
return
set_font("tuplet")
xm = (s2.x + s1.x) / 2
if (dir == C.SL_ABOVE) // 8 = width around the middle
ym = y_get(stu, 1, xm - 4, 8)
else
ym = y_get(std, 0, xm - 4, 8) -
gene.curfont.size
if (s1.stem * s2.stem > 0) {
if (s1.stem > 0)
xm += 4
else
xm -= 4
}
yy = ym + gene.curfont.size * .22
if (tp.f[2] == 0) // if 'which' == number
xy_str(xm, yy, tp.p.toString(), 'c')
else
xy_str(xm, yy, tp.p + ':' + tp.q, 'c')
for (s3 = s1; ; s3 = s3.next) {
if (s3.x >= xm)
break
}
if (dir == C.SL_ABOVE) {
ym += gene.curfont.size
if (s3.ymx < ym)
s3.ymx = ym;
y_set(stu, 1, xm - 3, 6, ym)
} else {
if (s3.ymn > ym)
s3.ymn = ym;
y_set(std, 0, xm - 3, 6, ym)
}
return
}
// here, 'what' is square bracket
/*fixme: two staves not treated*/
/*fixme: to optimize*/
// first, get the x offsets
x1 = s1.x - 4
// end the bracket according to the last note duration
if (s2.dur > s2.prev.dur) {
s3 = s2.next
if (!s3 // maybe a note in an overlay voice
|| s3.time != s2.time + s2.dur) {
for (s3 = s2.ts_next; s3; s3 = s3.ts_next) {
if (s3.seqst
&& s3.time >= s2.time + s2.dur)
break
}
}
//fixme: s3 cannot be null (bar at end of staff)
x2 = s3 ? s3.x - s3.wl - 5 : realwidth - 6
} else {
x2 = s2.x + 4
r = s2.stem >= 0 ? 0 : s2.nhd
if (s2.notes[r].shhd > 0)
x2 += s2.notes[r].shhd
if (s2.st == stu
&& s2.stem > 0)
x2 += 3.5
}
// above
if (dir == C.SL_ABOVE) {
if (s1.st >= s2.st) {
if (s1.stem > 0)
x1 += 3
ym = y_get(s1.st, 1, x1 - 4, 8)
y1 = ym > staff_tb[s1.st].topbar + 2
? ym
: staff_tb[s1.st].topbar + 2
} else {
y1 = staff_tb[s1.st].topbar + 2
}
if (s2.st >= s1.st) {
ym = y_get(s2.st, 1, x2 - 4, 8)
y2 = ym > staff_tb[s2.st].topbar + 2
? ym
: staff_tb[s2.st].topbar + 2
} else {
y2 = staff_tb[s2.st].topbar + 2
}
xm = .5 * (x1 + x2);
ym = .5 * (y1 + y2);
a = (y2 - y1) / (x2 - x1);
s0 = 3 * (s2.notes[s2.nhd].pit - s1.notes[s1.nhd].pit) / (x2 - x1)
if (s0 > 0) {
if (a < 0)
a = 0
else if (a > s0)
a = s0
} else {
if (a > 0)
a = 0
else if (a < s0)
a = s0
}
a = s1.fmt.beamslope * a / (s1.fmt.beamslope + Math.abs(a))
if (a * a < .1 * .1)
a = 0
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
break
}
if (!in_parenth) {
if (meter.bot)
m2 = +meter.bot
wmeasure += m1 * C.BLEN / m2
}
s.a_meter.push(meter);
meter = {}
while (p[i] == ' ')
i++
if (p[i] == '+') {
meter.top = p[i++];
s.a_meter.push(meter);
meter = {}
}
}
}
if (p[i] == '=') {
val = p.substring(++i).match(/^(\d+)\/(\d+)$/)
if (!val) {
syntax(1, "Bad duration '$1' in M:", p.substring(i))
return
}
wmeasure = C.BLEN * val[1] / val[2]
}
if (!wmeasure) {
syntax(1, errs.bad_val, 'M:')
return
}
s.wmeasure = wmeasure
if (cfmt.writefields.indexOf('M') < 0)
s.a_meter = []
if (parse.state != 3) {
info.M = p;
glovar.meter = s
if (parse.state) {
/* in the tune header, change the unit note length */
if (!glovar.ulen) {
if (wmeasure <= 1
|| wmeasure >= C.BLEN * 3 / 4)
glovar.ulen = C.BLEN / 8
else
glovar.ulen = C.BLEN / 16
}
for (v = 0; v < voice_tb.length; v++) {
voice_tb[v].meter = s;
voice_tb[v].wmeasure = wmeasure
}
}
} else {
curvoice.wmeasure = wmeasure
if (is_voice_sig())
curvoice.meter = s
else
sym_link(s)
// set the meter of the overlay voices
for (p_v = curvoice.voice_down; p_v; p_v = p_v.voice_down)
p_v.wmeasure = wmeasure
}
}
// link P: or Q:
function link_pq(s, text) {
var p_v, s2
if (curvoice.v == par_sy.top_voice) {
sym_link(s)
} else if (voice_tb[par_sy.top_voice].time == s.time) {
p_v = curvoice
curvoice = voice_tb[par_sy.top_voice]
sym_link(s)
curvoice = p_v
} else if (voice_tb[par_sy.top_voice].time > s.time) {
p_v = voice_tb[par_sy.top_voice]
for (s2 = p_v.sym; ; s2 = s2.next) {
if (s2.time >= s.time) {
set_ref(s)
s.fmt = cfmt
s.next = s2
s.prev = s2.prev
if (s2.prev)
s.prev.next = s
else
p_v.sym = s
s2.prev = s
s.v = s2.v
s.p_v = p_v
s.st = p_v.st
break
}
}
} else {
set_ref(s)
s.fmt = cfmt
if (!parse.pq_d)
parse.pq_d = []
parse.pq_d.push(s) // delayed insertion
}
if (!parse.pq)
parse.pq = {}
parse.pq[text] = s.time
} // link_pq()
/* Q: tempo */
function new_tempo(text) {
var i, c, d, nd,
txt = text, // (for info.Q)
s = {
type: C.TEMPO,
dur: 0
}
// get a note duration
function get_nd(p) {
var n, d,
nd = p.match(/(\d+)\/(\d+)/)
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
}
sym_link(s)
break
default:
syntax(0, "'$1:' line ignored", info_type)
break
}
}
// music line parsing functions
/* -- adjust the duration and time of symbols in a measure when L:auto -- */
function adjust_dur(s) {
var s2, time, auto_time, i, fac;
/* search the start of the measure */
s2 = curvoice.last_sym
if (!s2)
return;
/* the bar time is correct if there are multi-rests */
if (s2.type == C.MREST
|| s2.type == C.BAR) /* in second voice */
return
while (s2.type != C.BAR && s2.prev)
s2 = s2.prev;
time = s2.time;
auto_time = curvoice.time - time
fac = curvoice.wmeasure / auto_time
if (fac == 1)
return /* already good duration */
for ( ; s2; s2 = s2.next) {
s2.time = time
if (!s2.dur || s2.grace)
continue
s2.dur *= fac;
s2.dur_orig *= fac;
time += s2.dur
if (s2.type != C.NOTE && s2.type != C.REST)
continue
for (i = 0; i <= s2.nhd; i++)
s2.notes[i].dur *= fac
}
curvoice.time = s.time = time
}
/* -- parse a bar -- */
function new_bar() {
var s2, c, bar_type,
line = parse.line,
s = {
type: C.BAR,
fname: parse.fname,
istart: parse.bol + line.index,
dur: 0,
multi: 0 // needed for decorations
}
if (vover && vover.bar) // end of voice overlay
get_vover('|')
if (glovar.new_nbar) { // %%setbarnb
s.bar_num = glovar.new_nbar;
glovar.new_nbar = 0
}
bar_type = line.char()
while (1) {
c = line.next_char()
switch (c) {
case '|':
case '[':
case ']':
case ':':
bar_type += c
continue
}
break
}
if (bar_type[0] == ':') {
if (bar_type == ':') { // ":" alone
bar_type = '|';
s.bar_dotted = true
} else {
s.rbstop = 2 // right repeat with end
}
}
// set the annotations and the decorations
if (a_gch)
csan_add(s)
if (a_dcn.length)
deco_cnv(s)
/* if the last element is '[', it may start
* a chord or an embedded header */
if (bar_type.slice(-1) == '['
&& !(/[0-9" ]/.test(c))) { // "
bar_type = bar_type.slice(0, -1);
line.index--;
c = '['
}
// check if a repeat variant
if (c > '0' && c <= '9') {
s.text = c
while (1) {
c = line.next_char()
if ("0123456789,.-".indexOf(c) < 0)
break
s.text += c
}
} else if (c == '"' && bar_type.slice(-1) == '[') {
s.text = ""
while (1) {
c = line.next_char()
if (!c) {
syntax(1, "No end of repeat string")
return
}
if (c == '"') {
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
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
}
}
}
if (qplet == 0 || qplet == undefined)
qplet = (curvoice.wmeasure % 9) == 0 ?
3 : 2;
if (tpn < 0)
tpn = tp.length // new tuplet
tp.push({
p: pplet,
q: qplet,
r: rplet,
ro: rplet,
f: curvoice.tup || cfmt.tuplets
})
continue
}
if (c == '&') { // voice overlay start
if (grace) {
syntax(1, errs.bad_grace)
break
}
get_vover('(')
break
}
line.index--;
sls.push(parse_vpos())
continue
case ')': // slur end
s = curvoice.last_sym
if (s) {
switch (s.type) {
case C.SPACE:
if (!s.notes) {
s.notes = []
s.notes[0] = {}
}
case C.NOTE:
case C.REST:
break
case C.GRACE:
// stop the slur on the last grace note
for (s = s.extra; s.next; s = s.next)
;
break
default:
s = null
break
}
}
if (!s) {
syntax(1, errs.bad_char, c)
break
}
slur_add(s)
break
case '!': // start of decoration
if (type.length > 1) // decoration letter
a_dcn.push(type.slice(1, -1))
else
get_deco() // (line -> a_dcn)
break
case '"':
if (grace) {
syntax(1, errs.bad_grace)
break
}
parse_gchord(type)
break
case '[':
if (type.length > 1) { // U: [I:xxx]
self.do_pscom(type.slice(3, -1))
break
}
var c_next = line.buffer[line.index + 1]
if ('|[]: "'.indexOf(c_next) >= 0
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
if (psvg) // if PostScript support
psvg.ps_flush(true); // + setg(0)
// start a block if needed
if (parse.state == 1 && user.page_format && !blkdiv)
blkdiv = 1 // new tune
if (blkdiv > 0) {
user.img_out(blkdiv == 1 ?
'<div class="nobrk">' :
'<div class="nobrk newpage">')
blkdiv = -1 // block started
} else if (blkdiv < 0 && cfmt.splittune) {
i = 1 // header and first music line
blkdiv = 0
}
user.img_out(head + output + g + "</svg>");
if (i)
user.img_out("</div>")
output = ""
clr_sty()
defs = '';
posy = 0
img.wx = 0 // space used between the margins
}
// mark the end of a <div> block
function blk_flush() {
svg_flush()
if (blkdiv < 0 && !parse.state) {
user.img_out('</div>')
blkdiv = 0
}
}
Abc.prototype.blk_flush = blk_flush
// abc2svg - tune.js - tune generation
//
// Copyright (C) 2014-2025 Jean-Francois Moine
//
// This file is part of abc2svg-core.
//
// abc2svg-core is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// abc2svg-core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with abc2svg-core. If not, see <http://www.gnu.org/licenses/>.
var par_sy, // current staff system for parse
cur_sy, // current staff system for generation
voice_tb,
curvoice,
staves_found,
vover, // voice overlay
tsfirst
/* apply the %%voice options of the current voice */
function voice_filter() {
var opt
function vfilt(opts, opt) {
var i,
sel = new RegExp(opt)
if (sel.test(curvoice.id)
|| sel.test(curvoice.nm)) {
for (i = 0; i < opts.length; i++)
self.do_pscom(opts[i])
}
}
// global
if (parse.voice_opts)
for (opt in parse.voice_opts) {
if (parse.voice_opts.hasOwnProperty(opt))
vfilt(parse.voice_opts[opt], opt)
}
// tune
if (parse.tune_v_opts)
for (opt in parse.tune_v_opts) {
if (parse.tune_v_opts.hasOwnProperty(opt))
vfilt(parse.tune_v_opts[opt], opt)
}
}
/* -- link a ABC symbol into the current voice -- */
// if a voice is ignored (not in %%staves) don't link the symbol
// but update the time for P: and Q:
function sym_link(s) {
var tim = curvoice.time
if (!s.fname)
set_ref(s)
if (!curvoice.ignore) {
s.prev = curvoice.last_sym
if (curvoice.last_sym)
curvoice.last_sym.next = s
else
curvoice.sym = s
} else if (s.bar_type) {
curvoice.last_bar = s
}
curvoice.last_sym = s
s.v = curvoice.v;
s.p_v = curvoice;
s.st = curvoice.cst;
s.time = tim
if (s.dur && !s.grace)
curvoice.time += s.dur;
parse.ufmt = true
s.fmt = cfmt // global parameters
s.pos = curvoice.pos
if (curvoice.second)
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
i = s.match(/@font-face[^}]*}/)
if (i && i[0].indexOf("text") > 0) {
ff.text = "\n"
+ i[0] // assume only one @font-face
s = s.replace(i[0], '')
}
}
if (s && s != "\n")
style += s
}
j = 0
while (1) {
i = text.indexOf('<defs>\n', j)
if (i < 0)
break
j = text.indexOf('</defs>', i)
if (j < 0) {
syntax(1, "No </defs> in %%beginsvg sequence")
break
}
defs_add(text.slice(i + 6, j))
}
break
case "text":
action = get_textopt(opt);
if (!action)
action = cfmt.textoption
set_font("text")
if (text.indexOf('\\') >= 0)
text = cnv_escape(text)
if (parse.state > 1) {
s = new_block(type);
s.text = text
s.opt = action
s.font = cfmt.textfont
break
}
write_text(text, action)
break
}
}
/* -- generate a piece of tune -- */
function generate() {
var s, v, p_voice;
if (a_dcn.length) {
syntax(1, "Decoration(s) without symbol: $1", a_dcn)
a_dcn = []
}
if (parse.tp) {
syntax(1, "No end of tuplet")
s = parse.tps
if (s)
delete s.tp
delete parse.tp
}
if (vover) {
syntax(1, "No end of voice overlay");
get_vover(vover.bar ? '|' : ')')
}
self.voice_adj()
sort_all() /* define the time / vertical sequences */
if (tsfirst) {
for (v = 0; v < voice_tb.length; v++) {
if (!voice_tb[v].key)
voice_tb[v].key = parse.ckey // set the starting key
}
if (user.anno_start)
anno_start = a_start
if (user.anno_stop)
anno_stop = a_stop
self.set_bar_num()
if (info.P)
tsfirst.parts = info.P // for play
// give the parser result to the application
if (user.get_abcmodel)
user.get_abcmodel(tsfirst, voice_tb, abc2svg.sym_name, info)
if (user.img_out) // if SVG generation
self.output_music()
} // (tsfirst)
// finish the generation
set_page() // the page layout may have changed
if (info.W)
put_words(info.W)
put_history()
parse.state = 0 // file header
blk_flush() // (force end of block)
if (tsfirst) { // if non void, keep tune data for upper layers
tunes.push([tsfirst, voice_tb, info, cfmt])
tsfirst = null
}
}
// transpose the current key of the voice (called on K: or V:)
function key_trans() {
var i, n, a_acc, b40, d,
s = curvoice.ckey, // current key
ti = s.time || 0
if (s.k_bagpipe || s.k_drum)
return // no transposition
// set the score transposition
n = (curvoice.score | 0) // new transposition
+ (curvoice.shift | 0)
+ (cfmt.transp | 0)
if ((curvoice.tr_sco | 0) == n) { // if same transposition
s.k_sf = curvoice.ckey.k_sf
return
}
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
* create a new staff system and
* link the 'staves' symbol in a voice which is seen from
* the previous system - see sort_all
*/
if (!par_sy.voices[curvoice.v])
for (v = 0; v < par_sy.voices.length; v++) {
if (par_sy.voices[v]) {
curvoice = voice_tb[v]
break
}
}
curvoice.eoln = eoln
s = {
type: C.STAVES,
dur: 0
}
sym_link(s); // link the staves in this voice
par_sy.nstaff = nstaff;
// if no parameter, duplicate the current staff system
if (!parm) {
s.sy = clone(par_sy, 2) // clone the staves and voices
par_sy.next = s.sy
par_sy = s.sy
staves_found = maxtime
curvoice = voice_tb[par_sy.top_voice]
return
}
new_syst();
s.sy = par_sy
}
staves_found = maxtime
/* initialize the (old) voices */
for (v = 0; v < nv; v++) {
p_voice = voice_tb[v]
delete p_voice.second
delete p_voice.floating
if (p_voice.ignore) {
p_voice.ignore = 0 //false
s = p_voice.sym
if (s) {
while (s.next)
s = s.next
}
p_voice.last_sym = s // set back the last symbol
}
}
range = 0
for (i = 0; i < a_vf.length; i++) {
vid = a_vf[i][0];
p_voice = new_voice(vid);
v = p_voice.v
a_vf[i][0] = p_voice;
// set the range and add the overlay voices
while (1) {
par_sy.voices[v] = {
range: range++
}
p_voice = p_voice.voice_down
if (!p_voice)
break
v = p_voice.v
}
}
par_sy.top_voice = a_vf[0][0].v
if (a_vf.length == 1)
par_sy.one_v = 1 //true // one voice
/* change the behavior from %%staves to %%score */
if (cmd[1] == 't') { /* if %%staves */
for (i = 0; i < a_vf.length; i++) {
flags = a_vf[i][1]
if (!(flags & (OPEN_BRACE | OPEN_BRACE2)))
continue
if ((flags & (OPEN_BRACE | CLOSE_BRACE))
== (OPEN_BRACE | CLOSE_BRACE)
|| (flags & (OPEN_BRACE2 | CLOSE_BRACE2))
== (OPEN_BRACE2 | CLOSE_BRACE2))
continue
if (a_vf[i + 1][1] != 0)
continue
if ((flags & OPEN_PARENTH)
|| (a_vf[i + 2][1] & OPEN_PARENTH))
continue
/* {a b c} -> {a *b c} */
if (a_vf[i + 2][1] & (CLOSE_BRACE | CLOSE_BRACE2)) {
a_vf[i + 1][1] |= FL_VOICE
/* {a b c d} -> {(a b) (c d)} */
} else if (a_vf[i + 2][1] == 0
&& (a_vf[i + 3][1]
& (CLOSE_BRACE | CLOSE_BRACE2))) {
a_vf[i][1] |= OPEN_PARENTH;
a_vf[i + 1][1] |= CLOSE_PARENTH;
a_vf[i + 2][1] |= OPEN_PARENTH;
a_vf[i + 3][1] |= CLOSE_PARENTH
}
}
}
/* set the staff system */
st = -1
for (i = 0; i < a_vf.length; i++) {
flags = a_vf[i][1]
if ((flags & (OPEN_PARENTH | CLOSE_PARENTH))
== (OPEN_PARENTH | CLOSE_PARENTH)) {
flags &= ~(OPEN_PARENTH | CLOSE_PARENTH);
a_vf[i][1] = flags
}
p_voice = a_vf[i][0]
if (flags & FL_VOICE) {
p_voice.floating = true;
p_voice.second = true
lib/ChordPro/res/abc/abc2svg/abc2svg-1.js view on Meta::CPAN
par_sy.staves[st] = {
staffscale: 1
}
}
par_sy.staves[st].stafflines = p_voice.stafflines || "|||||",
par_sy.staves[st].flags = 0
}
v = p_voice.v;
p_voice.st = p_voice.cst =
par_sy.voices[v].st = st;
par_sy.staves[st].flags |= flags
if (flags & OPEN_PARENTH) {
p_voice2 = p_voice
while (i < a_vf.length - 1) {
p_voice = a_vf[++i][0];
v = p_voice.v
if (a_vf[i][1] & MASTER_VOICE) {
p_voice2.second = true
p_voice2 = p_voice
} else {
p_voice.second = true;
}
p_voice.st = p_voice.cst
= par_sy.voices[v].st
= st
if (a_vf[i][1] & CLOSE_PARENTH)
break
}
par_sy.staves[st].flags |= a_vf[i][1]
}
}
if (st < 0)
st = 0
par_sy.nstaff = nstaff = st
/* change the behaviour of '|' in %%score */
if (cmd[1] == 'c') { /* if %%score */
for (st = 0; st < nstaff; st++)
par_sy.staves[st].flags ^= STOP_BAR
}
nv = voice_tb.length
st = 0
for (v = 0; v < nv; v++) {
p_voice = voice_tb[v]
if (par_sy.voices[v])
st = p_voice.st
else
p_voice.st = st // (this avoids later crashes)
// if first %%staves
// update the staff of the symbols with no time
if (!maxtime) {
for (s = p_voice.sym; s; s = s.next)
s.st = st
}
if (!par_sy.voices[v])
continue
// set the staff of the overlay voices
p_voice2 = p_voice.voice_down
while (p_voice2) {
p_voice2.second = 1 //true
i = p_voice2.v
p_voice2.st = p_voice2.cst =
par_sy.voices[i].st = st
p_voice2 = p_voice2.voice_down
}
par_sy.voices[v].second = p_voice.second;
st = p_voice.st
if (st > 0 && p_voice.norepbra == undefined
&& !(par_sy.staves[st - 1].flags & STOP_BAR))
p_voice.norepbra = true
}
curvoice = parse.state >= 2 ? voice_tb[par_sy.top_voice] : null
}
// get a voice or create a clone of the current voice
function clone_voice(id) {
var v, p_voice
for (v = 0; v < voice_tb.length; v++) {
p_voice = voice_tb[v]
if (p_voice.id == id)
return p_voice // found
}
p_voice = clone(curvoice);
p_voice.v = voice_tb.length;
p_voice.id = id;
p_voice.sym = p_voice.last_sym = null;
p_voice.key = clone(curvoice.key)
p_voice.sls = []
delete p_voice.nm
delete p_voice.snm
delete p_voice.new_name
delete p_voice.lyric_restart
delete p_voice.lyric_cont
delete p_voice.sym_restart
delete p_voice.sym_cont
delete p_voice.have_ly
delete p_voice.tie_s
voice_tb.push(p_voice)
return p_voice
} // clone_voice()
/* -- get a voice overlay -- */
function get_vover(type) {
var p_voice2, p_voice3, range, s, time, v, v2, v3, s2
/* treat the end of overlay */
if (type == '|'
|| type == ')') {
if (!curvoice.last_note) {
syntax(1, errs.nonote_vo)
if (vover) {
curvoice = vover.p_voice
vover = null
}
return
}
curvoice.last_note.beam_end = true
if (!vover) {
syntax(1, "Erroneous end of voice overlay")
return
}
if (curvoice.time != vover.p_voice.time) {
if (!curvoice.ignore)
syntax(1, "Wrong duration in voice overlay");
if (curvoice.time > vover.p_voice.time)
vover.p_voice.time = curvoice.time
}
curvoice.acc = [] // no accidental anymore
// if the last symbols are spaces, move them to the main voice
p_voice2 = vover.p_voice // main voice
s = curvoice.last_sym
if (s.type == C.SPACE && p_voice2.last_sym.type != C.SPACE) {
s.p_v = p_voice2
s.v = s.p_v.v
while (s.prev.type == C.SPACE) {
s = s.prev
s.p_v = p_voice2
s.v = s.p_v.v
}
s2 = s.prev
s2.next = null
s.prev = p_voice2.last_sym
s.prev.next = s
p_voice2.last_sym = curvoice.last_sym
curvoice.last_sym = s2
}
curvoice = p_voice2
vover = null
return
}
/* treat the full overlay start */
if (type == '(') {
if (vover) {
syntax(1, "Voice overlay already started")
return
}
vover = {
p_voice: curvoice,
time: curvoice.time
}
return
}
/* (here is treated a new overlay - '&') */
/* create the extra voice if not done yet */
if (!curvoice.last_note) {
syntax(1, errs.nonote_vo)
return
}
curvoice.last_note.beam_end = true;
p_voice2 = curvoice.voice_down
if (!p_voice2) {
p_voice2 = clone_voice(curvoice.id + 'o');
curvoice.voice_down = p_voice2;
p_voice2.time = 0;
p_voice2.second = true;
p_voice2.last_note = null
v2 = p_voice2.v;
if (par_sy.voices[curvoice.v]) { // if voice in the staff system
par_sy.voices[v2] = {
st: curvoice.st,
second: true
}
range = par_sy.voices[curvoice.v].range
for (v = 0; v < par_sy.voices.length; v++) {
if (par_sy.voices[v]
&& par_sy.voices[v].range > range)
par_sy.voices[v].range++
}
par_sy.voices[v2].range = range + 1
}
}
p_voice2.ulen = curvoice.ulen
p_voice2.dur_fact = curvoice.dur_fact
p_voice2.acc = [] // no accidental
if (!vover) { /* first '&' in a measure */
time = p_voice2.time
if (curvoice.ignore)
s = curvoice.last_bar
else
for (s = curvoice.last_sym; s; s = s.prev) {
if (s.type == C.BAR
|| s.time <= time) /* (if start of tune) */
break
}
vover = {
bar: (s && s.bar_type) ? s.bar_type : '|',
p_voice: curvoice,
time: s ? s.time : curvoice.time
}
} else {
if (curvoice != vover.p_voice
&& curvoice.time != vover.p_voice.time) {
syntax(1, "Wrong duration in voice overlay")
if (curvoice.time > vover.p_voice.time)
vover.p_voice.time = curvoice.time
}
}
p_voice2.time = vover.time;
curvoice = p_voice2
}
// check if a clef, key or time signature may go at start of the current voice
function is_voice_sig() {
var s
if (curvoice.time)
return false
if (!curvoice.last_sym)
return true
for (s = curvoice.last_sym; s; s = s.prev)
if (w_tb[s.type])
return false
return true
}
// treat a clef found in the tune body
function get_clef(s) {
var s2, s3
// special case for percussion
if (s.clef_type == 'p') { // if percussion clef
s2 = curvoice.ckey
s2.k_drum = 1 //true
s2.k_sf = 0
s2.k_b40 = 2
s2.k_map = abc2svg.keys[7]
if (!curvoice.key)
curvoice.key = s2 // new root key
}
if (!curvoice.time // (force a clef when new voice)
&& is_voice_sig()) {
curvoice.clef = s
s.fmt = cfmt
return
}
// if not clef=none,
// move the clef before a key and/or a (not right repeat) bar
if (s.clef_none)
s2 = null
else
for (s2 = curvoice.last_sym;
s2 && s2.time == curvoice.time;
s2 = s2.prev) {
if (w_tb[s2.type])
break
}
if (s2
&& s2.time == curvoice.time // if no time skip
&& s2.k_sf != undefined) {
s3 = s2 // move before a key signature
s2 = s2.prev