App-Music-ChordPro

 view release on metacpan or  search on metacpan

lib/ChordPro/res/abc/abc2svg/abc2svg-1.js  view on Meta::CPAN

		de.x = x = realwidth - dd.wr

//    if (dd.func == 6
//     && ((de.pos & C.SL_ALI_MSK) == C.SL_ALIGN
//      || ((de.pos & C.SL_ALI_MSK) == 0
//       && de.s.fmt.dynalign > 0)))	// if align
//	;
//    else
	if (up)
		y_set(s.st, 1, x - dd.wl, w, y + dd.h)
	else
		y_set(s.st, 0, x - dd.wl, w, y - dd.hd)

	de.y = y
}

// add a decoration
/* syntax:
 *	%%deco <name> <c_func> <glyph> <h> <wl> <wr> [<str>]
 * "<h>" may be followed by ",<hd>" (descent)
 */
function deco_add(param) {
	var dv = param.match(/(\S*)\s+(.*)/);
	decos[dv[1]] = dv[2]
}

// define a decoration
// nm is the name of the decoration
// nmd is the name of the definition in the table 'decos'
function deco_def(nm, nmd) {
	if (!nmd)
		nmd = nm
    var a, dd, dd2, nm2, c, i, elts, str, hd,
	text = decos[nmd]

	// check if a long decoration with number
	if (!text) {
		if (/\d[()]$/.test(nmd))
			text = decos[nmd.replace(/\d/, '')]
		else if (/^\d$/.test(nmd))	// or some fingering/string number
			text = "3 fng 5,5 3 3 " + nmd
	}
	if (!text) {
		if (cfmt.decoerr)
			error(1, null, "Unknown decoration '$1'", nm)
		return //undefined
	}

	// extract the values
	a = text.match(/(\d+)\s+(.+?)\s+([0-9.,]+)\s+([0-9.]+)\s+([0-9.]+)/)
	if (!a) {
		error(1, null, "Invalid decoration '$1'", nm)
		return //undefined
	}
	var	c_func = Number(a[1]),
//		glyph = a[2],
		h = a[3],
		wl = parseFloat(a[4]),
		wr = parseFloat(a[5])

	if (isNaN(c_func)) {
		error(1, null, "%%deco: bad C function value '$1'", a[1])
		return //undefined
	}
	if (c_func > 10
	 && (c_func < 32 || c_func > 45)) {
		error(1, null, "%%deco: bad C function index '$1'", c_func)
		return //undefined
	}
//	if (c_func == 5)			// old !trill(!
//		c_func = 3
//	if (c_func == 7)			// old !cresc(!
//		c_func = 6

	if (h.indexOf(',') > 0) {
		h = h.split(',')
		hd = h[1]
		h = h[0]
	} else {
		hd = 0
	}
	if (h > 50 || wl > 80 || wr > 80) {
		error(1, null, "%%deco: abnormal h/wl/wr value '$1'", text)
		return //undefined
	}

	// create/redefine the decoration
	dd = dd_tb[nm]
	if (!dd) {
		dd = {
			name: nm
		}
		dd_tb[nm] = dd
	}

	/* set the values */
	dd.func = nm.indexOf("head-") == 0 ? 9 : c_func;
	dd.glyph = a[2];
	dd.h = Number(h)
	dd.hd = Number(hd)
	dd.wl = wl;
	dd.wr = wr;
	str = text.replace(a[0], '').trim()
	if (str) {				// optional string
		if (str[0] == '"')
			str = str.slice(1, -1);
		if (str[0] == '@') {
			c = str.match(/^@([0-9.-]+),([0-9.-]+);?/)
		    if (!c) {
			error(1, null, "%%deco: bad position '$1'", str)
			return
		    }
			dd.dx = +c[1]		// x and y offsets
			dd.dy = +c[2]
			str = str.replace(c[0], '')
		}
		dd.str = str
	}

	/* compatibility */
	if (dd.func == 6 && dd.str == undefined)

lib/ChordPro/res/abc/abc2svg/abc2svg-1.js  view on Meta::CPAN

//	transp: 0,			// global transpose
//	topmargin: .7 * IN,
	topspace: 22,
	tuplets: [0, 0, 0, 0],
	tupletfont: {name: txt_ff, style: "italic", size: 10},
	vocalfont: {name: txt_ff, weight: "bold", size: 13},
	vocalspace: 10,
	voicefont: {name: txt_ff, weight: "bold", size: 13},
//	voicescale: 1,
	writefields: "CMOPQsTWw",
	wordsfont: {name: txt_ff, size: 16},
	wordsspace: 5,
	"writeout-accidentals": "n"
}

// parameters that are used in the symbols
var sfmt = {
bardef: true,
barsperstaff: true,
beamslope: true,
breaklimit: true,
bstemdown: true,
cancelkey: true,
dynalign: true,
flatbeams: true,
gracespace: true,
hyphencont: true,
keywarn: true,
maxshrink: true,
maxstaffsep: true,
measrepnb: true,
rbmax: true,
rbmin: true,
shiftunison: true,
slurheight: true,
squarebreve: true,    
staffsep: true,
systvoices: 1, //true
stemheight: true,
stretchlast: true,
stretchstaff: true,
tieheight: true,
timewarn: true,
trimsvg: 1, //true
vocalspace: true
} // sfmt

function get_bool(param) {
	return !param || !/^(0|n|f)/i.test(param) // accept void as true !
}

// %%font <font> [<encoding>] [<scale>]
function get_font_scale(param) {
    var	i, font,
	a = info_split(param)	// a[0] = font name

	if (a.length <= 1)
		return
	var scale = +a[a.length - 1]

	if (isNaN(scale) || scale <= 0.5) {
		syntax(1, "Bad scale value in %%font")
		return
	}
	font_scale_tb[a[0]] = scale
}

// set the width factor of a font
function set_font_fac(font) {
    var scale = font_scale_tb[font.fname || font.name]

	if (!scale)
		scale = 1.1;
	font.swfac = font.size * scale
}

// %%xxxfont fontname|* [encoding] [size|*]
function param_set_font(xxxfont, p) {
    var	font, n, a, ft2, k

	// "setfont-<n>" goes to "u<n>font"
	if (xxxfont[xxxfont.length - 2] == '-') {
		n = xxxfont[xxxfont.length - 1]
		if (n < '1' || n > '9')
			return
		xxxfont = "u" + n + "font"
	}

	// fill the values
	font = {}
	a = p.match(/\s+(no)?box(\s|$)/)
	if (a) {				// if box
		if (a[1]) {
			font.box = false	// nobox
			font.pad = 0
		} else {
			font.box = true
			font.pad = 2.5
		}
		p = p.replace(a[0], a[2])
	}
	a = p.match(/\s+padding=([\d.]+)(\s|$)/)
	if (a) {				// if padding
		font.pad = a[1] ? +a[1] : 0
		p = p.replace(a[0], a[2])
	}

	a = p.match(/\s+class=(.*?)(\s|$)/)
	if (a) {
		font.class = a[1];
		p = p.replace(a[0], a[2])
	}
	a = p.match(/\s+wadj=(.*?)(\s|$)/)
	if (a) {
	    if (typeof document == "undefined")	// useless if in browser
		switch (a[1]) {
		case 'none':
			font.wadj = ''
			break
		case 'space':
			font.wadj = 'spacing'

lib/ChordPro/res/abc/abc2svg/abc2svg-1.js  view on Meta::CPAN


	if (!font.src) {			// if no url(...)

		// here is the font family
		p = p.trim()

		if (p == '*')
			p = ''
		p = p.replace(/Times-Roman|Times/, "serif")
			.replace("Helvetica", "sans-serif")
			.replace("Courier", "monospace")
			.replace("music", cfmt.musicfont.name)
//hack: the font "Figurato" is used for figured bass
			if (p.indexOf("Fig") > 0)
				font.figb = true
	}
	if (p && !font.name)
		font.name = p

	if (font.size)
		set_font_fac(font)

	// keep the previous attributes if no font name or no size
	if (!font.name || !font.size) {
		ft2 = cfmt[xxxfont]
		for (k in ft2) {
			if (!ft2.hasOwnProperty(k)
			 || font[k] != undefined)
				continue
			switch (k) {
			case "fid":
			case "used":
			case "src":
				break
			case "style":
			case "weight":
				if (font.normal)
					break
				// fall thru
			default:
				font[k] = ft2[k]
				break
			}
		}
		if (!font.swfac)
			set_font_fac(font)
	}
	if (font.pad == undefined)
		font.pad = 0
	font.fname = font.name
	if (font.weight >= 700)
		font.fname += 'Bold'

	cfmt[xxxfont] = font
}

// get a length with a unit - return the number of pixels
function get_unit(param) {
    var	v = param.toLowerCase().match(/(-?[\d.]+)(.*)/)
	if (!v)
		return NaN

	v[1] = +v[1]
	switch (v[2]) {
	case "cm":
		return v[1] * CM
	case "in":
		return v[1] * IN
	case "pt":		// paper point in 1/72 inch
		return v[1] / .75
	case "px":		// screen pixel in 1/96 inch
	case "":
		return v[1]
	}
	return NaN
}

// set the name of an info or a part
function set_infoname(cmd, param) {
//fixme: check syntax: '<letter> ["string"]'
    var	tmp = cfmt[cmd] ? cfmt[cmd].split("\n") : "",
		letter = param[0]

	for (var i = 0; i < tmp.length; i++) {
		var infoname = tmp[i]
		if (infoname[0] != letter)
			continue
		if (param.length == 1)
			tmp.splice(i, 1)
		else
			tmp[i] = param
		cfmt[cmd] = tmp.join('\n')
		return
	}
	if (cfmt[cmd])
		cfmt[cmd] += "\n" + param
	else
		cfmt[cmd] = param
}

// get the text option
var textopt = {
	align: 'j',
	center: 'c',
	fill: 'f',
	justify: 'j',
	obeylines: 'l',
	ragged: 'f',
	right: 'r',
	skip: 's',
// abcm2ps compatibility
	"0": 'l',
	"1": 'j',
	"2": 'f',
	"3": 'c',
	"4": 's',
	"5": 'r'
}
function get_textopt(v) {
    var	i = v.indexOf(' ')
	if (i > 0)
		v = v.slice(0, i)
	return textopt[v]
}

/* -- position of a voice element -- */
var posval = {
	above: C.SL_ABOVE,
	auto: 0,		// !! not C.SL_AUTO !!
	below: C.SL_BELOW,
	down: C.SL_BELOW,
	hidden: C.SL_HIDDEN,
	opposite: C.SL_HIDDEN,
	under: C.SL_BELOW,
	up: C.SL_ABOVE

lib/ChordPro/res/abc/abc2svg/abc2svg-1.js  view on Meta::CPAN

function set_v_param(k, v) {
	k = [k + '=', v]
	if (parse.state < 3)
		memo_kv_parm(curvoice ? curvoice.id : '*', k)
	else if (curvoice)
		set_kv_parm(k)
	else
		memo_kv_parm('*', k)
}

function set_page() {
	if (!img.chg)
		return
	img.chg = false;
	img.lm = cfmt.leftmargin - cfmt.printmargin
	if (img.lm < 0)
		img.lm = 0;
	img.rm = cfmt.rightmargin - cfmt.printmargin
	if (img.rm < 0)
		img.rm = 0;
	img.width = cfmt.pagewidth - 2 * cfmt.printmargin

	// must have 100pt at least as the staff width
	if (img.width - img.lm - img.rm < 100) {
		error(0, undefined, "Bad staff width");
		img.width = img.lm + img.rm + 150
	}
	set_posx()
} // set_page()

// set a format parameter
// (possible hook)
Abc.prototype.set_format = function(cmd, param) {
	var f, f2, v, i

//fixme: should check the type and limits of the parameter values
	if (/.+font(-[\d])?$/.test(cmd)) {
		if (cmd == "soundfont")
			cfmt.soundfont = param
		else
			param_set_font(cmd, param)
		return
	}

	// duplicate the global parameters if already used by symbols
	if (sfmt[cmd] && parse.ufmt)
		cfmt = Object.create(cfmt)

	switch (cmd) {
	case "aligncomposer":
	case "barsperstaff":
	case "infoline":
	case "measurenb":
	case "rbmax":
	case "rbmin":
	case "measrepnb":
	case "shiftunison":
	case "systnames":
	case "systvoices":
		v = parseInt(param)
		if (isNaN(v)) {
			syntax(1, "Bad integer value");
			break
		}
		if (cmd == "systnames") {	// compatibility
			switch (v) {
			case -1: v = 3; break
			case 1: v = 2; break
			case 2: v = 1; break
			}
			cmd = "systvoices"
		}
		cfmt[cmd] = v
		break
	case "abc-version":
	case "bgcolor":
	case "fgcolor":
	case "propagate-accidentals":
	case "writeout-accidentals":
		cfmt[cmd] = param
		break
	case "beamslope":
	case "breaklimit":			// float values
	case "lineskipfac":
	case "maxshrink":
	case "pagescale":
	case "parskipfac":
	case "scale":
	case "slurheight":
	case "stemheight":
	case "tieheight":
		f = +param
		if (isNaN(f) || !param || f < 0) {
			syntax(1, errs.bad_val, '%%' + cmd)
			break
		}
		switch (cmd) {
		case "scale":			// old scale
			f /= .75
		case "pagescale":
			if (f < .1)
				f = .1		// smallest scale
			cmd = "scale";
			img.chg = true
			break
		}
		cfmt[cmd] = f
		break
	case "annotationbox":
	case "gchordbox":
	case "measurebox":
	case "partsbox":
		param_set_font(cmd.replace("box", "font"),	// font
			"* * " + (get_bool(param) ? "box" : "nobox"))
		break
	case "altchord":
	case "bstemdown":
	case "breakoneoln":
	case "cancelkey":
	case "checkbars":
	case "contbarnb":
	case "custos":
	case "decoerr":
	case "flatbeams":
	case "graceslurs":
	case "graceword":
	case "hyphencont":
	case "keywarn":
	case "linewarn":
	case "squarebreve":
	case "splittune":
	case "straightflags":
	case "stretchstaff":
	case "timewarn":
	case "titlecaps":
	case "titleleft":
	case "trimsvg":
		cfmt[cmd] = get_bool(param)
		break
	case "dblrepbar":
		param = ":: " + param
		// fall thru
	case "bardef":			// %%bardef oldbar newbar
		v = param.split(/\s+/)
		if (v.length != 2) {
			syntax(1, errs.bad_val, "%%bardef")
		} else {
			if (parse.ufmt)
				cfmt.bardef = Object.create(cfmt.bardef)	// new object
			cfmt.bardef[v[0]] = v[1]
		}
		break
	case "chordalias":
		v = param.split(/\s+/)
		if (!v.length)
			syntax(1, errs.bad_val, "%%chordalias")
		else
			abc2svg.ch_alias[v[0]] = v[1] || ""
		break
	case "composerspace":
	case "indent":
	case "infospace":
	case "maxstaffsep":
	case "maxsysstaffsep":
	case "musicspace":
	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
		} while (--i >= 0)
		i = 5;
		f2 = cfmt.spatab[i]
		for ( ; ++i < cfmt.spatab.length; ) {
			f2 *= f;
			cfmt.spatab[i] = f2
		}
		break
	case "play":
		cfmt.sound = "play"		// without clef
		break
	case "pos":
		cmd = param.match(/(\w*)\s+(.*)/)
		if (!cmd || !cmd[2]) {
			syntax(1, "Error in %%pos")
			break
		}
		if (cmd[1].slice(0, 3) == 'tup'		// special case for %%pos tuplet
		 && curvoice) {				// inside tune
			if (!curvoice.tup)
				curvoice.tup = cfmt.tuplets
			else
				curvoice.tup = Object.create(curvoice.tup)
			v = posval[cmd[2]]
			switch (v) {
			case C.SL_ABOVE:
				curvoice.tup[3] = 1
				break
			case C.SL_BELOW:
				curvoice.tup[3] = 2
				break
			case C.SL_HIDDEN:
				curvoice.tup[2] = 1
				break
			}
			break
		}
		if (cmd[1].slice(0, 3) == "vol")
			cmd[1] = "dyn"			// compatibility
		set_pos(cmd[1], cmd[2])
		break
	case "sounding-score":
		if (cfmt.sound != "play")
			cfmt.sound = "sounding"
		break
	case "staffwidth":
		v = get_unit(param)
		if (isNaN(v)) {
			syntax(1, errs.bad_val, '%%' + cmd)
			break
		}
		if (v < 100) {
			syntax(1, "%%staffwidth too small")
			break
		}
		v = cfmt.pagewidth - v - cfmt.leftmargin
		if (v < 2) {
			syntax(1, "%%staffwidth too big")
			break
		}
		cfmt.rightmargin = v;
		img.chg = true
		break
	case "textoption":
		cfmt[cmd] = get_textopt(param)
		break
	case "dynalign":
	case "quiet":
	case "singleline":
	case "stretchlast":
	case "titletrim":
		v = param == '' ? 1 : +param
		if (isNaN(v))
			v = +get_bool(param)
		if (cmd[1] == 't') {		// stretchlast
			if (v < 0 || v > 1) {
				syntax(1, errs.bad_val, '%%' + cmd)
				break
			}
		}
		cfmt[cmd] = v
		break
	case "combinevoices":
		syntax(1, "%%combinevoices is deprecated - use %%voicecombine instead")
		break
	case "voicemap":
		set_v_param("map", param)
		break
	case "voicescale":
		set_v_param("scale", param)
		break
	case "unsizedsvg":
		if (get_bool(param))
			user.imagesize = ""
		else
			delete user.imagesize
		break
	// deprecated
	case "rbdbstop":
		v = get_bool(param)
		if (v && cfmt["abc-version"] >= "2.2")
			cfmt["abc-version"] = "1"
		else if (!v && cfmt["abc-version"] < "2.2")
			cfmt["abc-version"] = "2.2"
		break
	default:		// memorize all global commands
		if (!parse.state)		// (needed for modules)
			cfmt[cmd] = param
		break
	}

	// check if already a same format
	if (sfmt[cmd] && parse.ufmt) {
		// to do...
		parse.ufmt = false
	}
}

// font stuff

// build a font style
function st_font(font) {
    var	n = font.name,
	r = ""

	if (font.weight)
		r += font.weight + " "
	if (font.style)
		r += font.style + " "
	if (n.indexOf('"') < 0 && n.indexOf(' ') > 0)
		n = '"' + n + '"'
	return r + font.size.toFixed(1) + 'px ' + n
}

lib/ChordPro/res/abc/abc2svg/abc2svg-1.js  view on Meta::CPAN

	"/o": "ø",
//	"/D": "Đ",
//	"/d": "Ä‘",
	"/L": "Ł",
	"/l": "Å‚",
	"vL": "Ľ",
	"vl": "ľ",
	"vd": "ď",
	".i": "ı",
	"AA": "Ã…",
	"aa": "Ã¥",
	"AE": "Æ",
	"ae": "æ",
	"DH": "Ð",
	"dh": "ð",
//	"ng": "Å‹",
	"OE": "Å’",
	"oe": "Å“",
	"ss": "ß",
	"TH": "Þ",
	"th": "þ"
}

// accidentals as octal values (abcm2ps compatibility)
var oct_acc = {
	"1": "\u266f",
	"2": "\u266d",
	"3": "\u266e",
	"4": "&#x1d12a;",
	"5": "&#x1d12b;"
}

// convert the escape sequences to utf-8
function cnv_escape(src, flag) {
	var	c, c2,
		dst = "",
		i, j = 0

	while (1) {
		i = src.indexOf('\\', j)
		if (i < 0)
			break
		dst += src.slice(j, i);
		c = src[++i]
		if (!c)
			return dst + '\\'
		switch (c) {
		case '0':
		case '2':
			if (src[i + 1] != '0')
				break
			c2 = oct_acc[src[i + 2]]
			if (c2) {
				dst += c2;
				j = i + 3
				continue
			}
			break
		case 'u':
			j = Number("0x" + src.slice(i + 1, i + 5));
			if (isNaN(j) || j < 0x20) {
				dst += src[++i] + "\u0306"	// breve accent
				j = i + 1
				continue
			}
			c = String.fromCharCode(j)
			if (c == '\\') {
				i += 4
				break
			}
			dst += c
			j = i + 5
			continue
		case 't':			// TAB
			dst += '\t';
			j = i + 1
			continue
		case 'n':			// new line (voice name)
			dst += '\n';
			j = i + 1
			continue
		default:
			c2 = abc_utf[src.slice(i, i + 2)]
			if (c2) {
				dst += c2;
				j = i + 2
				continue
			}

			// try unicode combine characters
			c2 = src[i + 1]
			if (!c2)
				break	// !! the next test is true if c2 is undefined !!
			if (!/[A-Za-z]/.test(c2))
				break
			switch (c) {
			case '`':
				dst += c2 + "\u0300"	// grave
				j = i + 2
				continue
			case "'":
				dst += c2 + "\u0301"	// acute
				j = i + 2
				continue
			case '^':
				dst += c2 + "\u0302"	// circumflex
				j = i + 2
				continue
			case '~':
				dst += c2 + "\u0303"	// tilde
				j = i + 2
				continue
			case '=':
				dst += c2 + "\u0304"	// macron
				j = i + 2
				continue
			case '_':
				dst += c2 + "\u0305"	// overline
				j = i + 2
				continue
			case '.':

lib/ChordPro/res/abc/abc2svg/abc2svg-1.js  view on Meta::CPAN

	}
	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
		}

	sym_link(s)
	return s
}

// set the voice parameters
// (possible hook)
Abc.prototype.set_vp = function(a) {
    var	s, item, pos, val, clefpit,
	tr_p = 0

	while (1) {
		item = a.shift()
		if (!item)
			break
		if (item.slice(-1) == '='
		 && !a.length) {
			syntax(1, errs.bad_val, item)
			break
		}
		switch (item) {
		case "clef=":
			s = a.shift()		// keep last clef
			break
		case "clefpitch=":
			item = a.shift()		// (<note><octave>)
			if (item) {
				val = ntb.indexOf(item[0])
				if (val >= 0) {
					switch (item[1]) {
					case "'":
						val += 7
						break
					case ',':
						val -= 7
						if (item[2] == ',')
							val -= 7
						break
					}
					clefpit = 4 - val	// 4 = 'G'
					break
				}
			}
			syntax(1, errs.bad_val, item)
			break
		case "octave=":
			val = +a.shift()
			if (isNaN(val))
				syntax(1, errs.bad_val, item)
			else
				curvoice.octave = val
			break
		case "cue=":
			// (ignore cue=off)
//			curvoice.scale = a.shift() == 'on' ? .7 : 1
			if (a.shift() == 'on')
				curvoice.scale = .7
			break
		case "instrument=":

			// instrument=M/N => score=MN and sound=cN
			// (instrument=M == instrument=M/M)
			item = a.shift()
			val = item.indexOf('/')
			if (val < 0) {
				val = get_interval('c' + item)
				if (val == undefined)
					break
				curvoice.sound = val
				tr_p |= 2
				val = 0
			} else {
				val = get_interval('c' + item.slice(val + 1))
				if (val == undefined)
					break
				curvoice.sound = val
				tr_p |= 2
				val = get_interval(item.replace('/', ''))
				if (val == undefined)
					break
			}
			curvoice.score = cfmt.sound ? curvoice.sound : val
			tr_p |= 1
			break
		case "map=":			// %%voicemap
			curvoice.map = a.shift()
			break
		case "name=":
		case "nm=":
			curvoice.nm = a.shift()
			if (curvoice.nm[0] == '"')
				curvoice.nm = cnv_escape(curvoice.nm.slice(1, -1))
			curvoice.new_name = true
			break
		case "stem=":			// compatibility
		case "pos=":			// from %%pos only
			if (item == "pos=")
				item = a.shift()
					.slice(1, -1)	// always inside dble quotes
					.split(' ')
			else
				item = ["stm", a.shift()];
			val = posval[item[1]]
			if (val == undefined) {
				syntax(1, errs.bad_val, "%%pos")
				break
			}
			switch (item[2]) {
			case "align": val |= C.SL_ALIGN; break
			case "center": val |= C.SL_CENTER; break
			case "close": val |= C.SL_CLOSE; break
			}
			if (!pos)
				pos = {}
			pos[item[0]] = val
			break
		case "scale=":			// %%voicescale
			val = +a.shift()
			if (isNaN(val) || val < .5 || val > 2)
				syntax(1, errs.bad_val, "%%voicescale")
			else
				curvoice.scale = val
			break
		case "score=":
			if (cfmt.nedo) {
				syntax(1, errs.notransp)
				break
			}
			// score=MN
			// (score=M == score=Mc)
			item = a.shift()
			if (cfmt.sound)
				break
			val = get_interval(item, true)
			if (val != undefined) {
				curvoice.score = val
				tr_p |= 1
			}
			break
		case "shift=":
			if (cfmt.nedo) {
				syntax(1, errs.notransp)
				break
			}
			val = get_interval(a.shift())
			if (val != undefined) {
				curvoice.shift = val
				tr_p = 3
			}
			break
		case "sound=":
			if (cfmt.nedo) {
				syntax(1, errs.notransp)
				break
			}
// concert-score display: apply sound=
// sounding-score display: apply sound= only if M != c/C
// sound: apply sound=
			val = get_interval(a.shift())
			if (val == undefined)
				break
			curvoice.sound = val
			if (cfmt.sound)
				curvoice.score = val
			tr_p |= 2
			break
		case "subname=":
		case "sname=":
		case "snm=":
			curvoice.snm = a.shift()
			if (curvoice.snm[0] == '"')
				curvoice.snm = curvoice.snm.slice(1, -1);
			break
		case "stafflines=":
			val = get_st_lines(a.shift())
			if (val == undefined) {
				syntax(1, "Bad %%stafflines value")
				break
			}
			if (curvoice.st != undefined)
				par_sy.staves[curvoice.st].stafflines = val
			curvoice.stafflines = val
			break
		case "staffnonote=":
			val = +a.shift()
			if (isNaN(val))
				syntax(1, "Bad %%staffnonote value")
			else
				curvoice.staffnonote = val
			break
		case "staffscale=":
			val = +a.shift()
			if (isNaN(val) || val < .3 || val > 2)
				syntax(1, "Bad %%staffscale value")
			else
				curvoice.staffscale = val
			break
		case "tacet=":
			val = a.shift()
			curvoice.tacet = val || undefined
			break
		case "transpose=":		// (abcMIDI compatibility)
			val = get_transp(a.shift())
			if (val == undefined) {
				syntax(1, errs.bad_transp)
			} else {
				curvoice.sound = val
				if (cfmt.sound)
					curvoice.score = val
				tr_p = 2
			}
			break
		default:
			switch (item.slice(0, 4)) {
			case "treb":
			case "bass":
			case "alto":
			case "teno":
			case "perc":
				s = item
				break
			default:
				if ("GFC".indexOf(item[0]) >= 0)
					s = item
				else if (item.slice(-1) == '=')
					a.shift()
				break
			}
			break
		}
	}
	if (pos) {
		curvoice.pos = clone(curvoice.pos)
		for (item in pos)
			if (pos.hasOwnProperty(item))
				curvoice.pos[item] = pos[item]
	}

	if (s) {
		s = new_clef(s)
		if (s) {
			if (clefpit)
				s.clefpit = clefpit
			get_clef(s)
		}
	}

	// if transposition
	if (tr_p & 2) {			// curvoice.tr_sco is set in key_trans()
		tr_p = (curvoice.sound | 0) + (curvoice.shift | 0)
		if (tr_p)
			curvoice.tr_snd = abc2svg.b40m(tr_p + 122) - 36
							// semi-tone interval

lib/ChordPro/res/abc/abc2svg/abc2svg-1.js  view on Meta::CPAN

}

// 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+)/)

		if (nd) {
			d = +nd[2]
			if (d && !isNaN(d) && !(d & (d - 1))) {
				n = +nd[1]
				if (!isNaN(n))
					return C.BLEN * n / d
			}
		}
		syntax(1, "Invalid note duration $1", c)
	} // get_nd()

	set_ref(s)

	if (cfmt.writefields.indexOf('Q') < 0)
		s.invis = true			// don't display

	/* string before */
	if (text[0] == '"') {
		c = text.match(/"([^"]*)"/)		// "
		if (!c) {
			syntax(1, "Unterminated string in Q:")
			return
		}
		s.tempo_str1 = c[1]
		text = text.slice(c[0].length).replace(/^\s+/,'')
	}

	// string after
	if (text.slice(-1) == '"') {
		i = text.indexOf('"')
		s.tempo_str2 = text.slice(i + 1, -1)
		text = text.slice(0, i).replace(/\s+$/,'')
	}

	/* beat */
	i = text.indexOf('=')
	if (i > 0) {
		d = text.slice(0, i).split(/\s+/)
		text = text.slice(i + 1).replace(/^\s+/,'')
		while (1) {
			c = d.shift()
			if (!c)
				break
			nd = get_nd(c)
			if (!nd)
				return
			if (!s.tempo_notes)
				s.tempo_notes = []
			s.tempo_notes.push(nd)
		}

		// tempo value
		if (text.slice(0, 4) == "ca. ") {
			s.tempo_ca = 'ca. '
			text = text.slice(4)
		}
		i = text.indexOf('/')
		if (i > 0) {
			nd = get_nd(text)
			if (!nd)
				return
			s.new_beat = nd
		} else {
			s.tempo = +text
			if (!s.tempo || isNaN(s.tempo)) {
				syntax(1, "Bad tempo value")
				return
			}
		}
	}

	if (parse.state < 2			// if in tune header
	 || (!curvoice.time && !glovar.tempo)) {
		info.Q = txt
		glovar.tempo = s
		return
	}

	if (!glovar.tempo)
		syntax(0, "No previous tempo")
	s.time = curvoice.time
	text = 'Q' + (s.tempo_str1 ? 'S' : '') + s.time
						// accept [Q:"text"][Q:1/4=60]
	if (parse.pq
	 && parse.pq[text] == s.time)
		return				// already seen
	link_pq(s, text)
}

// treat the information fields which may embedded
function do_info(info_type, text) {
    var	s, d1, d2, a, vid, tim, v, p_v

	// skip this line if the current voice is ignored
	// but keep the time related definitions
	if (curvoice && curvoice.ignore) {
		switch (info_type) {
		default:
			return
		case 'P':
		case 'Q':
		case 'V':
			break
		}
	}

	switch (info_type) {

	// info fields in any state
	case 'I':
		self.do_pscom(text)
		break
	case 'L':
		a = text.match(/^1\/(\d+)(=(\d+)\/(\d+))?$/)
		if (a) {
			d1 = +a[1]
			if (!d1 || (d1 & (d1 - 1)) != 0)
				break
			d1 = C.BLEN / d1
			if (a[2]) {		// if '='
				d2 = +a[4]
				d2 = d2 ? +a[3] / d2 * C.BLEN : 0
			} else {
				d2 = d1
			}

lib/ChordPro/res/abc/abc2svg/abc2svg-1.js  view on Meta::CPAN

		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
	}

	switch (cmd) {
	case "clef":
		if (parse.state >= 2) {
			s = new_clef(param)
			if (s)
				get_clef(s)
		}
		return
	case "deco":
		deco_add(param)
		return
	case "linebreak":
		set_linebreak(param)
		return
	case "map":
		get_map(param)
		return
	case "maxsysstaffsep":
	case "sysstaffsep":
		if (parse.state == 3) {
			val = get_unit(param)
			if (isNaN(val)) {
				syntax(1, errs.bad_val, "%%" + cmd)
				return
			}
			par_sy.voices[curvoice.v][cmd[0] == 'm' ? "maxsep" : "sep"] =
					val
			return
		}
		break
	case "multicol":
		switch (param) {
		case "start":
		case "new":
		case "end":
			break
		default:
			syntax(1, "Unknown keyword '$1' in %%multicol", param)
			return
		}
		s = {
			type: C.BLOCK,
			subtype: "mc_" + param,
			dur: 0
		}
		if (parse.state >= 2) {
			if (curvoice.clone)
				do_cloning()
			curvoice = voice_tb[0]
			curvoice.eoln = 1 //true
			sym_link(s)
			return
		}
		set_ref(s)
		self.block_gen(s)
		return
	case "ottava":
		if (parse.state != 3)
			return
		n = parseInt(param)
		if (isNaN(n) || n < -2 || n > 2
		 || (!n && !curvoice.ottava)) {
			syntax(1, errs.bad_val, "%%ottava")
			return
		}
		k = n
		if (n) {
			curvoice.ottava = n
		} else {
			n = curvoice.ottava
			curvoice.ottava = 0
		}
		a_dcn.push(["15mb", "8vb", "", "8va", "15ma"][n + 2]
			+ (k ? '(' : ')'))
		return
	case "repbra":
		if (curvoice)
			curvoice.norepbra = !get_bool(param)
		return
	case "repeat":
		if (parse.state != 3)
			return
		if (!curvoice.last_sym) {
			syntax(1, "%%repeat cannot start a tune")
			return
		}
		if (!param.length) {
			n = 1;
			k = 1
		} else {
			b = param.split(/\s+/);
			n = parseInt(b[0]);
			k = parseInt(b[1])
			if (isNaN(n) || n < 1
			 || (curvoice.last_sym.type == C.BAR
			  && n > 2)) {
				syntax(1, "Incorrect 1st value in %%repeat")
				return
			}
			if (isNaN(k)) {
				k = 1
			} else {
				if (k < 1) {
					syntax(1, "Incorrect 2nd value in %%repeat")
					return
				}
			}
		}
		parse.repeat_n = curvoice.last_sym.type == C.BAR ? n : -n;
		parse.repeat_k = k
		return
	case "sep":
		var	h2, len, values, lwidth;

		set_page();
		lwidth = img.width - img.lm - img.rm;
		h1 = h2 = len = 0
		if (param) {
			values = param.split(/\s+/);
			h1 = get_unit(values[0])
			if (values[1]) {
				h2 = get_unit(values[1])
				if (values[2])
					len = get_unit(values[2])
			}
			if (isNaN(h1) || isNaN(h2) || isNaN(len)) {
				syntax(1, errs.bad_val, "%%sep")
				return
			}
		}
		if (h1 < 1)
			h1 = 14
		if (h2 < 1)
			h2 = h1
		if (len < 1)
			len = 90
		if (parse.state >= 2) {
			if (curvoice.clone)
				do_cloning()
			s = new_block(cmd);
			s.x = (lwidth - len) / 2 / cfmt.scale;
			s.l = len / cfmt.scale;
			s.sk1 = h1;
			s.sk2 = h2
			return
		}
		vskip(h1);
		output += '<path class="stroke"\n\td="M';
		out_sxsy((lwidth - len) / 2 / cfmt.scale, ' ', 0);
		output += 'h' + (len / cfmt.scale).toFixed(1) + '"/>\n';
		vskip(h2);
		blk_flush()
		return
	case "setbarnb":
		val = parseInt(param)
		if (isNaN(val) || val < 1) {
			syntax(1, "Bad %%setbarnb value")
			break
		}
		glovar.new_nbar = val
		return
	case "staff":
		if (parse.state != 3)
			return
		if (curvoice.clone)
			do_cloning()
		val = parseInt(param)
		if (isNaN(val)) {
			syntax(1, "Bad %%staff value '$1'", param)
			return
		}
		var st
		if (param[0] == '+' || param[0] == '-')
			st = curvoice.cst + val
		else
			st = val - 1
		if (st < 0 || st > nstaff) {
			syntax(1, "Bad %%staff number $1 (cur $2, max $3)",
					st, curvoice.cst, nstaff)
			return
		}
		delete curvoice.floating;
		curvoice.cst = st
		return
	case "staffbreak":
		if (parse.state != 3)
			return
		if (curvoice.clone)
			do_cloning()
		s = {
			type: C.STBRK,
			dur:0
		}
		if (param.slice(-1) == 'f') {
			s.stbrk_forced = true
			param = param.replace(/\sf$/, '')
		}
		if (param) {
			val = get_unit(param)
			if (isNaN(val)) {
				syntax(1, errs.bad_val, "%%staffbreak")
				return
			}
			s.xmx = val
		} else {
			s.xmx = 14
		}
		sym_link(s)
		return
	case "tacet":
		if (param[0] == '"')
			param = param.slice(1, -1)
		// fall thru
	case "stafflines":
	case "staffscale":
	case "staffnonote":
		set_v_param(cmd, param)
		return
	case "staves":
	case "score":
		if (!parse.state)
			return
		if (parse.scores && parse.scores.length > 0) {
			text = parse.scores.shift();
			cmd = text.match(/([^\s]+)\s*(.*)/);
			param = cmd[2]
			cmd = cmd[1]
		}
		get_staves(cmd, param)
		return
	case "center":
	case "text":
		k = cmd[0] == 'c' ? 'c' : cfmt.textoption
		set_font("text")
		if (parse.state >= 2) {
			if (curvoice.clone)
				do_cloning()
			s = new_block("text")
			s.text = param
			s.opt = k
			s.font = cfmt.textfont
			return
		}
		write_text(param, k)
		return
	case "transpose":		// (abcm2ps compatibility)
		if (cfmt.sound)
			return
		val = get_transp(param)
		if (val == undefined) {		// accept note interval
			val = get_interval(param)
			if (val == undefined)
				return
		}
		switch (parse.state) {
		case 0:
			cfmt.transp = 0
			// fall thru
		case 1:
			cfmt.transp = (cfmt.transp || 0) + val
			return
		}
		curvoice.shift = val
		key_trans()
		return
	case "tune":
//fixme: to do
		return
	case "user":
		set_user(param)
		return
	case "voicecolor":
		if (curvoice)
			curvoice.color = param
		return
	case "vskip":
		val = get_unit(param)
		if (isNaN(val)) {
			syntax(1, errs.bad_val, "%%vskip")
			return
		}
		if (val < 0) {
			syntax(1, "%%vskip cannot be negative")
			return
		}
		if (parse.state >= 2) {
			if (curvoice.clone)
				do_cloning()
			s = new_block(cmd);
			s.sk = val
			return
		}
		vskip(val);
		return
	case "newpage":
	case "leftmargin":
	case "rightmargin":
	case "pagescale":
	case "pagewidth":
	case "printmargin":
	case "scale":
	case "staffwidth":
		if (parse.state >= 2) {
			if (curvoice.clone)
				do_cloning()
			s = new_block(cmd);
			s.param = param
			return
		}
		if (cmd == "newpage") {
			blk_flush()
			if (user.page_format)
				blkdiv = 2	// start the next SVG in a new page
			return
		}
		break
	}
	self.set_format(cmd, param)
}

// treat the %%beginxxx / %%endxxx sequences
// (possible hook)
Abc.prototype.do_begin_end = function(type,
			opt,
			text) {
	var i, j, action, s

	if (curvoice && curvoice.clone)
		do_cloning()
	switch (type) {
	case "js":
		js_inject(text)
		break
	case "ml":
		if (cfmt.pageheight) {
			syntax(1, "Cannot have %%beginml with %%pageheight")
			break
		}



( run in 0.702 second using v1.01-cache-2.11-cpan-4e7a2411597 )