abc2svg
Check-in Differences
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Difference From d6636870ae43e9ac To 1f1e9ecb656a9e71

2024-02-01
10:50
core: keep the multi-measure rests of the second voices of the staves - asked by Gerhard Schacherl ... (check-in: fc7af4436c user: jef tags: trunk)
2024-01-30
16:56
New release v1.22.13 ... (check-in: 1f1e9ecb65 user: jef tags: trunk, v1.22.13)
2024-01-27
15:05
core: better vertical offset of rests when many voices ... (check-in: e8149de154 user: jef tags: trunk)
2023-01-07
14:29
modules: nns: fix: add 'roman=2' to %%nns and fix some chords - reported by Robert Bley-Vroman ... (check-in: 8365017fa6 user: jef tags: trunk)
07:38
New release v1.22.6 ... (check-in: d6636870ae user: jef tags: trunk, v1.22.6)
07:35
source: copyright update ... (check-in: d49a8df607 user: jef tags: trunk)

Changes to README.md.
︙
324
325
326
327
328
329
330
331
332


333
334
335
336
337
338
339
340
341




342
343
344
345

346
347
348
349
350
351
352
324
325
326
327
328
329
330


331
332
333
334
335
336
337
338
339


340
341
342
343
344
345
346

347
348
349
350
351
352
353
354







-
-
+
+







-
-
+
+
+
+



-
+







  The abc2svg music font (`abc2svf.woff` or `abc2svg.ttf`) must be installed
  in the local system for displaying and/or converting the .abw file.  
  Example:  
  `        abcmjs toabw.js my_file.abc > my_file.abw`

- `tomei.js`  
  This script outputs the music as a [MEI](https://music-encoding.org/) file.  
  Note, only one tune may be translated from ABC to MEI (multi-tunes ABC
  generates bad MEI).
  Note, only one tune may be translated from ABC to MEI (multi-tunes ABC files
  generate bad MEI files).

- `tonotes.js`  
  This script outputs a list of the MIDI events.

- `toodt.js`  
  This script creates an Open Document (ODT+SVG) which can be read by most
  word processors (abiword, libreoffice...).  
  It runs only with the shell script `abc2svg` and asks for the npm module
  `jszip` to be installed.  
  When runs with the shell script `abc2svg`, it asks for the npm module
  `jszip` to be installed.
  When run with `abcqjs` on unix-like systems, it creates a temporary
  directory tree in `/tmp`.  
  The output ODT document may be specified in the command line argument
  after `-o` (default `abc.odt`).  
  Example:  
  `        abc2svg toodt.js my_file.abc -o my_file.odt`
  `        abcqjs toodt.js my_file.abc -o my_file.odt`

- `toparam.js`  
  This script just outputs the abc2svg parameters.

#### 2.3 PDF generation

`abctopdf` is a shell script which converts ABC to PDF using one of the
︙
459
460
461
462
463
464
465
466

467
468
469
470
471
472
473
461
462
463
464
465
466
467

468
469
470
471
472
473
474
475







-
+







  the core interface (actually '`-1`').

#### 4.3 More about the web scripts

Here are the scripts which are used in a web context:

- `abcweb-1.js`  
  This script replaces the ABC or MEI sequences found in the (X)HTML file
  This script replaces the ABC sequences found in the (X)HTML file
  by SVG images of the music.  
  The ABC sequences are searched:
  - first inside <script> elements with a type
    ["text/vnd.abc"](https://www.iana.org/assignments/media-types/text/vnd.abc)
    (the script tag is replaced by a <div>),
  - or inside (X)HTML elements with a class `abc` (lower case letters),
  - otherwise on `X:` or `%abc-` at start of line up to a XML tag at start of line.
︙
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
539
540
541
542
543
544
545















546
547
548
549
550
551
552







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







	When one or many tunes are displayed, a menu in the top/right corner
  offers to go back to the tune list or to modify the ABC source.

- `snd-1.js`  
  This script may be used with `abcweb-1.js` or `abcweb1-1.js`
  to play the rendered ABC music.  

### 5. MEI support

As an experimental feature, an extended core `mei2svg-1.js` may be generated.
This one may handle both the ABC and
[MEI](https://music-encoding.org/ "Music Encoding Initiative")
notations.

In browser mode, the script `abcweb-1.js` loads either `abc2svg-1.js` or
`mei2svg-1.js` after checking if `<mei` exists in the page (see
[this tune](http://moinejf.free.fr/abc/Czerny_op603_6.html)
for an example).

In shell mode, the script `abcqjs` also loads the right abc2svg core
according to the source file extension (`.abc` or `.mei`).

### 6. Credit

**abc2svg** includes the following packages:

- wps by Tomas Hlavaty  
  <http://logand.com/sw/wps/log.html>

︙
Changes to abc2svg.ttf.

cannot compute difference between binary files

Changes to abctopdf.
︙
86
87
88
89
90
91
92

93
94


95
96
97
98
99
100
101
86
87
88
89
90
91
92
93


94
95
96
97
98
99
100
101
102







+
-
-
+
+







done

# check if some chromium-based browser is available
for c in "$BROWSER" chromium-browser vivaldi opera brave-browser epic google-chrome; do
	if command -v "$c" >/dev/null 2>&1; then
		echo "and $c"
		command $abcscr "$@" > /tmp/o.html
# --headless=new does not work
		"$c" --headless --disable-gpu\
			--print-to-pdf=$out --print-to-pdf-no-header /tmp/o.html
		"$c" --headless --print-to-pdf=$out --no-pdf-header-footer\
			/tmp/o.html
		rm /tmp/o.html
		exit 0
	fi
done

# try weasyprint
if command -v weasyprint >/dev/null 2>&1; then
︙
Changes to build.ninja.
︙
10
11
12
13
14
15
16

17
18
19
20
21
22
23
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24







+








rule cpm
  command = sed "s+@MAJOR@+$MAJOR+" $in > $out

rule font
  command = fontforge -c 'open("font/abc2svg.sfd").generate("abc2svg.ttf")';$
   fontforge -c 'open("font/abc2svg.sfd").generate("abc2svg.woff")';$
   fontforge -c 'open("font/abc2svg.sfd").generate("abc2svg.woff2")';$
   echo '// abc2svg music font' > font.js;$
   echo "var musicfont = 'url(\"data:application/octet-stream;base64,\\" >> font.js;$
   base64 abc2svg.ttf | sed 's/$$/\\/' >> font.js;$
   echo "\") format(\"truetype\")'" >> font.js

rule jsc
  command = if [ -e .fslckout ] && command -v fossil >/dev/null 2>&1; then $
︙
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
91
92
93
94
95
96
97




98
99
100
101
102
103
104







-
-
-
-







build sf: sf | Scc1t2/

build abc2svg-$MAJOR.js: jsc core/abc2svg.js core/deco.js core/draw.js $
 font.js core/format.js core/front.js core/music.js core/parse.js core/subs.js $
 core/svg.js core/tune.js core/lyrics.js core/gchord.js core/tail.js $
 core/modules.js
#| package.json
build mei2svg-$MAJOR.js: jsc core/abc2svg.js core/deco.js core/draw.js $
 font.js core/format.js core/front.js core/music.js core/parse.js core/subs.js $
 core/svg.js core/tune.js core/lyrics.js core/gchord.js core/mei.js core/tail.js $
 core/modules.js | package.json

build ambitus-$MAJOR.js: jscu modules/ambitus.js
build break-$MAJOR.js: jscu modules/break.js
build capo-$MAJOR.js: jscu modules/capo.js
build chordnames-$MAJOR.js: jscu modules/chordnames.js
build clair-$MAJOR.js: jscu modules/clair.js
build clip-$MAJOR.js: jscu modules/clip.js
︙
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
147
148
149
150
151
152
153

154
155
156
157
158
159
160







-







 combine-$MAJOR.js diag-$MAJOR.js equalbars-$MAJOR.js gamelan-$MAJOR.js $
 grid-$MAJOR.js grid2-$MAJOR.js grid3-$MAJOR.js jianpu-$MAJOR.js $
 jazzchord-$MAJOR.js  mdnn-$MAJOR.js MIDI-$MAJOR.js $
 nns-$MAJOR.js page-$MAJOR.js pedline-$MAJOR.js perc-$MAJOR.js psvg-$MAJOR.js $
 roman-$MAJOR.js soloffs-$MAJOR.js sth-$MAJOR.js strtab-$MAJOR.js $
 temper-$MAJOR.js tropt-$MAJOR.js edit-$MAJOR.css edit-$MAJOR.js edit-$MAJOR.xhtml $
 abckbd-$MAJOR.js abckbd2-$MAJOR.js
# not mei2svg-$MAJOR.js

default all

# fossil new release
rule version
  command = v=`fossil changes|wc -l`;$
	if [ $$v -ne 0 ]; then $
︙
Changes to cmdline.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - cmdline.js - command line
//
// Copyright (C) 2014-2021 Jean-Francois Moine
// Copyright (C) 2014-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
︙
46
47
48
49
50
51
52
53

54
55
56
57
58
59
60
46
47
48
49
50
51
52

53
54
55
56
57
58
59
60







-
+








		// convert the file content into a Unix string
		i = file.indexOf('\r')
		if (i >= 0) {
			if (file[i + 1] == '\n')
				file =  file.replace(/\r\n/g, '\n')	// M$
			else
				fike =  file.replace(/\r/g, '\n')	// Mac
				file =  file.replace(/\r/g, '\n')	// Mac
		}

		// load the required modules (synchronous)
		abc2svg.modules.load(file)

		return file
	},
︙
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
78
79
80
81
82
83
84







85
86
87
88
89
90
91







-
-
-
-
-
-
-







		if (fn != "default.abc")
			user.errmsg("Cannot read file '" + fn + "'")
		return
	}
//	if (typeof(utf_convert) == "function")
//		file = utf_convert(file)

	if (fn.slice(-4) == ".mei") {
		if (!abc.mei2mus)
			abc2svg.abort(new Error("No MEI support"));
		abc.mei2mus(file)
		return
	}

	// generate
	try {
		abc.tosvg(fn, file)
	} catch (e) {
		abc2svg.abort(e)
	}
} // do_file()
︙
Changes to core/abc2svg.js.
︙
110
111
112
113
114
115
116
117

118
119
120

121
122
123
124
125
126
127
128


129
130
131
132
133




134
135

136
137
138
139
140
141
142
143
144
110
111
112
113
114
115
116

117



118








119
120





121
122
123
124
125

126


127
128
129
130
131
132
133







-
+
-
-
-
+
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
+
+
+
+

-
+
-
-







abc2svg.b40_m = new Int8Array(			// base-40 to midi
//			 C		   D
		[-2, -1, 0, 1, 2, 0, 0, 1, 2, 3, 4, 0,
//	      E		     F		       G
	2, 3, 4, 5, 6, 3, 4, 5, 6, 7, 0, 5, 6, 7, 8, 9, 0,
//	      A			    B
	7, 8, 9, 10, 11, 0, 9, 10, 11, 12, 13 ])
abc2svg.b40k =  new Int8Array(		// base-40 interval to possible transposition
abc2svg.b40l5 = new Int8Array([			// base-40 to line of fifth
//		        C		  D
		[36, 1, 2, 3, 8, 2, 2, 7, 8,13,14, 2,
//		    37
//		  C			  D
//	       E	      F		        G
	 8,13,14,19,20,13,14,19,20,25, 2,19,24,25,30,31, 2,
//					    20
//	       A		 B
	25,30,31,36,37, 2,31,36,37, 2, 3 ])
//				    2
abc2svg.b40sf = new Int8Array(		// base-40 interval to key signature
//		        C		   D
	-14, -7,  0,  7, 14,  0,-12, -5,  2,  9, 16,  0,
//		  E		      F			      G	
		[-2,-7, 0, 7, 2, 88, 0,-5, 2,-3, 4, 88,
//	       E	      F		        G
	 2,-3, 4,-1, 6,-3, 4,-1, 6, 1,88,-1,-6, 1,-4, 3,88,
//	       A		 B
	 1,-4, 3,-2, 5,88, 3,-2, 5, 0, 7 ])
	-10, -3,  4, 11, 18,-15, -8, -1,  6, 13,  0,-13, -6,  1,  8, 15,  0,
//		  A			  B
	-11, -4,  3, 10, 17,  0, -9, -2,  5, 12, 19 ])

abc2svg.isb40 = new Int8Array(		// interval with sharp to base-40 interval
	[0, 1, 6,11,12,17,18,23,28,29,34,35])
	[0, 1, 6,7,12,17,18,23,24,29,30,35])
abc2svg.ifb40 = new Int8Array(		// interval with flat to base-40 interval
	[0, 5, 6,11,12,17,22,23,28,29,34,39])

abc2svg.pab40 = function(p, a) {
	p += 19				// staff pitch from C-1
   var	b40 = ((p / 7) | 0) * 40 + abc2svg.p_b40[p % 7]
	if (a && a != 3)		// if some accidental, but not natural
		b40 += a
	return b40
︙
175
176
177
178
179
180
181




182
183
184
185
186
187
188
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181







+
+
+
+







	"aug7": "+7",
	"7+5": "+7",
	"7#5": "+7",
	"sus": "sus4",
	"7sus": "7sus4"
} // ch_alias

// global fonts
abc2svg.font_tb = []	// fonts - index = font.fid
abc2svg.font_st = {}	// font style => font_tb index for incomplete user fonts

// font weight
// reference:
//	https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight
abc2svg.ft_w = {
	thin: 100,
	extralight: 200,
	light: 300,
︙
239
240
241
242
243
244
245
246



247
248
249
250
251
252
253
232
233
234
235
236
237
238

239
240
241
242
243
244
245
246
247
248







-
+
+
+







    // constants
    var	C = abc2svg.C;

	// mask some unsafe functions
    var	require = empty_function,
	system = empty_function,
	write = empty_function,
	XMLHttpRequest = empty_function;
	XMLHttpRequest = empty_function,
	std = null,
	os = null

// -- constants --

// staff system
var	OPEN_BRACE = 0x01,
	CLOSE_BRACE = 0x02,
	OPEN_BRACKET = 0x04,
︙
417
418
419
420
421
422
423
424
425

426
427
428
412
413
414
415
416
417
418


419


420







-
-
+
-
-

	}

	error(sev, s, msg, a1, a2, a3, a4)
}

// inject javascript code
function js_inject(js) {
	if (!/eval *\(|Function|setTimeout|setInterval/.test(js))
		eval('"use strict";\n' + js)
	eval('"use strict";\n' + js)
	else
		syntax(1, "Unsecure code")
}
Changes to core/deco.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - deco.js - decorations
//
// Copyright (C) 2014-2022 Jean-Francois Moine
// Copyright (C) 2014-2024 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.
︙
53
54
55
56
57
58
59
60
61
62
63
64





65
66
67
68
69
70
71
72
73
74
75
76
77












78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96














97
98
99
100


101
102
103
104
105
106
107
108
109







110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145


































146
147
148
149
150
151
152
53
54
55
56
57
58
59





60
61
62
63
64













65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82













83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98


99
100
101
102







103
104
105
106
107
108
109
110
111


































112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152







-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+






-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+


-
-
+
+


-
-
-
-
-
-
-
+
+
+
+
+
+
+


-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+








var	dd_tb = {},		// definition of the decorations
	a_de,			// array of the decoration elements
	cross			// cross voice decorations

// decorations - populate with standard decorations
var decos = {
	dot: "0 stc 6 1 1",
	tenuto: "0 emb 6 3 3",
	slide: "1 sld 3 7 0",
	arpeggio: "2 arp 12 10 2",
	roll: "3 roll 3,3 6 6",
	dot: "0 stc 6 1.5 1",
	tenuto: "0 emb 6 4 3",
	slide: "1 sld 3 7 1",
	arpeggio: "2 arp 12 10 3",
	roll: "3 roll 5,4 5 6",
	emphasis: "3 accent 3.5,3.5 4 4",
	lowermordent: "3 lmrd 4,4 5 5",
	uppermordent: "3 umrd 4,4 5 5",
	trill: "3 trl 14 5 5",
	upbow: "3 upb 10 5 5",
	downbow: "3 dnb 9 5 5",
	gmark: "3 grm 6 5 5",
	wedge: "0 wedge 8 3 3",	// (staccatissimo or spiccato)
	longphrase: "3 lphr 0 1 1",
	mediumphrase: "3 mphr 0 1 1",
	shortphrase: "3 sphr 0 1 1",
	turnx: "3 turnx 5,5 6 6",
	invertedturn: "3 turn 5,5 6 6",
	lowermordent: "3 lmrd 6,5 4 6",
	uppermordent: "3 umrd 6,5 4 6",
	trill: "3 trl 14 5 8",
	upbow: "3 upb 10,2 3 7",
	downbow: "3 dnb 9 4 6",
	gmark: "3 grm 7 4 6",
	wedge: "0 wedge 8 1.5 1",		// (staccatissimo or spiccato)
	longphrase: "5 lphr 0 1 16",
	mediumphrase: "5 mphr 0 1 16",
	shortphrase: "5 sphr 0 1 16",
	turnx: "3 turnx 7,2.5 5 6",
	invertedturn: "3 turn 7,2 5 6",
	"0": "3 fng 5,5 3 3 0",
	"1": "3 fng 5,5 3 3 1",
	"2": "3 fng 5,5 3 3 2",
	"3": "3 fng 5,5 3 3 3",
	"4": "3 fng 5,5 3 3 4",
	"5": "3 fng 5,5 3 3 5",
	plus: "3 dplus 7 3 3",
	"+": "3 dplus 7 3 3",
	accent: "3 accent 3.5,3.5 4 4",
	">": "3 accent 3.5,3.5 4 4",
	marcato: "3 marcato 9 3 3",
	"^": "3 marcato 9 3 3",
	mordent: "3 lmrd 4,4 5 5",
	open: "3 opend 10 3 3",
	snap: "3 snap 14 3 3",
	thumb: "3 thumb 14 3 3",
	turn: "3 turn 5,5 6 6",
	"trill(": "3 ltr 8 4 0",
	"trill)": "3 ltr 8 4 0",
	plus: "3 dplus 8,2 2 4",
	"+": "3 dplus 8,2 2 4",
	">": "5 accent 3.5,3.5 4 4",
	accent: "5 accent 3.5,3.5 4 4",
	emphasis: "5 accent 3.5,3.5 4 4",
	marcato: "3 marcato 9 5 5",
	"^": "3 marcato 9 5 5",
	mordent: "3 lmrd 6,5 4 6",
	open: "3 opend 8 3 3",
	snap: "3 snap 10 3 3",
	thumb: "3 thumb 10 3 3",
	turn: "3 turn 7,2.5 5 6",
	"trill(": "5 ltr 8 0 0",
	"trill)": "5 ltr 8 0 0",
	"8va(": "5 8va 12 6 6",
	"8va)": "5 8va 12 6 6",
	"8vb(": "7 8vb 12 6 6",
	"8vb)": "7 8vb 12 6 6",
	"8vb(": "4 8vb 10,5 6 6",
	"8vb)": "4 8vb 10,5 6 6",
	"15ma(": "5 15ma 12 9 9",
	"15ma)": "5 15ma 12 9 9",
	"15mb(": "7 15mb 12 9 9",
	"15mb)": "7 15mb 12 9 9",
	breath: "5 brth 0 1 20",
	caesura: "5 caes 0 1 10",
	short: "5 short 0 1 4",
	tick: "5 tick 0 1 4",
	coda: "5 coda 24 10 10",
	"15mb(": "4 15mb 12 9 9",
	"15mb)": "4 15mb 12 9 9",
	breath: "5 brth 0 1 16",
	caesura: "5 caes 0 1 20",
	short: "5 short 0 1 16",
	tick: "5 tick 0 1 16",
	coda: "5 coda 22,5 10 10",
	dacapo: "5 dacs 16 20 20 Da Capo",
	dacoda: "5 dacs 16 20 20 Da Coda",
	"D.C.": "5 dcap 16 10 10",
	"D.S.": "5 dsgn 16 10 10",
	"D.C.alcoda": "5 dacs 16 38 38 D.C. al Coda",
	"D.S.alcoda": "5 dacs 16 38 38 D.S. al Coda",
	"D.C.alfine": "5 dacs 16 38 38 D.C. al Fine",
	"D.S.alfine": "5 dacs 16 38 38 D.S. al Fine",
	fermata: "3 hld 12 7 7",
	fine: "5 dacs 16 10 10 Fine",
	invertedfermata: "4 hld 12 7 7",
	segno: "5 sgno 22 8 8",
	f: "6 f 18 4 4",
	ff: "6 ff 18 6 6",
	fff: "6 fff 18 9 9",
	ffff: "6 ffff 18 12 12",
	mf: "6 mf 18 9 9",
	mp: "6 mp 18 10 10",
	p: "6 p 18 5 5",
	pp: "6 pp 18 9 9",
	ppp: "6 ppp 18 13 13",
	pppp: "6 pppp 18 17 17",
	pralltriller: "3 umrd 4,4 5 5",
	sfz: "6 sfz 18 8 8",
	ped: "7 ped 18 6 10",
	"ped-up": "7 pedoff 12 4 4",
	"ped(": "7 lped 20 5 5",
	"ped)": "7 lped 20 5 5",
	"crescendo(": "6 cresc 18 0 0",
	"crescendo)": "6 cresc 18 0 0",
	"<(": "6 cresc 18 0 0",
	"<)": "6 cresc 18 0 0",
	"diminuendo(": "6 dim 18 0 0",
	"diminuendo)": "6 dim 18 0 0",
	">(": "6 dim 18 0 0",
	">)": "6 dim 18 0 0",
	"D.C.": "5 dcap 16,3 6 6",
	"D.S.": "5 dsgn 16,3 6 6",
	"D.C.alcoda": "5 dacs 16 32 32 D.C. al Coda",
	"D.S.alcoda": "5 dacs 16 32 32 D.S. al Coda",
	"D.C.alfine": "5 dacs 16 32 32 D.C. al Fine",
	"D.S.alfine": "5 dacs 16 32 32 D.S. al Fine",
	fermata: "5 hld 12 7.5 7.5",
	fine: "5 dacs 16 12 12 Fine",
	invertedfermata: "7 hld 12 8 8",
	segno: "5 sgno 22,2 5 5",
	f: "6 f 12,5 3 4",
	ff: "6 ff 12,5 8 5",
	fff: "6 fff 12,5 11 9",
	ffff: "6 ffff 12,5 15 12",
	mf: "6 mf 12,5 8 10",
	mp: "6 mp 12,5 9 10",
	p: "6 p 12,5 3 6",
	pp: "6 pp 12,5 8 9",
	ppp: "6 ppp 12,5 14 11",
	pppp: "6 pppp 12,5 14 17",
	pralltriller: "3 umrd 6,5 4 6",
	sfz: "6 sfz 12,5 9 9",
	ped: "6 ped 9 6 10",
	"ped-up": "6 pedoff 9 4 4",
	"ped(": "7 lped 14 1 1",
	"ped)": "7 lped 14 1 1",
	"crescendo(": "6 cresc 15,2 0 0",
	"crescendo)": "6 cresc 15,2 0 0",
	"<(": "6 cresc 15,2 0 0",
	"<)": "6 cresc 15,2 0 0",
	"diminuendo(": "6 dim 15,2 0 0",
	"diminuendo)": "6 dim 15,2 0 0",
	">(": "6 dim 15,2 0 0",
	">)": "6 dim 15,2 0 0",
	"-(": "8 gliss 0 0 0",
	"-)": "8 gliss 0 0 0",
	"~(": "8 glisq 0 0 0",
	"~)": "8 glisq 0 0 0",
// internal
//	color: "10 0 0 0 0",
	invisible: "32 0 0 0 0",
︙
187
188
189
190
191
192
193
194

195
196
197
198
199
200
201
187
188
189
190
191
192
193

194
195
196
197
198
199
200
201







-
+







		null, null, null,
		d_upstaff,	// 3 - tied to note
		d_upstaff	// 4 (below the staff)
	],
	f_staff = [
		null, null, null, null, null,
		d_upstaff,	// 5 (above the staff)
		d_pf,		// 6 - tied to staff (dynamic marks)
		d_upstaff,	// 6 - tied to staff (dynamic marks)
		d_upstaff	// 7 (below the staff)
	]

/* -- get the max/min vertical offset -- */
function y_get(st, up, x, w) {
	var	y,
		p_staff = staff_tb[st],
︙
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424


425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455

456
457
458
459
460
461
462
324
325
326
327
328
329
330



























































































331
332

333
334
335
336
337













338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-


-
+
+



-
-
-
-
-
-
-
-
-
-
-
-
-















+







	de.has_val = true;
	de.val = h;
//	de.x = s.x - xc;
	de.x -= xc;
	de.y = 3 * ((s.notes[0].pit + s.notes[s.nhd].pit) / 2 - 18) - h / 2 - 3
}

// special case for long dynamic decorations
function d_cresc(de) {
	if (de.ldst)			// skip start of deco
		return
    var	up, dx, x2, i, de3,
	dd = de.dd,
	s2 = de.s,
	de2 = de.start,			// start of the deco
	s = de2.s,
	x = s.x + 3			// x left

	de.st = s2.st;
	de.lden = false;		/* old behaviour */
	de.has_val = true;
	if (dd.ty == '^')
		up = 1
	else if (dd.ty != '_')
		up = up6(s2, s2.pos.dyn)
	if (up)
		de.up = true

	// shift the starting point if any dynamic mark on this symbol
	i = de2.ix
	while (--i >= 0) {
		de3 = a_de[i]
		if (!de3 || de3.s != s)
			break
	}
	while (1) {
		i++
		de3 = a_de[i]
		if (!de3 || de3.s != s)
			break
		if (de3 == de || de3 == de2)
			continue
		if (!(de.up ^ de3.up)
		 && f_staff[de3.dd.func]) {	// if dynamic mark
//			x2 = de3.x + de3.val + 4
			x2 = de3.x + de3.dd.wr + 2
			if (x2 > x)
				x = x2
			break
		}
	}

	if (de.defl.noen) {		/* if no decoration end */
		dx = de.x - x
		if (dx < 20) {
			x = de.x - 20 - 3;
			dx = 20
		}
	} else {

		// shift the ending point if any dynamic mark
		x2 = s2.x
		i = de.ix
		while (--i > 0) {
			de3 = a_de[i]
			if (!de3 || de3.s != s2)
				break
		}
		while (1) {
			i++
			de3 = a_de[i]
			if (!de3 || de3.s != s2)
				break
			if (de3 == de || de3 == de2)
				continue
			if (!(de.up ^ de3.up)
			 && f_staff[de3.dd.func]) {	// if dynamic mark
				x2 -= de3.dd.wl
				break
			}
		}
		dx = x2 - x - 4
		if (dx < 20) {
			x -= (20 - dx) * .5;
			dx = 20
		}
	}

	de.val = dx;
	de.x = x;
	de.y = y_get(de.st, up, x, dx)
	if (!up)
		de.y -= dd.h
	else
		de.y += dd.hd
	/* (y_set is done later in draw_deco_staff) */
}

/* 0: near the note (dot, tenuto) */
function d_near(de) {
	var	y, up,
	var	y,
		up = de.up,
		s = de.s,
		dd = de.dd

	if (dd.str) {			// annotation like decoration
//		de.x = s.x;
//		de.y = s.y;
		return
	}
	if (dd.ty == '^')
		up = 1
	else if (dd.ty == '_')
		up = 0
	else if (s.multi)
		up = s.multi > 0
	else
		up = s.stem < 0
	y = up ? s.ymx : s.ymn
	if (y > 0 && y < 24) {
		y = (((y + 9) / 6) | 0) * 6 - 6	// between lines
	}
	if (up) {
		y += dd.hd
		s.ymx = y + dd.h
	} else if (dd.name[0] == 'w') {		// wedge (no descent)
		de.inv = true
		y -= dd.h
		s.ymn = y
	} else {
		y -= dd.h
		s.ymn = y - dd.hd
	}
	de.x -= dd.wl
	de.y = y
	if (s.type == C.NOTE)
		de.x += s.notes[s.stem >= 0 ? 0 : s.nhd].shhd
	if (dd.name[0] == 'd') {		// if dot (staccato)
	    if (!(s.beam_st && s.beam_end)) {	// if in a beam sequence
		if (up) {
			if (s.stem > 0)
︙
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
371
372
373
374
375
376
377

















































378
379
380
381
382
383
384







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







				s.ymx = de.y + dd.h
			}
		}
	    }
	}
}

/* 6: dynamic marks */
function d_pf(de) {
	var	dd2, x2, x, up,
		s = de.s,
		dd = de.dd,
		de_prev;

	// don't treat here the long decorations
	if (de.ldst)			// if long deco start
		return
	if ((de.pos & C.SL_ALI_MSK) == C.SL_CLOSE
	 || ((de.pos & C.SL_ALI_MSK) == 0
	  && s.fmt.dynalign < 0)) {	// if no dynalign
		d_upstaff(de)		// then, do as above/below the staff
		return
	}
	if (de.start) {			// if long decoration
		d_cresc(de)
		return
	}

	de.val = dd.wl + dd.wr;
	up = up6(s, de.pos)
	if (up)
		de.up = true;
	x = s.x
	if (de.ix > 0) {
		de_prev = a_de[de.ix - 1]
		if (de_prev.s == s
		 && ((de.up && !de_prev.up)
		  || (!de.up && de_prev.up))) {
			dd2 = de_prev.dd
			if (f_staff[dd2.func]) {	/* if dynamic mark */
				x2 = de_prev.x + de_prev.val + 4;
				if (x2 > x)
					x = x2
			}
		}
	}

	de.x = x;
	de.y = y_get(s.st, up, x - dd.wl, de.val)
	if (!up)
		de.y -= dd.h
	else
		de.y += dd.hd
	/* (y_set is done later in draw_deco_staff) */
}

/* 1: special case for slide */
function d_slide(de) {
	var	m, dx,
		s = de.s,
		yc = s.notes[0].pit,
		xc = 5

︙
556
557
558
559
560
561
562
563

564
565

566
567
568
569
570


























































571
572
573
574
575
576
577
578
579
580
581

582
583
584
585
586
587
588
589
590
591
592
593

594
595
596
597

598
599
600
601
602
603
604
605
606
607


608
609

610
611
612


613
614

615
616
617
618
619
620
621
405
406
407
408
409
410
411

412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485




486












487




488
489
490
491
492
493
494
495
496


497
498


499



500
501


502
503
504
505
506
507
508
509







-
+


+





+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
+








-
-
+
+
-
-
+
-
-
-
+
+
-
-
+







	de.y = 3 * (yc - 18)
}

// special case for long decoration
function d_trill(de) {
	if (de.ldst)
		return
    var	up, y, w, tmp,
    var	y, w, tmp,
	dd = de.dd,
	de2 = de.prev,
	up = de.start.up,
		s2 = de.s,
		st = s2.st,
		s = de.start.s,
		x = s.x

	// shift the starting point of a long decoration
	// in the cases "T!trill(!" and "!pp!!<(!"
	// (side effect on x)
	function sh_st() {
	    var	de3,
		de2 = de.start,			// start of the decoration
		s = de2.s,
		i = de2.ix			// index of the current decoration

		while (--i >= 0) {
			de3 = a_de[i]
			if (!de3 || de3.s != s)
				break
		}
		while (1) {			// loop on the decorations of the symbol
			i++
			de3 = a_de[i]
			if (!de3 || de3.s != s)
				break
			if (de3 == de2)
				continue
			if (!(up ^ de3.up)
			 && (de3.dd.name == "trill"
			  || de3.dd.func == 6)) {	// dynamic
				x += de3.dd.wr + 2
				break
			}
		}
	} // sh_st()

	// shift the ending point of a long decoration
	// (side effect on w)
	function sh_en() {
	    var	de3,
		i = de.ix			// index of the current decoration

		while (--i > 0) {
			de3 = a_de[i]
			if (!de3 || de3.s != s2)
				break
		}
		while (1) {			// loop on the decorations of the symbol
			i++
			de3 = a_de[i]
			if (!de3 || de3.s != s2)
				break
//			if (de3 == de || de3 == de2)
			if (de3 == de)
				continue
			if (!(up ^ de3.up)
			 && de3.dd.func == 6) {	// if dynamic mark
				w -= de3.dd.wl
				break
			}
		}
	} //sh_en()

	// d_trill()
	if (de2) {			// same height
		x = de2.s.x + de.dd.wl + 2
		de2.val -= de2.dd.wr
		if (de2.val < 8)
			de2.val = 8
	}
	de.st = st

	switch (dd.func) {
	case 5:
		up = 1
	de.up = up
		break
	case 4:
	case 7:
		break
	case 3:			// tied to note
	case 6:			// dynamic mark
			if (dd.func == 6)
				up = up6(s, de.pos)
			else
				up = up3(s, de.pos)
			break
	}

	if (dd.ty == '^')
		up = 1
	else if (dd.ty == '_')
		up = 0
	sh_st()				// shift the starting point?

	if (de.defl.noen) {		/* if no decoration end */
		w = de.x - x
		if (w < 20) {
			x = de.x - 20 - 3;
			w = 20
		}
	} else {
		w = s2.x - x - 6
		if (s2.type == C.NOTE)
		w = s2.x - x - 4
		sh_en(de)		// shift the ending point?
			w -= 6
		if (w < 10) {
		if (w < 20)
			x -= 10 - w
			w = 10
		}
			w = 20
	}
	}
	y = y_get(st, up, x - dd.wl - 5, w)
	y = y_get(st, up, x - dd.wl, w)
	if (up) {
		tmp = staff_tb[s.st].topbar + 2
		if (y < tmp)
			y = tmp
	} else {
		tmp = staff_tb[s.st].botbar - 2
		if (y > tmp)
︙
639
640
641
642
643
644
645
646
647
648


649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667


668
669
670
671

672
673
674
675
676
677
678
679
680
681
682
683
684

685
686
687
688

689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736









737
738
739
740




741
742
743
744
745
746
747
748
749
527
528
529
530
531
532
533

534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555

556
557
558
559
560

561


562
563
564
565
566
567
568
569
570
571

572
573
574
575

576
577
578
579
580
581
582
583
584
585
586
587
588
589



590
591
592
593
594
595
596
597
598
599
600
601


602
603
604
605
606
607


608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626




627
628
629
630
631

632
633
634
635
636
637
638







-


+
+


















-
+
+



-
+
-
-










-
+



-
+













-
-
-












-
-






-
-










+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+

-







	}

	de.lden = false;
	de.has_val = true;
	de.val = w;
	de.x = x;
	de.y = y
	de.up = up
	if (up)
		y += dd.h;
	else
		y -= dd.hd
	y_set(st, up, x, w, y)
	if (up)
		s.ymx = s2.ymx = y
	else
		s.ymn = s2.ymn = y
}

/* 3, 4, 5, 7: above (or below) the staff */
function d_upstaff(de) {

	// don't treat here the long decorations
	if (de.ldst)			// if long deco start
		return
	if (de.start) {			// if long decoration
		d_trill(de)
		return
	}

    var	y, up, inv,
    var	y, inv,
	up = de.up,
	s = de.s,
	dd = de.dd,
	x = de.x,
	w = dd.wl + dd.wr,
	w = dd.wl + dd.wr
	stafft = staff_tb[s.st].topbar + 2 + dd.hd,
	staffb = staff_tb[s.st].botbar - 2 - dd.h

	// glyphs inside the staff
	switch (dd.glyph) {
	case "brth":
	case "caes":
	case "lphr":
	case "mphr":
	case "sphr":
	case "short":
	case "tick":
		y = stafft
		y = staff_tb[s.st].topbar + 2 + dd.hd
		if (s.type == C.BAR) {
			s.invis = 1
		} else {
		if (dd.glyph == "brth" && y < s.ymx)
			if (dd.glyph == "brth" && y < s.ymx)
				y = s.ymx
			for (s = s.ts_next; s; s = s.ts_next)
				if (s.seqst)
					break
			x += ((s ? s.x : realwidth) - x) * .45
		}
		de.x = x
		de.y = y
		return
	}

	if (s.nhd)
		x += s.notes[s.stem >= 0 ? 0 : s.nhd].shhd;
	de.up = up = (dd.func == 4 || dd.func == 7) ? 0
			: dd.func == 6 ? up6(s, de.pos)
					: up3(s, de.pos)

	switch (dd.ty) {
	case '@':
	case '<':
	case '>':
		y = de.y
		break
	}
	if (y == undefined) {
		if (up) {
			y = y_get(s.st, true, x - dd.wl, w)
					+ dd.hd
			if (y < stafft)
				y = stafft
			if (de.y > y)
				y = de.y
			s.ymx = y + dd.h
		} else {
			y = y_get(s.st, false, x - dd.wl, w)
				- dd.h
			if (y > staffb)
				y = staffb
			if (de.y < y)
				y = de.y
			if (dd.name == "fermata"
			 || dd.glyph == "accent"
			 || dd.glyph == "roll")
				de.inv = 1
			s.ymn = y - dd.hd
		}
	}

	if (dd.wr > 5 && x > realwidth - dd.wr)
		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 (y >= stafft)
			y_set(s.st, 1, x - dd.wl, w, y + dd.h)
		else if (y <= staffb)
			y_set(s.st, 0, x - dd.wl, w, y - dd.hd)
	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.x = x;
	de.y = y
}

// add a decoration
/* syntax:
 *	%%deco <name> <c_func> <glyph> <h> <wl> <wr> [<str>]
 * "<h>" may be followed by ",<hd>" (descent)
︙
826
827
828
829
830
831
832
833
834



835
836




837
838
839
840
841
842
843
715
716
717
718
719
720
721


722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737







-
-
+
+
+


+
+
+
+







	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] == '@'
		 && !str.match(/^@([0-9.-]+),([0-9.-]+);?/)) {
		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)
		dd.str = nm
︙
928
929
930
931
932
933
934
935

936
937
938
939
940
941
942
822
823
824
825
826
827
828

829
830
831
832
833
834
835
836







-
+







		dd.ty = ty
	}
	return dd
} // get_dd()

/* -- convert the decorations -- */
function deco_cnv(s, prev) {
    var	j, dd, nm, note, s1, court
    var	i, j, dd, nm, note, s1, court

	while (1) {
		nm = a_dcn.shift()
		if (!nm)
			break
		dd = get_dd(nm)
		if (!dd)
︙
953
954
955
956
957
958
959













960
961
962
963
964
965
966
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873







+
+
+
+
+
+
+
+
+
+
+
+
+







		case 1:			// slide
		case 2:			// arp
//			if (s.type != C.NOTE && s.type != C.REST) {
			if (!s.notes) {
				error(1, s, errs.must_note_rest, nm)
				continue
			}
			break
		case 4:			// below the staff
		case 5:			// above the staff
			i = nm.match(/1?[85]([vm])([ab])([()])/)
			if (i) {				// if ottava
				j = i[1] == 'v' ? 1 : 2
				if (i[2] == 'b')
					j = -j
				if (!s.ottava)
					s.ottava = []
				s.ottava[i[3] == '(' ? 0 : 1] = j
				glovar.ottava = 1 //true
			}
			break
		case 8:			// gliss
			if (s.type != C.NOTE) {
				error(1, s, errs.must_note, nm)
				continue
			}
			note = s.notes[s.nhd] // move to the upper note of the chord
︙
1060
1061
1062
1063
1064
1065
1066




1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081




1082
1083
1084
1085
1086
1087




1088
1089
1090
1091
1092
1093
1094
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013







+
+
+
+















+
+
+
+






+
+
+
+







		case 40:		/* stemless */
			s.stemless = true
			break
		case 41:		/* rbend */
			s.rbstop = 2	// with end
			break
		case 42:		// editorial
			if (s.type != C.NOTE) {
				error(1, s, errs.must_note, nm)
				continue
			}
			if (!s.notes[0].acc)
				continue
			nm = "sacc" + s.notes[0].acc.toString() // small accidental
			dd = dd_tb[nm]
			if (!dd) {
				dd = deco_def(nm)
				if (!dd) {
					error(1, s, errs.bad_val, "!editorial!")
					continue
				}
			}
			delete s.notes[0].acc
			curvoice.acc[s.notes[0].pit + 19] = 0	// ignore the accidental
			break
		case 43:		// courtesy
			if (s.type != C.NOTE) {
				error(1, s, errs.must_note, nm)
				continue
			}
			j = curvoice.acc[s.notes[0].pit + 19]
			if (s.notes[0].acc || !j)
				continue
			court = 1			// defer
			break
		case 44:		// cross-voice ties
			if (s.type != C.NOTE) {
				error(1, s, errs.must_note, nm)
				continue
			}
			do_ctie(nm, s, s.notes[0])	// (only one note for now)
			continue
//		default:
//			break
		}

		// add the decoration in the symbol
︙
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135



1136
1137
1138
1139
1140
1141
1142
1045
1046
1047
1048
1049
1050
1051

1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063







-


+
+
+







		default:
//		case 2:			// arpeggio
//		case 5:			// trill
//		case 7:			// d_cresc
			error(1, s, "Cannot have !$1! on a head", nm)
			continue
		case 9:			// head replacement
		case 32:		// invisible
			nt.invis = true
			break
		case 32:		// invisible
			nt.invis = true
			continue
		case 10:		// color
			nt.color = nm
			continue
		case 40:		// stemless chord (abcm2ps behaviour)
			s.stemless = true
			continue
		case 44:		// cross-voice ties
︙
1161
1162
1163
1164
1165
1166
1167
1168

1169
1170


1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183


1184
1185
1186
1187
1188
1189
1190
1191
1192
1193





1194
1195
1196
1197
1198
1199

1200
1201
1202
1203
1204

1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226

1227
1228
1229
1230
1231
1232
1233
1082
1083
1084
1085
1086
1087
1088

1089
1090

1091
1092
1093
1094
1095
1096
1097
1098
1099



1100


1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122

1123
1124
1125
1126
1127

1128
1129
1130
1131
1132
1133
1134
1135


1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147

1148
1149
1150
1151
1152
1153
1154
1155







-
+

-
+
+







-
-
-

-
-
+
+










+
+
+
+
+





-
+




-
+







-
-












-
+







		de = a_de[i]
		if (de.s == s)
			de.x += dx
	}
}

/* -- adjust the symbol width -- */
function deco_width(s) {
function deco_width(s, wlnt) {
    var	dd, i, w,
		wl = 0,
	wl = wlnt,
	wr = s.wr,
		a_dd = s.a_dd,
		nd = a_dd.length

	for (i = 0; i < nd; i++) {
		dd =  a_dd[i]
		switch (dd.func) {
		case 1:			/* slide */
			if (wl < 7)
				wl = 7
			break
		case 2:			/* arpeggio */
			if (wl < 14)
				wl = 14
			if (wl < 12)
				wl = 12
			break
		case 3:
			switch (dd.glyph) {
			case "brth":
			case "lphr":
			case "mphr":
			case "sphr":
				if (s.wr < 20)
					s.wr = 20
				break
			default:
				w = dd.wl + 2
				if (wl < w)
					wl = w
				break
			}
			// fall thru
		default:
			switch (dd.ty) {
			case '<':
				w = dd.wl + dd.wr + 6
				w = wlnt + dd.wl + dd.wr + 6
				if (wl < w)
					wl = w
				break
			case '>':
				w = dd.wl + dd.wr + 8
				w = wr + dd.wl + dd.wr + 6
				if (s.wr < w)
					s.wr = w
				break
			}
			break
		}
	}
	if (wl && s.prev && s.prev.type == C.BAR)
		wl -= 3
	return wl
}

// compute the width of decorations in chord
function deco_wch(nt) {
    var	i, w, dd,
	wl = 0,
	n = nt.a_dd.length

	for (i = 0; i < n; i++) {
		dd = nt.a_dd[i]
		if (dd.ty == '<') {
			w = dd.wl + dd.wr + 8
			w = dd.wl + dd.wr + 4
			if (w > wl)
				wl = w
		}
	}
	return wl
} // deco_wch()

︙
1275
1276
1277
1278
1279
1280
1281
1282
1283


1284
1285
1286
1287
1288
1289
1290
1197
1198
1199
1200
1201
1202
1203


1204
1205
1206
1207
1208
1209
1210
1211
1212







-
-
+
+







			set_sscale(s.st)
		else
			set_scale(s);

		st = de.st;
		if (!staff_tb[st].topbar)
			continue		// invisible staff
		x = de.x;
		y = de.y + staff_tb[st].y
		x = de.x + (dd.dx || 0)
		y = de.y + staff_tb[st].y + (dd.dy || 0)

		// update the coordinates if head decoration
		if (de.m != undefined) {
			note = s.notes[de.m];
			if (note.shhd)
				x += note.shhd * stv_g.scale;

︙
1324
1325
1326
1327
1328
1329
1330

1331
1332
1333
1334





1335
1336
1337
1338

1339
1340
1341
1342
1343
1344
1345
1246
1247
1248
1249
1250
1251
1252
1253




1254
1255
1256
1257
1258
1259
1260
1261

1262
1263
1264
1265
1266
1267
1268
1269







+
-
-
-
-
+
+
+
+
+



-
+







					if (stv_g.scale != 1)
						y += stv_g.dy / 2
				}
			}
		}

		// check if user JS decoration
		if (user.deco) {
		uf = user[f]
		if (uf && typeof(uf) == "function") {
			uf(x, y, de)
			continue
			uf = user.deco[f]
			if (uf && typeof(uf) == "function") {
				uf.call(self, x, y, de)
				continue
			}
		}

		// check if user PS definition
		if (self.psdeco(f, x, y, de))
		if (self.psdeco(x, y, de))
			continue

		anno_start(s, 'deco')
//		if (de.flags.grace) {
//			g_open(x, y, 0, .7, de.inv ? -.7 : 0);
//			x = y = 0
//		} else
︙
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362



1363
1364
1365
1366
1367
1368
1369
1370

1371
1372
1373
1374
1375
1376
1377
1277
1278
1279
1280
1281
1282
1283



1284
1285
1286






1287

1288
1289
1290
1291
1292
1293
1294
1295







-
-
-
+
+
+
-
-
-
-
-
-

-
+







			 || stv_g.st < 0)	// or not staff scale
// || voice_tb[s.v].scale != 1)
				out_deco_val(x, y, f, de.val / stv_g.scale, de.defl)
			else
				out_deco_val(x, y, f, de.val, de.defl)
			if (de.cont)
				new_de.push(de.start)	// to be continued next line
		} else if (dd.str != undefined) {
			str = dd.str
			if (str[0] == '@') {
		} else if (dd.str != undefined		// string
			&& !tgls[dd.glyph]
			&& !glyphs[dd.glyph]) {		// with a class
				a = str.match(/^@([0-9.-]+),([0-9.-]+);?/);
				x += Number(a[1]);
				y += Number(a[2]);
				str = str.replace(a[0], "")
			}
//			out_deco_str(x, y + de.dy,	// - dd.h * .2,
			out_deco_str(x, y,		// - dd.h * .2,
					f, str)
					de)
		} else if (de.lden) {
			out_deco_long(x, y, de)
		} else {
			xygl(x, y, f)
		}
		if (stv_g.g)
			g_close();
︙
1402
1403
1404
1405
1406
1407
1408
1409

1410
1411
1412
1413
1414
1415
1416
1320
1321
1322
1323
1324
1325
1326

1327
1328
1329
1330
1331
1332
1333
1334







-
+







			de.s.x = de.x = x;
			de.defl.nost = true
		}
	}

	/* -- create the deco elements, and treat the near ones -- */
	function create_deco(s) {
	    var	dd, k, pos, de, x, y, v,
	    var	dd, k, pos, de, x, y, up,
		nd = s.a_dd.length

		if (s.y == undefined)
			s.y = 0			// (no y in measure bars)

/*fixme:pb with decorations above the staff*/
		for (k = 0; k < nd; k++) {
︙
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434

1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455

1456
1457
1458
1459
1460
1461
1462
1342
1343
1344
1345
1346
1347
1348

1349
1350

1351



1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368

1369
1370
1371
1372
1373
1374
1375
1376







-


-
+
-
-
-

















-
+







				if (dd.func >= 10)
					continue
				pos = 0
				break
			case 3:				/* d_upstaff */
			case 4:
			case 5:				// after slurs
			case 7:
				pos = s.pos.orn
				break
			case 6:				/* d_pf */
			case 6:				/* dynamic */
				pos = s.pos.vol
				break
			case 7:				/* d_cresc */
				pos = s.pos.dyn
				break
			}

			switch (dd.ty) {		// explicit position
			case '^':
				pos = (pos & ~0x07) | C.SL_ABOVE
				break
			case '_':
				pos = (pos & ~0x07) | C.SL_BELOW
				break
			case '<':
			case '>':
				pos = (pos & 0x07) | C.SL_CLOSE
				if (dd.ty == '<') {
					x -= dd.wr + 8
					if (s.notes[0].acc)
						x -= 5.5
						x -= 8
				} else {
					x += dd.wl + 8
				}
				y = 3 * (s.notes[0].pit - 18)
						- (dd.h - dd.hd) / 2
				break
			case '@':
︙
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481






























1482
1483
1484
1485
1486
1487
1488
1385
1386
1387
1388
1389
1390
1391




1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428







-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







			de = {
				s: s,
				dd: dd,
				st: s.st,
				ix: a_de.length,
				defl: {},
				x: x,
				y: y,
				pos: pos
//				dy: 0
			}
				y: y
			}
			if (pos)
				de.pos = pos

			up = 0 //false
			if (dd.ty == '^') {
				up = 1 //true
			} else if (dd.ty == '_') {
				;
			} else {
				switch (dd.func) {
				case 0:
					if (s.multi)
						up = s.multi > 0
					else
						up = s.stem < 0
					break
				case 3:
				case 5:
					up = up3(s, pos)
					break
				case 6:
				case 7:
					up = up6(s, pos)
					break
				}
			}
			de.up = up

			if (dd.name.indexOf("inverted") >= 0)
				de.inv = 1
			if (s.type == C.BAR && !dd.ty)
				de.x -= s.wl / 2 - 2
			a_de.push(de)
			if (dd.dd_en) {
				de.ldst = true
︙
1512
1513
1514
1515
1516
1517
1518
1519

1520
1521
1522
1523
1524
1525
1526
1527
1528
1529

1530


1531
1532



1533
1534
1535
1536
1537
1538
1539
1452
1453
1454
1455
1456
1457
1458

1459
1460
1461
1462
1463
1464
1465
1466
1467
1468

1469
1470
1471
1472


1473
1474
1475
1476
1477
1478
1479
1480
1481
1482







-
+









-
+

+
+
-
-
+
+
+







				s: s,
				dd: dd,
				st: s.st,
				m: m,
				ix: 0,
				defl: {},
				x: x,
				y: 3 * (note.pit - 18)
				y: 3 * (note.pit - 18) - (dd.h - dd.hd) / 2
//				dy: 0
			}

			if (dd.ty) {		// if explicit position
				if (dd.ty == '@') {
					de.x += dd.x
					de.y += dd.y
				} else {
					de.y -= (dd.h - dd.hd) / 2	// center
					if (dd.ty == '<')
					if (dd.ty == '<') {
						de.x -= dd.wr + 8
						if (s.notes[m].acc)
							x -= 8
					else if (dd.ty == '>')
						de.x += dd.wr + 8
					} else if (dd.ty == '>') {
						de.x += dd.wl + 8
					}
				}
			}

			a_de.push(de)
			if (dd.dd_en) {
				de.ldst = true
			} else if (dd.dd_st) {
︙
1636
1637
1638
1639
1640
1641
1642
1643

1644
1645
1646
1647
1648
1649
1650
1579
1580
1581
1582
1583
1584
1585

1586
1587
1588
1589
1590
1591
1592
1593







-
+







				st: de2.st,
				dd: de2.dd.dd_st,
				ix: a_de.length - 1,
//				x: s.x - s.wl - 4,
				y: s.y,
				ldst: true
			}
			de.x = de.s.x
			de.x = de.s.x + de.s.wr
			if (de2.m != undefined)
				de.m = de2.m;
			a_de.push(de);
			de2.start = de
		}
	} // ll_deco

︙
1701
1702
1703
1704
1705
1706
1707
1708

1709
1710
1711
1712
1713
1714
1715
1644
1645
1646
1647
1648
1649
1650

1651
1652
1653
1654
1655
1656
1657
1658







-
+







// -- define the music elements tied to the staff --
//	- decoration tied to the staves
//	- chord symbols
//	- repeat brackets
/* (the staves are not yet defined) */
/* (unscaled delayed output) */
function draw_deco_staff() {
    var	s, p_voice, y, i, v, de, dd,
    var	s, p_voice, y, i, v, de, dd, w,
	minmax = new Array(nstaff + 1),
	nd = a_de.length

	/* draw the repeat brackets */
	function draw_repbra(p_voice) {
		var s, s1, x, y, y2, i, p, w, wh, first_repeat;

︙
1731
1732
1733
1734
1735
1736
1737



1738

1739
1740
1741
1742
1743
1744

1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755

1756
1757
1758
1759
1760
1761
1762
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683

1684
1685
1686
1687
1688
1689

1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700

1701
1702
1703
1704
1705
1706
1707
1708







+
+
+
-
+





-
+










-
+







			for (;;) {
				if (!s.next)
					break
				s = s.next
				if (s.rbstop)
					break
			}
			x = s1.x
			if (s1.xsh)			// volta shift
				x += s1.xsh
			y2 = y_get(p_voice.st, true, s1.x, s.x - s1.x) + 2
			y2 = y_get(p_voice.st, true, x, s.x - x) + 2
			if (y < y2)
				y = y2

			// have room for the vertical lines and the repeat numbers
			if (s1.rbstart == 2) {
				y2 = y_get(p_voice.st, true, s1.x, 3) + 10
				y2 = y_get(p_voice.st, true, x, 3) + 10
				if (y < y2)
					y = y2
			}
			if (s.rbstop == 2) {
				y2 = y_get(p_voice.st, true, s.x - 3, 3) + 10
				if (y < y2)
					y = y2
			}
			if (s1.text) {
				wh = strwh(s1.text);
				y2 = y_get(p_voice.st, true, s1.x + 4, wh[0]) +
				y2 = y_get(p_voice.st, true, x + 4, wh[0]) +
						wh[1]
				if (y < y2)
					y = y2
			}
			if (s.rbstart)
				s = s.prev
		}
︙
1777
1778
1779
1780
1781
1782
1783


1784
1785
1786
1787
1788
1789
1790
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738







+
+







				s = s.next
				if (s.rbstop)
					break
			}
			if (s1 == s)
				break
			x = s1.x
			if (s1.xsh)			// volta shift
				x += s1.xsh
			if (cfmt.measurenb > 0 & s.bar_num
			 && s.bar_num % cfmt.measurenb)
				x += 6
			if (s.type != C.BAR) {
				w = s.rbstop ? 0 : s.x - realwidth + 4
			} else if ((s.bar_type.length > 1	// if complex bar
				 && s.bar_type != "[]")
︙
1823
1824
1825
1826
1827
1828
1829
1830

1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846


1847

1848

1849

1850

1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864

1865
1866
1867
1868

1869
1870
1871
















1872

1873
1874







1875
1876

1877
1878
1879
1880
1881
1882
1883
1884
1885
1886


1887
















1888
1889
1890
1891
1892
1893
1894
1771
1772
1773
1774
1775
1776
1777

1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793

1794
1795
1796
1797
1798
1799

1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815

1816
1817
1818
1819

1820
1821


1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839


1840
1841
1842
1843
1844
1845
1846
1847

1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860

1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883







-
+















-
+
+

+

+
-
+

+













-
+



-
+

-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
-
-
+
+
+
+
+
+
+

-
+










+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







			output+= 'h' + w.toFixed(1)
			if (s.rbstop == 2)
				output += 'v10';
			output += '"/>\n';
			y_set(s1.st, true, x, w, y + 2)

			if (s.rbstart)
				s = s.prev.prev
				s = s.prev
		}
	} // draw_repbra()

	/* create the decorations tied to the staves */
	for (i = 0; i <= nstaff; i++)
		minmax[i] = {
			ymin: 0,
			ymax: 0
		}
	for (i = 0; i < nd; i++) {
		de = a_de[i];
		dd = de.dd
		if (!dd)		// if error
			continue
		if (!f_staff[dd.func]	/* if not tied to the staff */
		 || de.m != undefined)	// or head decoration
		 || de.m != undefined	// or head decoration
		 || dd.ty == '<' || dd.ty == '>' || dd.ty == '@')
			continue

		f_staff[dd.func](de)
		if (dd.func != 6
		if (dd.dd_en)		// if start
		 || dd.dd_en)		// if start
			continue

		if ((de.pos & C.SL_ALI_MSK) == C.SL_ALIGN
		 || ((de.pos & C.SL_ALI_MSK) == 0
		  && de.s.fmt.dynalign > 0)) {	// if align
			if (de.up) {
				if (de.y > minmax[de.st].ymax)
					minmax[de.st].ymax = de.y
			} else {
				if (de.y < minmax[de.st].ymin)
					minmax[de.st].ymin = de.y
			}
		}
	}

	/* and, if wanted, set them at a same vertical offset */
	// set the same vertical offset of the dynamic marks
	for (i = 0; i < nd; i++) {
		de = a_de[i];
		dd = de.dd
		if (!dd)		// if error
		if (!dd)				// if error
			continue
		if (dd.dd_en		// if start
		 || !f_staff[dd.func])

		// if @x,y offsets, update the top and bottom of the staff
		if (dd.ty == '@') {
		    var	y2

			y = de.y
			if (y > 0) {
				y2 = y + dd.h + 2
				if (y2 > staff_tb[de.st].ann_top)
					staff_tb[de.st].ann_top = y2
			} else {
				y2 = y - dd.hd - 2
				if (y2 < staff_tb[de.st].ann_bot)
					staff_tb[de.st].ann_bot = y2

			}
			continue
		}
		if (dd.func == 6
		 &&((de.pos & C.SL_ALI_MSK) == C.SL_ALIGN
		if (dd.func != 6
		 || dd.ty == '<' || dd.ty == '>'
		 || dd.dd_en)				// if start
			continue

		w = de.val || (dd.wl + dd.wr)
		if ((de.pos & C.SL_ALI_MSK) == C.SL_ALIGN
		  || ((de.pos & C.SL_ALI_MSK) == 0
		   && de.s.fmt.dynalign > 0))) {	// if align
		   && de.s.fmt.dynalign > 0)) {		// if align
			if (de.up)
				y = minmax[de.st].ymax
			else
				y = minmax[de.st].ymin;
			de.y = y
		} else {
			y = de.y
		}
		if (de.up)
			y += dd.h;
		else
			y -= dd.hd
		y_set(de.st, de.up, de.x, de.val, y)
		y_set(de.st, de.up, de.x, w, y)
	}

	// second pass for pedal (under the staff)
	for (i = 0; i < nd; i++) {
		de = a_de[i]
		dd = de.dd
		if (!dd)			// if error
			continue
		if (dd.dd_en			// if start
		 || dd.name.slice(0, 3) != "ped")
			continue
		w = de.val || 10
		de.y = y_get(de.st, 0, de.x, w)
			- (dd.dd_st && cfmt.pedline ? 10 : dd.h)
		y_set(de.st, 0, de.x, w, de.y)	// (no descent)
	}

	draw_all_chsy()		// draw all chord symbols

	/* draw the repeat brackets */
	for (v = 0; v < voice_tb.length; v++) {
		p_voice = voice_tb[v]
︙
1948
1949
1950
1951
1952
1953
1954


1955

1956
1957
1958
1959
1960
1961
1962
1937
1938
1939
1940
1941
1942
1943
1944
1945

1946
1947
1948
1949
1950
1951
1952
1953







+
+
-
+







		     if (s.type != C.BAR || !s.bar_num) {
			any_nb = true;
			w = w0
			if (bar_num >= 10)
				w *= bar_num >= 100 ? 3 : 2
			if (gene.curfont.pad)
				w += gene.curfont.pad * 2
			x = (s.prev
				? s.prev.x + s.prev.wr / 2
			x = s.x - s.wl - w
				: s.x - s.wl) - w
			y = y_get(st, true, x, w) + 5
			if (y < staff_tb[st].topbar + 6)
				y = staff_tb[st].topbar + 6;
			y += gene.curfont.pad
			xy_str(x, y - gene.curfont.size * .2, bar_num.toString())
			y += gene.curfont.size + gene.curfont.pad
			y_set(st, true, x, w, y);
︙
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030














2031
2032

2033
2034
2035
2036


2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052

2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082

2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107

2108
2109
2110
2111

2112
2113
2114
2115
2116
2117
2118



2119
2120
2121
2122






2123
2124
2125


2126
2127


















































2009
2010
2011
2012
2013
2014
2015






2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030

2031
2032
2033


2034
2035
















2036






























2037


2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056




2057
2058
2059
2060
2061
2062
2063






2064
2065
2066
2067
2068
2069

2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080


2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130







-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+


-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-



















-
-
-
-
+




+

-
-
-
-
-
-
+
+
+



-
+
+
+
+
+
+



+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
	gene.nbar = bar_num

	if (font_size)
		param_set_font("measurefont", "* " + font_size.toString());
}

/* -- draw the parts and the tempo information -- */
/* (the staves are being defined) */
function draw_partempo(st, top) {
    var	s, s2, some_part, some_tempo, h, w, y,
	dy = 0,		/* put the tempo indication at top */
	ht = 0

// (unscaled delayed output)
function draw_partempo() {
    var	s, s2, some_part, some_tempo, h, w, y, st,
	sy = cur_sy

	// search the top staff
	for (st = 0; st <= nstaff; st++) {
		if (sy.st_print[st])
			break
	}
	if (st > nstaff)
		return				// no visible staff
	set_dscale(st, 1)			// no scale

	/* get the minimal y offset */
	var	ymin = staff_tb[st].topbar + 8,
    var	ymin = staff_tb[st].topbar + 2,
		dosh = 0,
		shift = 1,
		x = -100	// (must be negative for %%soloffs)

		x = -100,	// (must be negative for %%soloffs)
	yn = 0			// y min when x < 0
	for (s = tsfirst; s; s = s.ts_next) {
		if (s.type != C.TEMPO || s.invis)
			continue
		if (!some_tempo)
			some_tempo = s;
		w = s.tempo_wh[0]
		if (s.time == 0 && s.x > 40)	// at start of tune and no %%soloffs,
			s.x = 40;	// shift the tempo over the key signature
		y = y_get(st, true, s.x - 16, w)
		if (y > ymin)
			ymin = y
		if (x >= s.x - 16 && !(dosh & (shift >> 1)))
			dosh |= shift;
		shift <<= 1;
		x = s.x - 16 + w
	}

	if (some_tempo) {
		set_sscale(-1);
		set_font("tempo");
		ht = gene.curfont.size + 8;
		y = 2 - ht;
		h = y - ht
		if (dosh != 0)
			ht *= 2
		if (top < ymin + ht)
			dy = ymin + ht - top

		/* draw the tempo indications */
		for (s = some_tempo; s; s = s.ts_next) {
			if (s.type != C.TEMPO
			 || s.invis)		// (displayed by %%titleformat)
				continue
			if (user.anno_start || user.anno_stop) {
				s.wl = 16;
				s.wr = 30;
				s.ymn = (dosh & 1) ? h : y;
				s.ymx = s.ymn + 14;
				anno_start(s)
			}
			writempo(s, s.x - 16, (dosh & 1) ? h : y);
			anno_stop(s);
			dosh >>= 1
		}
	}

	/* then, put the parts */
	// output the parts
/*fixme: should reduce vertical space if parts don't overlap tempo...*/
	ymin = staff_tb[st].topbar + 6
	for (s = tsfirst; s; s = s.ts_next) {
		s2 = s.part
		if (!s2 || s2.invis)
			continue
		if (!some_part) {
			some_part = s;
			set_font("parts");
			h = gene.curfont.size + 2 +
				gene.curfont.pad * 2
		}
		if (s2.x == undefined)
			s2.x = s.x - 10
		w = strwh(s2.text)[0]
		y = y_get(st, true, s2.x, w + 3)
		if (ymin < y)
			ymin = y
	}
	if (some_part) {
		set_sscale(-1)
		ht += h
		if (top + dy < ymin + ht)
			dy = ymin + ht - top

		ymin *= staff_tb[st].staffscale
		for (s = some_part; s; s = s.ts_next) {
			s2 = s.part
			if (!s2 || s2.invis)
				continue
			w = strwh(s2.text)[0]
			if (user.anno_start || user.anno_stop) {
				s2.type = C.PART
				s2.p_v = s.p_v
				s2.v = s.v
				s2.st = s2.wl = 0
				s2.wr = strwh(s2.text)[0]
				s2.ymn = -ht
				s2.wl = 0
				s2.wr = w
				s2.ymn = ymin
				s2.ymx = s2.ymn + h
				anno_start(s2)
			}
			xy_str(s2.x, 2 - ht + gene.curfont.size * .22, s2.text)
			xy_str(s2.x,
				ymin + 2 + gene.curfont.pad + gene.curfont.size * .22,
				s2.text)
			y_set(st, 1, s2.x, w + 3, ymin + 2 + h)
			if (s2.x < 0)
				yn = ymin + 2 + h
			anno_stop(s2)
		}
	}

	// output the tempos
	return dy /= staff_tb[0].staffscale
}
	ymin = staff_tb[st].topbar + 6
	for (s = tsfirst; s; s = s.ts_next) {
		if (s.type != C.TEMPO || s.invis)
			continue
		if (!some_tempo)
			some_tempo = s
		w = s.tempo_wh[0]
//		if (s.time == 0 && s.x > 40)	// at start of tune and no %%soloffs,
//			s.x = 40	// shift the tempo over the key signature
		y = y_get(st, true, s.x - 16, w)
		if (s.x - 16 < 0)
			y = yn
		if (y > ymin)
			ymin = y
		if (x >= s.x - 16 && !(dosh & (shift >> 1)))
			dosh |= shift
		shift <<= 1
		x = s.x - 16 + w
	}
	if (some_tempo) {
		set_sscale(-1)
		set_font("tempo")
		h = gene.curfont.size
		ymin += 2
		ymin *= staff_tb[st].staffscale

		/* draw the tempo indications */
		for (s = some_tempo; s; s = s.ts_next) {
			if (s.type != C.TEMPO
			 || s.invis)		// (displayed by %%titleformat)
				continue
			w = s.tempo_wh[0]
			y = ymin
			if (dosh & 1)
				y += h
			if (user.anno_start || user.anno_stop) {
				s.wl = 16
//				s.wr = 30
				s.wr = w - 16
				s.ymn = y
				s.ymx = s.ymn + 14
				anno_start(s)
			}
			writempo(s, s.x - 16, y)
			anno_stop(s)
			y_set(st, 1, s.x - 16, w, y + h + 2)
			dosh >>= 1
		}
	}
}
Changes to core/draw.js.
︙
94
95
96
97
98
99
100
101

102
103
104
105
106
107
108
94
95
96
97
98
99
100

101
102
103
104
105
106
107
108







-
+







	[STEM_CH_MIN, STEM_CH_MIN,
		STEM_CH_MIN2, STEM_CH_MIN3, STEM_CH_MIN4, STEM_CH_MIN4]
]

// (possible hook)
Abc.prototype.calculate_beam = function(bm, s1) {
    var	s, s2, g, notes, nflags, st, v, two_staves, two_dir,
		x, y, ys, a, b, stem_err, max_stem_err,
	n, x, y, ys, a, b, stem_err, max_stem_err,
		p_min, p_max, s_closest,
		stem_xoff, scale,
		visible, dy

	if (!s1.beam_st) {	/* beam from previous music line */
		s = sym_dup(s1);
		lkvsym(s, s1);
︙
193
194
195
196
197
198
199
200
201


202
203
204
205
206
207


208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227







228

229
230
231
232
233
234
235
236
237

238
239
240
241
242


243
244
245
246
247
248










249
250
251
252
253












254
255
256
257
258
259
260
193
194
195
196
197
198
199


200
201
202
203
204
205


206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226

227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243

244
245
246

247
248
249
250
251





252
253
254
255
256
257
258
259
260
261





262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280







-
-
+
+




-
-
+
+



















-
+
+
+
+
+
+
+

+








-
+


-


+
+

-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+







	for (s = s1; ; s = s.next) {
		if (s.type != C.NOTE)
			continue
		if ((scale = s.p_v.scale) == 1)
			scale = staff_tb[s.st].staffscale
		if (s.stem >= 0) {
			x = stem_xoff + s.notes[0].shhd
			if (s.notes[s.nhd].pit > p_max) {
				p_max = s.notes[s.nhd].pit;
			if (s.notes[s.nhd].midi > p_max) {
				p_max = s.notes[s.nhd].midi
				s_closest = s
			}
		} else {
			x = -stem_xoff + s.notes[s.nhd].shhd
			if (s.notes[0].pit < p_min) {
				p_min = s.notes[0].pit;
			if (s.notes[0].midi < p_min) {
				p_min = s.notes[0].midi
				s_closest = s
			}
		}
		s.xs = s.x + x * scale;
		if (s == s2)
			break
	}

	// have flat beams on grace notes when asked
	if (s.grace && s1.fmt.flatbeams)
		a = 0

	// if a note inside the beam is the closest to the beam, the beam is flat
	else if (!two_dir
	      && notes >= 3
	      && s_closest != s1 && s_closest != s2)
		a = 0

	y = s1.ys + staff_tb[st].y
	if (a == undefined)
	if (a == undefined) {
		if (two_dir
		 && s1.stem != s2.stem
		 && s1.st == s2.st) {		// if inverted stems,
			y -= 5 * s1.stem	// remove the beam depth
			s2.ys -= 5 * s2.stem			
		}
		a = (s2.ys + staff_tb[s2.st].y - y) / (s2.xs - s1.xs)
	}

	if (a != 0) {
		a = s1.fmt.beamslope * a /
			(s1.fmt.beamslope + Math.abs(a)) // max steepness for beam
		if (a > -.04 && a < .04)
			a = 0				// slope too low
	}

	// pivot around the middle of the beam
	// center the main beam
	b = (y + s2.ys + staff_tb[s2.st].y) / 2 - a * (s2.xs + s1.xs) / 2

/*fixme: have a look again*/
	/* have room for the symbols in the staff */
	max_stem_err = 0;		/* check stem lengths */

	// when 2 directions, check if all beams are on the same side of the main beam
	s = s1
	if (two_dir) {				/* 2 directions */
/*fixme: more to do*/
		ys = ((s1.grace ? 3.5 : BEAM_SHIFT) * (nflags - 1) +
			BEAM_DEPTH) * .5
		if (s1.nflags == s2.nflags)
	if (two_dir) {
		n = 1
		while (1) {
			if (s.stem != s1.stem
			 && (s.nflags == 1
			  || s.beam_br1  || s.beam_br2)) {
				n = 0
				break
			}
			if (s == s2)
			;
		else if (s1.stem != s2.stem && s1.nflags < s2.nflags)
			b += ys * s2.stem
		else
			b += ys * s1.stem
				break
			s = s.next
		}
		if (n)				// same side
			n = (s1.nflags + s2.nflags)
				* (s1.nflags >= s2.nflags ? s1.stem : s2.stem)
					/ 4
		else				// different sides
			n = -(s1.nflags * s1.stem + s2.nflags * s2.stem)
					/ 2
		b += ((s1.grace ? 3.5 : BEAM_SHIFT) * n
				+ BEAM_DEPTH * s1.stem) / 2
	} else if (!s1.grace) {		/* normal notes */
		var beam_h = BEAM_DEPTH + BEAM_SHIFT * (nflags - 1)
//--fixme: added for abc2svg
		while (s.ts_prev
		    && s.ts_prev.type == C.NOTE
		    && s.ts_prev.time == s.time
		    && s.ts_prev.x > s1.xs)
︙
335
336
337
338
339
340
341
342

343
344
345
346
347
348
349
350
351
352
353
354
355
356
357

358
359
360
361
362
363
364
355
356
357
358
359
360
361

362

363
364
365
366
367
368
369
370
371
372
373
374
375

376
377
378
379
380
381
382
383







-
+
-













-
+







				break
		}
	}

	if (max_stem_err > 0)		/* shift beam if stems too short */
		b += s1.stem * max_stem_err

	/* have room for the gracenotes, bars and clefs */
	// have room for the gracenotes and clefs
/*fixme: test*/
    if (!two_staves && !two_dir)
	for (s = s1.next; ; s = s.next) {
		switch (s.type) {
		case C.REST:		/* cannot move rests in multi-voices */
			if (!s.multi)
				break
			g = s.ts_next
			if (!g || g.st != st
			 || (g.type != C.NOTE && g.type != C.REST))
				break
//fixme:too much vertical shift if some space above the note
//fixme:this does not fix rest under beam in second voice (ts_prev)
			/*fall thru*/
		case C.BAR:
//		case C.BAR:
			if (s.invis)
				break
			/*fall thru*/
		case C.CLEF:
			y = a * s.x + b
			if (s1.stem > 0) {
				y = s.ymx - y
︙
456
457
458
459
460
461
462
463

464

465
466
467
468
469
470
471
475
476
477
478
479
480
481

482
483
484
485
486
487
488
489
490
491







-
+

+







	bm.nflags = nflags
	return true
}

/* -- draw the beams for one word -- */
/* (the staves are defined) */
function draw_beams(bm) {
	var	s, i, beam_dir, shift, bshift, bstub, bh, da, bd,
    var	s, i, beam_dir, shift, bshift, bstub, bh, da, bsh,
		k, k1, k2, x1,
	osh = 0,				// shift other side
		s1 = bm.s1,
		s2 = bm.s2

	/* -- draw a single beam -- */
	function draw_beam(x1, x2, dy, h, bm,
				 n) {		/* beam number (1..n) */
		var	y1, dy2,
︙
516
517
518
519
520
521
522
523

524
525
526
527
528
529
530
536
537
538
539
540
541
542

543
544
545
546
547
548
549
550







-
+







		bh = 1.8
	}
	bh /= stv_g.scale

/*fixme: quick hack for stubs at end of beam and different stem directions*/
	beam_dir = s1.stem
	if (s1.stem != s2.stem
	 && s1.nflags < s2.nflags)
	 && s1.nflags > s2.nflags)
		beam_dir = s2.stem
	if (beam_dir < 0)
		bh = -bh;

	/* make first beam over whole word and adjust the stem lengths */
	draw_beam(s1.xs - shift, s2.xs + shift, 0, bh, bm, 1);
	da = 0
︙
591
592
593
594
595
596
597
598

599
600
601
602
603
604
605
611
612
613
614
615
616
617

618
619
620
621
622
623
624
625







-
+







					break
				s = k
			}
			k2 = s
			while (k2.type != C.NOTE)
				k2 = k2.prev;
			x1 = k1.xs
			bd = beam_dir
			bsh = shift * beam_dir
			if (k1 == k2) {
				if (k1 == s1) {
					x1 += bstub
				} else if (k1 == s2) {
					x1 -= bstub
				} else if (k1.beam_br1
				        || (k1.beam_br2
︙
621
622
623
624
625
626
627

628

629
630
631

632













633
634

635
636
637
638
639
640
641
641
642
643
644
645
646
647
648

649
650
651
652
653

654
655
656
657
658
659
660
661
662
663
664
665
666
667

668
669
670
671
672
673
674
675







+
-
+



+
-
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+







						  && k1.dots < k.dots))
							x1 += bstub
						else
							x1 -= bstub
					}
				}
				if (k1.stem != beam_dir) {
					osh -= bshift
					bd = k1.stem
					bsh = osh * beam_dir
					k1.ys = bm.a * k1.xs + bm.b
						- staff_tb[k1.st].y - bh
				}
			} else if (k1.stem == k2.stem && k1.stem != beam_dir) {
			}

				// inverted stems: put the beam on the other side
				osh -= bshift
				bsh = osh * beam_dir
				for (s = k1; ; s = s.next) {
					if (s.type == C.NOTE)
						s.ys = bm.a * s.xs + bm.b
							- staff_tb[s.st].y
							- bh
					if (s == k2)
						break
				}
			}
			draw_beam(x1, k2.xs,
				  shift * bd,
				  bsh,
				  bh, bm, i)
			if (s == s2)
				break
		}
	}
	if (s1.tmp)
		unlksym(s1)
︙
1163
1164
1165
1166
1167
1168
1169




























1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187

1188
1189
1190
1191












1192
1193
1194
1195
1196
1197
1198
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250




1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


















+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+







// -- draw a multi-measure rest --
// (the staves are defined)
function draw_mrest(s) {
    var	x1, x2, prev,
	p_st = staff_tb[s.st],
	y = p_st.y + (p_st.topbar + p_st.botbar) / 2,
	p = s.nmes.toString()

	// output an old multimeasure rest
	function omrest() {
	    var	x = s.x,
		y = p_st.y + 12,
		n = s.nmes,
		k = n >> 2			// number of rests

		if (n & 3) {
			k++
			if (n & 3 == 3)
				k++
		}
//dx = 6
		x -= 3 * (k - 1)
		while (n >= 4) {
			xygl(x, y, "r00")
			n -= 4
			x += 6
		}
		if (n >= 2) {
			xygl(x, y, "r0")
			n -= 2
			x += 6
		}
		if (n)
			xygl(x + 2, y, "r1")
	} // omrest()

	if (!s.next) {
		error(1, s, "Lack of bar after multi-measure rest")
		return
	}
	set_scale(s)

	prev = s		// search the start of the previous time sequence
	while (!prev.seqst)
		prev = prev.ts_prev
	prev = prev.ts_prev
	while (!prev.seqst)
		prev = prev.ts_prev

	x1 = prev.x + 20
	x2 = s.next.x - 20
	s.x = (x1 + x2) / 2
	anno_start(s)
	if (!cfmt.oldmrest || s.nmes > cfmt.oldmrest) {
	out_XYAB('<path d="mX Y', x1 + .6, y - 2.7)
	output += 'v2.7h-1.4v-10.8h1.4v2.7h'
		+ ((x2 - x1 - 2.8) / stv_g.scale).toFixed(1)
		+ 'v-2.7h1.4v10.8h-1.4v-2.7z"/>\n'
		out_XYAB('<path d="mX Y', x1 + .6, y - 2.7)
		output += 'v2.7h-1.4v-10.8h1.4v2.7h'
			+ ((x2 - x1 - 2.8) / stv_g.scale).toFixed(1)
			+ 'v-2.7h1.4v10.8h-1.4v-2.7z"/>\n'
	} else {
		omrest()		// old multirest
	}
    if (s.tacet)
	out_XYAB('<text x ="X" y="Y" style="font-size:12px;font-weight:700"\
 text-anchor="middle">A</text>\n',
		s.x, y + 18, s.tacet)
    else
	out_XYAB('<text x ="X" y="Y" text-anchor="middle">A</text>\n',
		s.x, y + 22, m_gl(p))
	anno_a.push(s)
} // draw_mrest()

function grace_slur(s) {
    var	yy, x0, y0, x3, y3, bet1, bet2, dy1, dy2, last, below,
︙
1744
1745
1746
1747
1748
1749
1750
1751


1752
1753

1754
1755
1756
1757
1758
1759
1760

1761
1762

1763
1764
1765
1766

1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784


































































































1785
1786
1787
1788
1789
1790
1791
1815
1816
1817
1818
1819
1820
1821

1822
1823
1824

1825
1826
1827
1828
1829
1830
1831

1832
1833

1834




1835


1836
1837
1838
1839
1840
1841
1842









1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947







-
+
+

-
+






-
+

-
+
-
-
-
-
+
-
-







-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







}

// draw a slur between two chords / notes
/* (the staves are not yet defined) */
/* (delayed output) */
/* (not a pretty routine, this) */
function draw_slur(path,	// list of symbols under the slur
		sl) {		// slur variables: type, end symbol, note
		   sl,		// slur variables: type, end symbol, note
		   recurr) {	// recurrent call when slur on two staves
    var	i,
	k, g, x1, y1, x2, y2, height, addy,
	k, g, x1, y1, x2, y2, height, addy, s_st2,
	a, y, z, h, dx, dy,
	ty = sl.ty,
	dir = (ty & 0x07) == C.SL_ABOVE ? 1 : -1,
	n = path.length,
	i1 = 0,
	i2 = n - 1,
	not1 = sl.nts,		// if the slur start on a note
	not1 = sl.nts,		// if the slur starts on a note
	k1 = path[0],
	k2 = path[i2]
	k2 = path[i2],

/*fixme: if two staves, may have upper or lower slur*/

	var	nn = 1,
	nn = 1
		upstaff = k1.st,
		two_staves = false

	set_dscale(k1.st)

	for (i = 1; i < n; i++) {
		k = path[i]
		if (k.type == C.NOTE || k.type == C.REST) {
			nn++
			if (k.st != upstaff) {
				two_staves = true
				if (k.st < upstaff)
					upstaff = k.st
			}
		}
	}
/*fixme: KO when two staves*/
if (two_staves) error(2, k1, "*** multi-staves slurs not treated yet");
			if (k.st != k1.st
			 && !s_st2)
				s_st2 = k
		}
	}

	// if slur on 2 staves, define it, but don't output it now
	// this will be done in draw_sl2()
	if (s_st2 && !recurr) {			// if not 2nd call to draw_slur()
		if (!gene.a_sl)
			gene.a_sl = []

		// replace the symbols of the other staff
		// by symbols in the current staff but with updated y offsets
		h = 24 + k1.fmt.sysstaffsep		// delta y
		if (s_st2.st > k1.st)
			h = -h
		for (i = 0; i < n; i++) {
			k = path[i]
			if (k.st == k1.st) {
				if (k.dur)
					a = k		// (used for types // and \\)
				continue
			}
			k = clone(k)
			if (path[i] == s_st2)
				s_st2 = k
			path[i] = k
			if (k.dur) {
				k.notes = clone(k.notes)
				k.notes[0] = clone(k.notes[0])
				if (sl.ty & C.SL_CENTER) {
					if (k.st != a.st) {
						sl.ty = (sl.ty & ~0x07)
							 | (a.st < k.st
								? C.SL_BELOW
								: C.SL_ABOVE)
						z = k1.ymn
						h = k2.ymx
						if (k.st < a.st) {
							for (i1 = 1; i1 < i; i1++) {
								a = path[i1]
								if (a.ymn < z)
									z = a.ymn
							}
							for (i1 = i; i1 < i2; i1++) {
								a = path[i1]
								if (a.ymx > h)
									h = a.ymx
							}
						} else {
							for (i1 = 1; i1 < i; i1++) {
								a = path[i1]
								if (a.ymx > h)
									h = a.ymx
							}
							for (i1 = i; i1 < i2; i1++) {
								a = path[i1]
								if (a.ymn < z)
									z = a.ymn
							}
						}
						h += z
						a = k
					}
					k.y = h - k.y
					k.notes[0].pit = (k.y / 3 | 0) + 18
					k.ys = h - k.ys
					y = k.ymx
					k.ymx = h - k.ymn
					k.ymn = h - y
					k.stem = -k.stem
				} else {
					k.notes[0].pit += h / 3 | 0
					k.ys += h
					k.y += h
					k.ymx += h
					k.ymn += h
				}
			}
//			k.st = k1.st	// keep the staff number for draw_sl2()
		}

		ty = k1.st > s_st2.st ? '/' : '\\'
		if (sl.ty & C.SL_CENTER)
			ty = ty + ty			// type = // or \\
		else if (k1.st == k2.st)
			ty = ty == '/' ? '/\\' : '\\/'	// type = /\ or \/
		else
			ty += dir > 0 ? '+' : '-'	// type = .+ or .-

	    var	savout = output
		output = ""
		draw_slur(path, sl, 1 /*true*/)
		gene.a_sl.push([k1, s_st2, ty, output])
		output = savout
		return
	}

	/* fix endpoints */
	x1 = k1.x
	if (k1.notes && k1.notes[0].shhd)
		x1 += k1.notes[0].shhd;
	x2 = k2.x
	if (k2.notes)
︙
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
2114
2115
2116
2117
2118
2119
2120


2121
2122
2123
2124
2125
2126
2127







-
-







	h = 0;
	a = (y2 - y1) / (x2 - x1)
	if (k1 != k2
	 && k1.v == k2.v) {
	    addy = y1 - a * x1
	    for (i = 1; i < i2; i++) {
		k = path[i]
		if (k.st != upstaff)
			continue
		switch (k.type) {
		case C.NOTE:
		case C.REST:
			if (dir > 0) {
				y = 3 * (k.notes[k.nhd].pit - 18) + 6
				if (y < k.ymx)
					y = k.ymx;
︙
2050
2051
2052
2053
2054
2055
2056
2057

2058
2059
2060
2061
2062
2063


2064
2065
2066
2067
2068
2069
2070
2071

2072
2073
2074
2075

2076
2077
2078


2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116

2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138



2139
2140

2141

2142
2143
2144
2145
2146
2147














2148
2149
2150
2151
2152
2153
2154
2204
2205
2206
2207
2208
2209
2210

2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223


2224

2225
2226
2227
2228

2229
2230


2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252


















2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273


2274
2275
2276
2277

2278

2279
2280





2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301







-
+






+
+




-
-

-
+



-
+

-
-
+
+




















-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+




















-
-
+
+
+

-
+
-
+

-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+







	addy = y1 - a * x1
	if (height > 0)
		addy += 4 * Math.sqrt(height) - 2
	else
		addy -= 4 * Math.sqrt(-height) - 2
	for (i = 0; i < i2; i++) {
		k = path[i]
		if (k.st != upstaff || k.type == C.BAR)
		if (k.st != k1.st || k.type == C.BAR)
			continue
		y = a * k.x + addy
		if (k.ymx < y)
			k.ymx = y
		else if (k.ymn > y)
			k.ymn = y
		if (recurr)			// no room when slur on 2 staves
			continue
		if (i == i2 - 1) {
			dx = x2
			if (sl.nte)
				dx -= 5;
			if (i)
				y -= height / 3
		} else {
			dx = path[i + 1].x
			dx = k.x + k.wr
		}
		if (i != 0)
			x1 = k.x
		else
		if (!i || i == i2)
			y -= height / 3
		dx -= x1;
		y_set(upstaff, dir > 0, x1, dx, y)
		dx -= x1 - k.wl
		y_set(k1.st, dir > 0, x1 - k.wl, dx, y)
	}
}

/* -- draw the slurs between 2 symbols --*/
function draw_slurs(s, last) {
    var	gr1, i, m, note, sls, nsls

	// draw a slur knowing the start and stop elements
	function draw_sls(s,		// start symbol
			sl) {		// slur variables
	    var	k, v, i, dir, s3,
		path = [],
		s2 = sl.se			// slur end

		if (last && s2.time > last.time)
			return			// will be drawn next time

		// handle slurs without start or end
		switch (sl.loc) {
		case 'i':			// no start
			s3 = s.ts_prev
			for (s = s3; s; s = s.ts_prev) {
				if (s.dur) {
					if (s.v == s2.v) {
						s3 = s
						break
					}
					if (s.st == s2.st) {
						s3 = s
						continue
					} else if (!s3) {
						s3 = s
					}
				} else if (!s3) {
					s3 = s
				}
			}
			s = s3
			s = prev_scut(s)
			break
		case 'o':			// no end
			for (s3 = s; s3.ts_next; s3 = s3.ts_next)
				;
			s2 = s3
			for (; s3; s3 = s3.ts_prev) {
				if (s3.v == s.v) {
					s2 = s3
					break
				}
				if (s3.st == s.st)
					s2 = s3
				if (s3.ts_prev.time != s2.time)
					break
			}
			break
		}

		// if the slur continues on the next music line,
		// stop it at the end of the current line
		if (tsnext && s2.time >= tsnext.time) {
		    if (s2.grace && s2.time == tsnext.time) {
		if (s.p_v.s_next && s2.time >= tsnext.time) {
		  if (s2.time == tsnext.time) {
		    if (s2.grace) {
			for (s3 = tsnext; s3 && s3.time == s2.time; s3 = s3.ts_next) {
				if (s3.type == C.GRACE)
				if (s3.type == C.GRACE) {
//fixme: check if s2 in the grace notes
					s3 = null
					break
			}
			if (s3.type == C.GRACE)
				s3 = null
		    }
		    if (!s2.grace || s2.time == tsnext.time || !s3) {
				}
			}
		    } else {
			for (s3 = tsnext; s3.time == s2.time; s3 = s3.ts_next) {
				if (s3 == s2) {
					s3 = null	// end of slur in next line
					break
				}
			}
		    }
		  } else {
			s3 = null
		  }
		    if (!s3) {
			s.p_v.sls.push(sl);		// continuation on next line
			s2 = s.p_v.s_next.prev		// one voice
			while (s2.next)
				s2 = s2.next;		// search the ending bar
			sl = Object.create(sl);		// new slur
		    }
		}
︙
2193
2194
2195
2196
2197
2198
2199
2200

2201
2202
2203
2204
2205
2206
2207
2208
2340
2341
2342
2343
2344
2345
2346

2347

2348
2349
2350
2351
2352
2353
2354







-
+
-







				s = s.next
			else
				s = s.ts_next
		}

		if (!s2.grace) {		// if end on a normal note
			while (s) {
				if (s.v == v
				if (s.v == v)
				 && !s.invis)
					path.push(s)
				if (s == s2)
					break
				s = s.ts_next
			}
		} else if (s.grace) {		// if start/end in the same sequence
			while (1) {
︙
2275
2276
2277
2278
2279
2280
2281
2282

2283
2284
2285
2286
2287
2288
2289
2290
2291

2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311






2312
2313
2314
2315
2316
2317
2318
2421
2422
2423
2424
2425
2426
2427

2428
2429
2430
2431
2432
2433
2434
2435


2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454


2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467







-
+







-
-
+


















-
-
+
+
+
+
+
+








/* -- draw a tuplet -- */
/* (the staves are not yet defined) */
/* (delayed output) */
/* See http://moinejf.free.fr/abcm2ps-doc/tuplets.html
 * for the value of 'tp.f' */
function draw_tuplet(s1) {
    var	s2, s3, g, upstaff, nb_only,
    var	s2, s3, g, stu, std, nb_only,
	x1, x2, y1, y2, xm, ym, a, s0, yy, yx, dy, a, dir, r,
	tp = s1.tp.shift()		// tuplet parameters

	if (!s1.tp.length)
		delete s1.tp		// last tuplet

	// treat the slurs and the nested tuplets
	upstaff = s1.st
	set_dscale(s1.st)
	stu = std = s1.st
	for (s2 = s1; s2; s2 = s2.next) {
		switch (s2.type) {
		case C.GRACE:
			if (!s2.sl1)
				continue
			for (g = s2.extra; g; g = g.next) {
				if (g.sls)
					draw_slurs(g)
			}
			// fall thru
		default:
			continue
		case C.NOTE:
		case C.REST:
			break
		}
		if (s2.sls)
			draw_slurs(s2)
		if (s2.st < upstaff)
			upstaff = s2.st
		if (s2.st < stu) {
			std = stu
			stu = s2.st
		} else if (s2.st > std) {
			std = s2.st
		}
		if (s2.tp)
			draw_tuplet(s2)
		if (s2.tpe)
			break
	}

	if (s2)
︙
2329
2330
2331
2332
2333
2334
2335

2336
2337
2338
2339
2340
2341
2342
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492







+







	dir = tp.f[3]				// 'where'
	if (!dir) {				// if auto
		s3 = s1
		while (s3 && !s3.stem)		// (may have tuplets of rests!)
			s3 = s3.next
		dir = (s3 && s3.stem < 0) ? C.SL_BELOW : C.SL_ABOVE
	}
	set_dscale(dir == C.SL_ABOVE ? stu : std)

	if (s1 == s2				// tuplet with 1 note (!)
	 || tp.f[1] == 2) {			// what == nothing
		nb_only = true
	} else if (tp.f[1] == 1) {			/* 'what' == slur */
		nb_only = true;
		draw_slur([s1, s2], {ty: dir})
︙
2393
2394
2395
2396
2397
2398
2399
2400

2401
2402

2403
2404
2405
2406
2407

2408
2409

2410
2411

2412
2413

2414
2415

2416
2417
2418
2419
2420
2421
2422
2423
2424
2425

2426
2427
2428
2429

2430
2431
2432
2433
2434

2435
2436
2437
2438
2439
2440
2441
2543
2544
2545
2546
2547
2548
2549

2550
2551

2552
2553
2554
2555
2556

2557
2558

2559
2560
2561
2562
2563

2564
2565

2566
2567
2568
2569
2570
2571
2572
2573
2574
2575

2576
2577
2578
2579

2580
2581
2582
2583
2584

2585
2586
2587
2588
2589
2590
2591
2592







-
+

-
+




-
+

-
+


+

-
+

-
+









-
+



-
+




-
+







	/* 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(upstaff, 1, xm - 4, 8)
			ym = y_get(stu, 1, xm - 4, 8)
		else
			ym = y_get(upstaff, 0, xm - 4, 8) -
			ym = y_get(std, 0, xm - 4, 8) -
					gene.curfont.size

		if (s1.stem * s2.stem > 0) {
			if (s1.stem > 0)
				xm += 1.5
				xm += 4
			else
				xm -= 1.5
				xm -= 4
		}

		yy = ym + gene.curfont.size * .22
		if (tp.f[2] == 0)		// if 'which' == number
			xy_str(xm, ym, tp.p.toString(), 'c')
			xy_str(xm, yy, tp.p.toString(), 'c')
		else
			xy_str(xm, ym, tp.p+':'+tp.q, 'c')
			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(upstaff, true, xm - 3, 6, ym)
			y_set(stu, 1, xm - 3, 6, ym)
		} else {
			if (s3.ymn > ym)
				s3.ymn = ym;
			y_set(upstaff, false, xm - 3, 6, ym)
			y_set(std, 0, xm - 3, 6, ym)
		}
		return
	}

	// here, what is square bracket
	// here, 'what' is square bracket

/*fixme: two staves not treated*/
/*fixme: to optimize*/

	// first, get the x offsets
	x1 = s1.x - 4

︙
2453
2454
2455
2456
2457
2458
2459
2460

2461
2462
2463
2464
2465
2466
2467

2468
2469
2470






2471
2472

2473
2474
2475

2476
2477
2478
2479
2480
2481
2482




2483
2484
2485

2486
2487
2488
2489
2490
2491

2492
2493
2494
2495
2496
2497
2498
2604
2605
2606
2607
2608
2609
2610

2611
2612
2613
2614
2615
2616
2617

2618



2619
2620
2621
2622
2623
2624
2625

2626

2627

2628







2629
2630
2631
2632



2633






2634
2635
2636
2637
2638
2639
2640
2641







-
+






-
+
-
-
-
+
+
+
+
+
+

-
+
-

-
+
-
-
-
-
-
-
-
+
+
+
+
-
-
-
+
-
-
-
-
-
-
+







//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 == upstaff
		if (s2.st == stu
		 && s2.stem > 0)
			x2 += 3.5
	}

    // above
    if (dir == C.SL_ABOVE) {

	if (s1.st >= s2.st) {
	/* sole or upper voice: the bracket is above the staff */
	if (s1.st == s2.st) {
		y1 = y2 = staff_tb[upstaff].topbar + 2
		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 = s1.ymx;
		y1 = staff_tb[s1.st].topbar + 2
		y2 = s2.ymx
	}

	if (s2.st >= s1.st) {
	if (s1.st == upstaff) {
		for (s3 = s1; !s3.dur; s3 = s3.next)
			;
		ym = y_get(upstaff, 1, s3.x - 4, 8)
		if (ym > y1)
			y1 = ym
		if (s1.stem > 0)
		ym = y_get(s2.st, 1, x2 - 4, 8)
		y2 = ym > staff_tb[s2.st].topbar + 2
			? ym
			: staff_tb[s2.st].topbar + 2
			x1 += 3
	}

	} else {
	if (s2.st == upstaff) {
		for (s3 = s2; !s3.dur; s3 = s3.prev)
			;
		ym = y_get(upstaff, 1, s3.x - 4, 8)
		if (ym > y2)
			y2 = ym
		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)
︙
2511
2512
2513
2514
2515
2516
2517
2518

2519
2520
2521
2522
2523
2524

2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538

2539
2540
2541
2542

2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553




2554
2555
2556
2557

2558
2559

2560

2561
2562


2563
2564




2565
2566

2567
2568
2569
2570
2571
2572
2573
2654
2655
2656
2657
2658
2659
2660

2661
2662
2663
2664
2665
2666

2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680

2681
2682
2683
2684

2685
2686
2687
2688
2689
2690
2691
2692




2693
2694
2695
2696




2697
2698

2699
2700
2701


2702
2703


2704
2705
2706
2707
2708

2709
2710
2711
2712
2713
2714
2715
2716







-
+





-
+













-
+



-
+







-
-
-
-
+
+
+
+
-
-
-
-
+

-
+

+
-
-
+
+
-
-
+
+
+
+

-
+







	if (a * a < .1 * .1)
		a = 0

	/* shift up bracket if needed */
	dy = 0
	for (s3 = s1; ; s3 = s3.next) {
		if (!s3.dur			/* not a note or a rest */
		 || s3.st != upstaff) {
		 || s3.st != stu) {
			if (s3 == s2)
				break
			continue
		}
		yy = ym + (s3.x - xm) * a;
		yx = y_get(upstaff, 1, s3.x - 4, 8) + 2
		yx = y_get(stu, 1, s3.x - 4, 8) + 2
		if (yx - yy > dy)
			dy = yx - yy
		if (s3 == s2)
			break
	}

	ym += dy;
	y1 = ym + a * (x1 - xm);
	y2 = ym + a * (x2 - xm);

	/* shift the slurs / decorations */
	ym += 6
	for (s3 = s1; ; s3 = s3.next) {
		if (s3.st == upstaff) {
		if (s3.st == stu) {
			yy = ym + (s3.x - xm) * a
			if (s3.ymx < yy)
				s3.ymx = yy
			y_set(upstaff, true, s3.x - 3, 6, yy)
			y_set(stu, 1, s3.x - 3, 6, yy)
		}
		if (s3 == s2)
			break
	}

    // below
    } else {	/* lower voice of the staff: the bracket is below the staff */
/*fixme: think to all of that again..*/
	if (s1.stem < 0)
		x1 -= 2

	if (s1.st <= s2.st) {
		ym = y_get(s1.st, 0, x1 - 4, 8)
		y1 = ym < -2
			? ym
	if (s1.st == upstaff) {
		for (s3 = s1; !s3.dur; s3 = s3.next)
			;
		y1 = y_get(upstaff, 0, s3.x - 4, 8)
			: -2
	} else {
		y1 = 0
		y1 = -2
	}
	if (s2.st <= s1.st) {
	if (s2.st == upstaff) {
		for (s3 = s2; !s3.dur; s3 = s3.prev)
		if (s2.stem < 0)
			x2 -= 3
			;
		y2 = y_get(upstaff, 0, s3.x - 4, 8)
		ym = y_get(s2.st, 0, x2 - 4, 8)
		y2 = ym < -2
			? ym
			: -2
	} else {
		y2 = 0
		y2 = -2
	}

	xm = .5 * (x1 + x2);
	ym = .5 * (y1 + y2);

	a = (y2 - y1) / (x2 - x1);
	s0 = 3 * (s2.notes[0].pit - s1.notes[0].pit) / (x2 - x1)
︙
2589
2590
2591
2592
2593
2594
2595
2596

2597
2598
2599
2600
2601
2602

2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616

2617
2618
2619
2620

2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635

2636
2637

2638
2639
2640
2641
2642
2643
2644
2732
2733
2734
2735
2736
2737
2738

2739
2740
2741
2742
2743
2744

2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758

2759
2760
2761
2762

2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777

2778
2779

2780
2781
2782
2783
2784
2785
2786
2787







-
+





-
+













-
+



-
+














-
+

-
+







	if (a * a < .1 * .1)
		a = 0

	/* shift down the bracket if needed */
	dy = 0
	for (s3 = s1; ; s3 = s3.next) {
		if (!s3.dur			/* not a note nor a rest */
		 || s3.st != upstaff) {
		 || s3.st != std) {
			if (s3 == s2)
				break
			continue
		}
		yy = ym + (s3.x - xm) * a;
		yx = y_get(upstaff, 0, s3.x - 4, 8)
		yx = y_get(std, 0, s3.x - 4, 8)
		if (yx - yy < dy)
			dy = yx - yy
		if (s3 == s2)
			break
	}

	ym += dy - 8
	y1 = ym + a * (x1 - xm);
	y2 = ym + a * (x2 - xm);

	/* shift the slurs / decorations */
	ym -= 2
	for (s3 = s1; ; s3 = s3.next) {
		if (s3.st == upstaff) {
		if (s3.st == std) {
			yy = ym + (s3.x - xm) * a
			if (s3.ymn > yy)
				s3.ymn = yy;
			y_set(upstaff, false, s3.x - 3, 6, yy)
			y_set(std, 0, s3.x - 3, 6, yy)
		}
		if (s3 == s2)
			break
	}
    } /* lower voice */

	if (tp.f[2] == 1) {			/* if 'which' == none */
		out_tubr(x1, y1 + 4, x2 - x1, y2 - y1, dir == C.SL_ABOVE);
		return
	}
	out_tubrn(x1, y1, x2 - x1, y2 - y1, dir == C.SL_ABOVE,
		tp.f[2] == 0 ? tp.p.toString() : tp.p + ':' +  tp.q);

	if (dir == C.SL_ABOVE)
		y_set(upstaff, true, xm - 3, 6, yy + 2)
		y_set(stu, 1, xm - 3, 6, yy + 2)
	else
		y_set(upstaff, false, xm - 3, 6, yy)
		y_set(std, 0, xm - 3, 6, yy)
}

// -- draw a ties --
function draw_tie(not1, not2,
			job) {	// -: start and end
				// 1: no starting note
				// 2: no ending note
︙
2813
2814
2815
2816
2817
2818
2819

2820
2821
2822
2823
2824
2825
2826
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970







+







 *   - tuplets and slurs
 * - not scaled
 *   - measure numbers
 *   - lyrics
 *   - staff decorations
 *   - chord symbols
 *   - repeat brackets
 *   - parts and tempos
 * The buffer output is delayed until the definition of the staff system
 */
function draw_sym_near() {
    var	p_voice, p_st, s, v, st, y, g, w, i, st, dx, top, bot, ymn,
	output_sav = output;

	// set the staff offsets of a beam
︙
3038
3039
3040
3041
3042
3043
3044


3045
3046
3047
3048
3049
3050
3051
3052
3053



3054


3055
3056
3057
3058
3059
3060
3061
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202

3203
3204
3205
3206
3207
3208
3209
3210
3211







+
+









+
+
+
-
+
+







			draw_all_lyrics()
			break
		}
	}

	draw_deco_staff()

	draw_partempo()			// draw the parts and tempo indications if any

	set_dscale(-1);
	output = output_sav
}

/* -- draw the name/subname of the voices -- */
function draw_vname(indent, stl) {
    var	p_voice, n, st, v, a_p, p, y, h, h2,
	staff_d = []

	if (!gene.vnt)
		return

	for (st = stl.length; st >= 0; st--) {
//	for (st = stl.length; st >= 0; st--) {
	for (st = stl.length; --st >= 0; ) {
		if (stl[st])
			break
	}
	if (st < 0)
		return

	for (v = 0; v < voice_tb.length; v++) {
︙
3103
3104
3105
3106
3107
3108
3109
3110

3111
3112
3113



3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130


3131
3132

3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147

3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167


3168
3169
3170
3171
3172
3173
3174
3253
3254
3255
3256
3257
3258
3259

3260
3261

3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280


3281
3282


3283

3284
3285
3286
3287
3288
3289




3290
3291
3292

3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311


3312
3313
3314
3315
3316
3317
3318
3319
3320







-
+

-

+
+
+















-
-
+
+
-
-
+
-






-
-
-
-



-
+


















-
-
+
+







			y -= h
		}
	}
}

// -- set the y offset of the staves and return the height of the whole system --
function set_staff() {
    var	i, st, prev_staff, v,
    var	i, st, prev_staff, v, fmt, s,
	y, staffsep, dy, maxsep, mbot, val, p_voice, p_staff,
	fmt = tsfirst.fmt,
	sy = cur_sy

	// the last values of {,max}{,sys}staffsep are in the last format
	fmt = tsnext ? tsnext.fmt : cfmt

	/* set the scale of the voices */
	for (v = 0; v < voice_tb.length; v++) {
		p_voice = voice_tb[v]
		if (p_voice.scale != 1)
			p_voice.scale_str = 
				'transform="scale(' + p_voice.scale.toFixed(2) + ')"'
	}

	// search the top staff
	for (st = 0; st <= nstaff; st++) {
		if (gene.st_print[st])
			break
	}
	y = 0
	if (st > nstaff) {
		st--;			/* one staff, empty */
	if (st > nstaff)
		return y
		p_staff = staff_tb[st]
	}

// else {
		p_staff = staff_tb[st]
		for (i = 0; i < YSTEP; i++) {
			val = p_staff.top[i]
			if (y < val)
				y = val
		}
//	}

	/* draw the parts and tempo indications if any */
	y += draw_partempo(st, y)

	/* set the vertical offset of the 1st staff */
	y *= p_staff.staffscale;
	staffsep = fmt.staffsep * .5 +
	staffsep = tsfirst.fmt.staffsep / 2 +
			p_staff.topbar * p_staff.staffscale
	if (y < staffsep)
		y = staffsep
	if (y < p_staff.ann_top)	// absolute annotation
		y = p_staff.ann_top;
	p_staff.y = -y;

	/* set the offset of the other staves */
	for (prev_staff = 0; prev_staff < st; prev_staff++)
		staff_tb[prev_staff].y = -y
	if (!gene.st_print[st])		// no staff
		return y

	var sy_staff_prev = sy.staves[prev_staff]
	for (st++; st <= nstaff; st++) {
		if (!gene.st_print[st])
			continue
		p_staff = staff_tb[st]
		staffsep = sy_staff_prev.sep || cfmt.sysstaffsep;
		maxsep = sy_staff_prev.maxsep || cfmt.maxsysstaffsep;
		staffsep = sy_staff_prev.sep || fmt.sysstaffsep;
		maxsep = sy_staff_prev.maxsep || fmt.maxsysstaffsep;

		dy = 0
		if (p_staff.staffscale == staff_tb[prev_staff].staffscale) {
			for (i = 0; i < YSTEP; i++) {
				val = p_staff.top[i] -
						staff_tb[prev_staff].bot[i]
				if (dy < val)
︙
3289
3290
3291
3292
3293
3294
3295

3296
3297
3298
3299
3300
3301
3302
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449







+







		if (!/[\[|]/.test(stafflines))
			return				// no line
		w = x2 - x1;
		set_sscale(-1)

		// check if default staff
		if (cache && cache.st_l == stafflines
		 && staff_tb[st].staffscale == 1
		 && cache.st_w == (w | 0)) {
			xygl(x1, staff_tb[st].y, 'stdef' + cfmt.fullsvg)
			return
		}
		for (i = 0; i < l; i++, y -= il) {
			if (stafflines[i] == '.')
				continue
︙
3321
3322
3323
3324
3325
3326
3327
3328


3329
3330
3331
3332
3333
3334
3335
3468
3469
3470
3471
3472
3473
3474

3475
3476
3477
3478
3479
3480
3481
3482
3483







-
+
+







					'" d="m0 ' + y + 'h' + w.toFixed(1);
				dy = 0
			}
			ln += '"/>'
		}
		y = staff_tb[st].y
		if (!cache
		 && w > get_lwidth() - 10) {
		 && w > get_lwidth() - 10
		 && staff_tb[st].staffscale == 1) {
			cache = {
				st_l: stafflines,
				st_w: w | 0
			}
			i = 'stdef' + cfmt.fullsvg;
			if (ln.indexOf('<path', 1) < 0)
				glyphs[i] = ln.replace('path', 'path id="' + i + '"')
︙
3499
3500
3501
3502
3503
3504
3505
















3506
3507
3508
3509
3510
3511

3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525

3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674

3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687


3688





3689
3690
3691
3692
3693
3694
3695







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+





-
+












-
-
+
-
-
-
-
-







		case '[':
			break
		default:
			set_hl(p_st, j, x, -7, 7)
			break
		}
	} // hl_rest()

	// return the left x offset of a new staff
	// s is the %%staves
	function st1(st, s) {
	    var	tim = s.time

		do {			// search a voice of this staff
			s = s.ts_next
		} while (s.st != st)
		while (s.prev		// search the first symbol of this voice
		    && s.prev.time >= tim)
			s = s.prev
		if (s.bar_type)
			return s.x
		return s.x - s.wl
	} // st1()

	// ---- draw_systems() ----

	/* draw the staff, skipping the staff breaks */
	for (st = 0; st <= nstaff; st++) {
		stl[st] = gene.st_print[st] || cur_sy.st_print[st] // staff in the line
		stl[st] = cur_sy.st_print[st]		// staff at start of line
		xstaff[st] = !stl[st] ? -1 : 0;
	}
	bar_set();
	draw_lstaff(0)
	for (s = tsfirst; s; s = s.ts_next) {
		switch (s.type) {
		case C.STAVES:
			sy = s.sy
			for (st = 0; st <= nstaff; st++) {
				x = xstaff[st]
				if (x < 0) {		// no staff yet
					if (sy.st_print[st]) {
						if (s.ts_prev.bar_type)
							xstaff[st] = s.ts_prev.x
						xstaff[st] = st1(st, s)
						else if (s.ts_next.bar_type)
							xstaff[st] = s.x
						else
							xstaff[st] = s.ts_prev.x
								+ s.ts_prev.wr
						stl[st] = true
					}
					continue
				}
				if (sy.st_print[st]	// if not staff stop
				 && cur_sy.staves[st]
				 && sy.staves[st].stafflines ==
︙
3559
3560
3561
3562
3563
3564
3565
3566



3567
3568
3569
3570
3571
3572
3573
3717
3718
3719
3720
3721
3722
3723

3724
3725
3726
3727
3728
3729
3730
3731
3732
3733







-
+
+
+







			   && s.ts_prev.st == s.st)))
				break
			ba.push([s, bar_bot[s.st], bar_height[s.st]])
			break
		case C.STBRK:
			if (cur_sy.voices[s.v]
			 && cur_sy.voices[s.v].range == 0) {
				if (s.xmx > 14) {
				if (s.xmx > 14
				 && s.next			// if not at end of line
				 && s.next.type == C.CLEF) {	// and before a clef

					/* draw the left system if stbrk in all voices */
					var nv = 0
					for (var i = 0; i < voice_tb.length; i++) {
						if (cur_sy.voices[i]
						  && cur_sy.voices[i].range > 0)
							nv++
︙
3645
3646
3647
3648
3649
3650
3651




3652
3653
3654
3655
3656
3657
3658
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822







+
+
+
+







	var	bm = {},
		s, x, y, st;

//	bm.s2 = undefined
	for (s = p_voice.sym; s; s = s.next) {
		if (s.invis) {
			switch (s.type) {
			case C.CLEF:
				if (s.time >= staff_tb[s.st].clef.time)
					staff_tb[s.st].clef = s
				continue
			case C.KEY:
				p_voice.ckey = s
			default:
				continue
			case C.NOTE:	// (beams may start on invisible notes)
				break
			}
︙
3683
3684
3685
3686
3687
3688
3689
3690


3691
3692
3693
3694
3695
3696
3697
3847
3848
3849
3850
3851
3852
3853

3854
3855
3856
3857
3858
3859
3860
3861
3862







-
+
+







			break
		case C.BAR:
			break			/* drawn in draw_systems */
		case C.CLEF:
			if (s.time >= staff_tb[st].clef.time)
				staff_tb[st].clef = s
			if (s.second
			 || !staff_tb[st].topbar)
			 || !staff_tb[st].topbar
			 || !gene.st_print[st])
				break
			set_color();
			set_sscale(st);
			anno_start(s);
			y = staff_tb[st].y
			if (s.clef_name)
				xygl(x, y + s.y, s.clef_name)
︙
3765
3766
3767
3768
3769
3770
3771































































































3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786

3787



3788
3789
3790
3791
3792
3793
3794
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+















+

+
+
+







	set_scale(p_voice.sym);
}

/* -- draw all symbols -- */
function draw_all_sym() {
    var	p_voice, v,
	n = voice_tb.length

	// draw the slurs on 2 staves
	// sl = [symbol of 1st staff, symbol of 2nd staff, slur type, <path .../>
	function draw_sl2() {
	    var	i, a, d, dy, dy2, dy2o, dz, n, sl

		while (1) {
			sl = gene.a_sl.shift()
			if (!sl)
				break

			// extract the path header and the values
			i = sl[3].indexOf('d="M') + 4
			output += sl[3].slice(0, i)	// <path .. >d="M

			a = new Float32Array(sl[3].slice(i).match(/[\d.-]+/g))

			// update the starting point of the slur
			a[1] -= staff_tb[sl[0].st].y	// absolute vertical offset

// [0][1] = M
// [2][3] [4][5] [6][7] = c
// [8] = v			second curve if not dotted
// [9][10] [11][12] [13][14] = c
//
// y:      3-------5
//	  / 12---10 \
//	 / /       \ \
//	/ /         \ \ 7
//     1 14          \| 8
//
// x:  0   2       4    6
//       13 11    9	

			// deltas between staves, original and now
			dy2o = sl[0].fmt.sysstaffsep + 24
			dy2 = staff_tb[sl[1].st].y - staff_tb[sl[0].st].y

			switch (sl[2]) {		// slur type
			case "//":			// '~' like
			case "\\\\":

				// get the middle of the '~' slur (* 2)
				d = -(sl[1].prev.prev.y + staff_tb[sl[0].st].y
					+ sl[1].prev.next.y + staff_tb[sl[1].st].y)
					- 2 * (a[1] - posy)
				a[5] = d - a[5]
				a[7] = d - a[7]
				if (a.length > 8) {
					d = sl[2][0] == '/' ? 3 : -3
					a[8] = -a[8]
					a[10] = -a[3] + d
					a[12] = -a[5] + d
					a[14] = -a[7]
				}
				break
			case "/\\":
			case "\\/":
				d = sl[2][0] == '/'
					? dy2 - dy2o - 10
					: dy2 + dy2o + 10
				a[3] += d
				a[5] += d
				if (a.length > 8) {
					a[10] += d
					a[12] += d
				}
				break
			default:			// /+, /-, \+ or \-
				d = sl[2][0] == '/' ? dy2 - dy2o : -dy2 - dy2o
				a[5] += d
				a[7] += d
				if (a.length > 8) {
					a[12] -= d
					a[14] -= d
				}
				break
			}

			// output the slur
			output += a[0].toFixed(1) + ' ' + a[1].toFixed(1)
				+ 'c' + a[2].toFixed(1) + ' ' + a[3].toFixed(1)
				+ ' ' + a[4].toFixed(1) + ' ' + a[5].toFixed(1)
				+ ' ' + a[6].toFixed(1) + ' ' + a[7].toFixed(1)
			if (a.length > 8)
				output += 'v' + a[8].toFixed(1)
					+ 'c' + a[9].toFixed(1)
						+ ' ' + a[10].toFixed(1)
					+ ' ' + a[11].toFixed(1)
						+ ' ' + a[12].toFixed(1)
					+ ' ' + a[13].toFixed(1)
						+ ' ' + a[14].toFixed(1)
			output += '"/>\n'
		}
	} // draw_sl2()

	for (v = 0; v < n; v++) {
		p_voice = voice_tb[v]
		if (p_voice.sym
		 && p_voice.sym.x != undefined) {
			self.draw_symbols(p_voice)
			draw_all_ties(p_voice);
// no need to reset the scale as in abcm2ps
			set_color()
		}
	}

	self.draw_all_deco()
	glout()			// output the symbols
	anno_put()		// before outputting the symbol annotations

	set_sscale(-1)				/* restore the scale */

	if (gene.a_sl)		// if slurs on two staves
		draw_sl2()
}

/* -- set the tie directions for one voice -- */
function set_tie_dir(s) {
    var i, ntie, dir, sec, pit, ty, s2

	for ( ; s; s = s.next) {
︙
Changes to core/format.js.
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

23
24
25
26
27
28

29
30
31
32
33
34
35
1
2

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19



20
21
22
23
24
25

26
27
28
29
30
31
32
33


-
+
















-
-
-
+





-
+







// abc2svg - format.js - formatting functions
//
// Copyright (C) 2014-2022 Jean-Francois Moine
// Copyright (C) 2014-2023 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	font_tb = [],
	font_st = {},	// font style => font_tb index for incomplete user fonts
	font_scale_tb = {
    var	font_scale_tb = {
		serif: 1,
		serifBold: 1,
		'sans-serif': 1,
		'sans-serifBold': 1,
		Palatino: 1.1,
		monospace: 1.35
		monospace: 1
	},
	txt_ff = "text,serif",		// text font-family (serif for compatibility)
	fmt_lock = {}

var cfmt = {
	"abc-version": "1",		// default: old version
	annotationfont: {name: "text,sans-serif", size: 12},
︙
107
108
109
110
111
112
113

114
115
116
117
118
119
120
121
122
123
124
125
126
127

128
129
130
131
132
133
134
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

126
127
128
129
130
131
132
133







+













-
+







	staffsep: 46,
	stemheight: 21,			// one octave
	stretchlast: .25,
	stretchstaff: true,
	subtitlefont: {name: txt_ff, size: 16},
	subtitlespace: 3,
	sysstaffsep: 34,
	systnames: -1,
	tempofont: {name: txt_ff, weight: "bold", size: 12},
	textfont: {name: txt_ff, size: 16},
//	textoption: undefined,
	textspace: 14,
	tieheight: 1.0,
	titlefont: {name: txt_ff, size: 20},
//	titleleft: false,
	titlespace: 6,
	titletrim: true,
//	transp: 0,			// global transpose
//	topmargin: .7 * IN,
	topspace: 22,
	tuplets: [0, 0, 0, 0],
	tupletfont: {name: txt_ff, style: "italic", size: 12},
	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,
︙
153
154
155
156
157
158
159

160
161
162
163
164

165
166
167
168
169
170
171
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172







+





+







measrepnb: true,
rbmax: true,
rbmin: true,
shiftunison: true,
slurheight: true,
squarebreve: true,    
staffsep: true,
systnames: 1, //
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 !
}

︙
192
193
194
195
196
197
198
199

200
201
202
203
204
205
206
207
208
209

210
211
212

213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
193
194
195
196
197
198
199

200
201
202
203
204
205
206
207
208
209

210



211















212
213
214
215
216
217
218







-
+









-
+
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







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

// %%xxxfont fontname|* [encoding] [size|*]
function param_set_font(xxxfont, p) {
    var	font, n, a
    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"
	}

	// create a new font
	// fill the values
	font = cfmt[xxxfont];
	if (!font) {			// set-font-<n> or new element
		font = {
	font = {}
			pad: 0
		}
	} else {
		font = {
			name: font.name,
			size: font.size,
			weight: font.weight,
			style: font.style,
			box: font.box,
			pad: font.pad || 0
		}
	}
	cfmt[xxxfont] = font;

	// fill the values
	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
︙
271
272
273
274
275
276
277
278
279
280
281



282
283
284
285
286
287
288
289
290
291



292
293

294
295
296
297
298
299
300
301
302


303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332










333
334
335
336
337
338
339

340
341
342
343
344
345
346
347
348
349
350
351

352

353
354
355
356
357

































358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373

374
375
376
377
378
379
380
255
256
257
258
259
260
261




262
263
264
265
266
267
268
269

270



271
272
273


274









275
276
277
278
279
280
281
282




283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318

319
320
321
322
323
324
325
326
327
328
329
330
331
332

333
334
335
336


337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384

385
386
387
388
389
390
391
392







-
-
-
-
+
+
+





-

-
-
-
+
+
+
-
-
+
-
-
-
-
-
-
-
-
-
+
+






-
-
-
-




















+
+
+
+
+
+
+
+
+
+






-
+












+
-
+



-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+















-
+







	a = p.match(/\s+([0-9.]+|\*)$/)
	if (a) {
		if (a[1] != "*")
			font.size = +a[1]
		p = p.replace(a[0], "")
	}

	font.fname = p			// full name for scale factor

	// accept url(...) as the font name
	if (p[0] == 'u' && p.slice(0, 4) == "url(") {
	// accept local(..) and url(...) as the font source
	if ((p[0] == 'u' && p.slice(0, 4) == "url(")
	 || (p[0] == 'l' && p.slice(0, 6) == "local(")) {
		n = p.indexOf(')', 1)
		if (n < 0) {
			syntax(1, "No end of url in font family")
			return
		}
		p = p.slice(0, n + 1)

		font.src = p
		font.fid = font_tb.length
		font_tb.push(font)
		font.src = p.slice(0, n + 1)
		font.fid = abc2svg.font_tb.length
		abc2svg.font_tb.push(font)
		font.normal = true
		p = 'ft' + font.fid
		font.name = 'ft' + font.fid
	} else {
		if (p[0] == '"') {
			n = p.indexOf('"', 1)
			if (n < 0) {
				syntax(1, "No end of string in font family")
				return
			}
			p = p.slice(1, n)
		}
		p = p.replace(font.src, '')
	}

		// extract the font attributes
		a = p.match(/[- ]?[nN]ormal/)
		if (a) {
			font.normal = true
			p = p.replace(a[0], '')
			if (font.weight)
				font.weight = null
			if (font.style)
				font.style = null
		}

		// font weight
		a = p.match(abc2svg.ft_re)
		if (a) {
			font.weight = abc2svg.ft_w[a[0].replace(/[ -]/, '')
					.toLowerCase()]
			p = p.replace(a[0], '')
		}

		a = p.match(/[- ]?[iI]talic/)
		if (a) {
			font.style = "italic"
			p = p.replace(a[0], '')
		}
		a = p.match(/[- ]?[oO]blique/)
		if (a) {
			font.style = "oblique"
			p = p.replace(a[0], '')
		}

	if (!font.src) {			// if no url(...)
		if (p[0] == '"') {
			n = p.indexOf('"', 1)
			if (n < 0) {
				syntax(1, "No end of string in font family")
				return
			}
			p = p.slice(1, n)
		}

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

		switch (p) {
		case "":
		case "*": return
		case "*": p = ""; break
		case "Times-Roman":
		case "Times":	p = "serif"; break
		case "Helvetica": p = "sans-serif"; break
		case "Courier": p = "monospace"; break
		case "music": p = cfmt.musicfont.name; break
		default:
//hack: the font "Figurato" is used for figured bass
			if (p.indexOf("Fig") > 0)
				font.figb = true
			break
		}
	}
	if (p && !font.name)
	font.name = p
		font.name = p

	if (font.size)
		set_font_fac(font)
	else
		font.swfac = 0

	// 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
		return v[1] / .75
	case "px":		// screen pixel in 1/96 inch
	case "":
		return v[1]
	}
	return NaN
}

︙
403
404
405
406
407
408
409
410








411
412
413
414
415
416
417
415
416
417
418
419
420
421

422
423
424
425
426
427
428
429
430
431
432
433
434
435
436







-
+
+
+
+
+
+
+
+







	align: 'j',
	center: 'c',
	fill: 'f',
	justify: 'j',
	obeylines: 'l',
	ragged: 'f',
	right: 'r',
	skip: 's'
	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]
}
︙
510
511
512
513
514
515
516

517
518
519
520
521
522
523
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543







+







	case "barsperstaff":
	case "infoline":
	case "measurenb":
	case "rbmax":
	case "rbmin":
	case "measrepnb":
	case "shiftunison":
	case "systnames":
		v = parseInt(param)
		if (isNaN(v)) {
			syntax(1, "Bad integer value");
			break
		}
		cfmt[cmd] = v
		break
︙
536
537
538
539
540
541
542
543

544
545
546
547
548
549
550


551
552
553
554
555
556
557
556
557
558
559
560
561
562

563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579







-
+







+
+







	case "pagescale":
	case "parskipfac":
	case "scale":
	case "slurheight":
	case "stemheight":
	case "tieheight":
		f = +param
		if (isNaN(f)) {
		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":
︙
579
580
581
582
583
584
585

586
587
588
589
590
591
592
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615







+







	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+/)
︙
651
652
653
654
655
656
657



658
659
660
661
662
663
664
665
666
667
668
669
670
671
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689

690
691
692
693
694
695
696







+
+
+






-







	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":
	case "volume":
		set_pos(cmd, param)
		break
	case "font":
		get_font_scale(param)
		break
	case "fullsvg":
		if (parse.state != 0) {
︙
762
763
764
765
766
767
768


769
770
771
772
773
774
775
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802







+
+







				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":
︙
813
814
815
816
817
818
819






820
821
822
823
824
825
826
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859







+
+
+
+
+
+







		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"
︙
869
870
871
872
873
874
875
876
877


878
879
880
881








882
883
884
885
886
887
888
902
903
904
905
906
907
908


909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929







-
-
+
+




+
+
+
+
+
+
+
+







}

// use the font
function use_font(font) {
	if (!font.used) {
		font.used = true;
		if (font.fid == undefined) {	// if default font
			font.fid = font_tb.length
			font_tb.push(font)
			font.fid = abc2svg.font_tb.length
			abc2svg.font_tb.push(font)
			if (!font.swfac)
				set_font_fac(font)
			if (!font.pad)
				font.pad = 0

			// set the pointer to the width of the characters
			font.cw_tb = !font.name ? ssw_tb
				: font.name.indexOf("ans") > 0
					? ssw_tb		// sans-serif
					: font.name.indexOf("ono") > 0
						? mw_tb		// monospace
						: sw_tb		// serif
		}
		add_fstyle(".f" + font.fid +
			(cfmt.fullsvg || "") +
			"{" + style_font(font) + "}")
		if (font.src)
			add_fstyle("@font-face{\n\
 font-family:" + font.name + ";\n\
︙
925
926
927
928
929
930
931
932

933
934
935


936
937
938
939
940
941
966
967
968
969
970
971
972

973
974


975
976
977
978
979
980
981
982







-
+

-
-
+
+






		if (font.size)
			font2.size = font.size
		st = st_font(font2)
		if (font.class) {
			font2.class = font.class
			st += ' '+ font.class
		}
		fid = font_st[st]
		fid = abc2svg.font_st[st]
		if (fid != undefined)
			return font_tb[fid]
		font_st[st] = font_tb.length	// will be the font id
			return abc2svg.font_tb[fid]
		abc2svg.font_st[st] = abc2svg.font_tb.length	// will be the font id
		font2.fid = font2.used = undefined
		font = font2
	}
	use_font(font)
	return font
}
Changes to core/front.js.
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22


23
24
25
26
27
28
29
1
2

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

22
23
24
25
26
27
28
29
30


-
+


















-
+
+







// abc2svg - front.js - ABC parsing front-end
//
// Copyright (C) 2014-2022 Jean-Francois Moine
// Copyright (C) 2014-2024 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	sav = {},	// save global (between tunes) definitions
	mac = {},	// macros (m:)
	maci = {}	// first letters of macros
	maci = {},	// first letters of macros
	modone = {}	// hooks done by module

// translation table from the ABC draft version 2.2
var abc_utf = {
	"=D": "Đ",
	"=H": "Ħ",
	"=T": "Ŧ",
	"=d": "đ",
︙
279
280
281
282
283
284
285
286

287
288
289
290
291
292
293
280
281
282
283
284
285
286

287
288
289
290
291
292
293
294







-
+







		glovar = sav.glovar;
		maps = sav.maps;
		mac = sav.mac;
		maci = sav.maci;
		parse.tune_v_opts = null;
		parse.scores = null;
		parse.ufmt = false
		delete parse.ctrl
		delete parse.pq
		init_tune()
		img.chg = true;
		set_page();
	} // end_tune()

	// get %%voice
	function do_voice(select, in_tune) {
︙
378
379
380
381
382
383
384
385
386
387








388
389
390
391
392
393
394
379
380
381
382
383
384
385



386
387
388
389
390
391
392
393
394
395
396
397
398
399
400







-
-
-
+
+
+
+
+
+
+
+







						parse.tune_v_opts[j].
								concat(opts[j])
			}
		}
	} // tune_filter()

	// export functions and/or set module hooks
	if (abc2svg.modules
	 && (abc2svg.modules.hooks.length || abc2svg.modules.g_hooks.length))
		set_hooks()
	if (abc2svg.mhooks) {
		for (i in abc2svg.mhooks) {
			if (!modone[i]) {
				modone[i] = 1 //true
				abc2svg.mhooks[i](self)
			}
		}
	}

	// initialize
	parse.file = file;		// used for errors
	parse.fname = in_fname

	// scan the file
	if (bol == undefined)
︙
433
434
435
436
437
438
439

440
441


442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
439
440
441
442
443
444
445
446


447
448
449
450
451
452
453
454
455
456
457
458
459
460
461


462
463
464
465
466
467
468







+
-
-
+
+













-
-







		parse.istart = parse.bol = bol;
		parse.iend = eol;
		parse.line.index = 0;

		// check if the line is a pseudo-comment or I:
		line0 = file[bol];
		line1 = file[bol + 1]
		if ((line0 == 'I' && line1 == ':')
		if (line0 == '%') {
			if (parse.prefix.indexOf(line1) < 0)
		  || line0 == '%') {
			if (line0 == '%' && parse.prefix.indexOf(line1) < 0)
				continue		// comment

			// change "%%abc xxxx" to "xxxx"
			if (file[bol + 2] == 'a'
			 && file[bol + 3] == 'b'
			 && file[bol + 4] == 'c'
			 && file[bol + 5] == ' ') {
				bol += 6;
				line0 = file[bol];
				line1 = file[bol + 1]
			} else {
				pscom = true
			}
		} else if (line0 == 'I' && line1 == ':') {
			pscom = true
		}

		// pseudo-comments
		if (pscom) {
			pscom = false;
			bol += 2		// skip %%/I:
			text = file.slice(bol, eol)
︙
531
532
533
534
535
536
537
538
539


540
541
542


543
544
545
546

547
548

549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568

569
570
571
572
573
574
575
536
537
538
539
540
541
542


543
544
545


546
547
548



549


550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569

570
571
572
573
574
575
576
577







-
-
+
+

-
-
+
+

-
-
-
+
-
-
+



















-
+







				if (!parse.tune_opts)
					parse.tune_opts = {};
				parse.tune_opts[select] = opt = {
						t_opts: []
//						v_opts: {}
					};
				while (1) {
					bol = ++eol
					if (file[bol] != '%')
					bol = eol
					if (file[bol + 1] != '%')
						break
					eol = file.indexOf('\n', eol);
					if (file[bol + 1] != line1)
					eol = file.indexOf('\n', eol + 1)
					if (file[bol + 2] != line1)
						continue
					bol += 2
					if (eol < 0)
						text = file.slice(bol)
					text = file.slice(bol + 3,
					else
						text = file.slice(bol, eol);
							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 - 1
				parse.eol = bol
				continue
			case "voice":
				if (parse.state != 0) {
					syntax(1, errs.not_in_tune, "%%voice")
					continue
				}
				select = uncomment(a[2])
︙
737
738
739
740
741
742
743




744
745
746
747
748
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754







+
+
+
+





			continue
		}
		txt_add = '\n';
		last_info = line0
	}
	if (include)
		return
	if (parse.state == 1) {
		syntax(1, "End of file in tune header")
		get_key("C")
	}
	if (parse.state >= 2)
		end_tune();
	parse.state = 0
}
Abc.prototype.tosvg = tosvg
Changes to core/gchord.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - gchord.js - chord symbols
//
// Copyright (C) 2014-2022 Jean-Francois Moine
// Copyright (C) 2014-2023 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.
︙
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
124
125
126
127
128
129
130







131
132
133
134
135
136
137







-
-
-
-
-
-
-







		}
		gch.type = type
		while (1) {
			c = text[i]
			if (!c)
				break
			switch (c) {
			case '\\':
				c = text[++i]
				if (c == 'n')
					break
				gch.text += '\\'
				if (!c)
					break
			default:
				gch.text += c;
				i++
				continue
			case '&':			/* skip "&xxx;" */
				while (1) {
					gch.text += c;
︙
155
156
157
158
159
160
161

162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180


181
182
183

184
185
186
187
188
189
190
191
192






193
194
195
196


197
198

199
200








201
202

203
204
205







206
207
208
209
210
211
212
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169





170
171

172
173
174
175
176
177
178
179
180



181
182
183
184
185
186
187



188
189
190
191
192


193
194
195
196
197
198
199
200


201



202
203
204
205
206
207
208
209
210
211
212
213
214
215







+














-
-
-
-
-
+
+
-


+






-
-
-
+
+
+
+
+
+

-
-
-
+
+


+
-
-
+
+
+
+
+
+
+
+
-
-
+
-
-
-
+
+
+
+
+
+
+







				}
				if (c == ';') {
					i++;
					gch.text += c
					continue
				}
				break
			case '\n':		// abcm2ps compatibility
			case ';':
				break
			}
			i++
			break
		}
		gch.otext = gch.text	// save for play accompaniment
		if (!a_gch)
			a_gch = []
		a_gch.push(gch)
	}
}

// transpose a chord symbol
var	note_names = "CDEFGAB",
	acc_name = ["bb", "b", "", "#", "##"]

	function gch_tr1(p) {
	    var	i, o, n, a, ip, b40,
	function gch_tr1(p, tr) {
	    var	i, o, n, ip,
		tr = curvoice.tr_sco,
		csa = p.split('/')

		tr = abc2svg.b40l5[(tr + 202) % 40]	// transpose in the line of fifth
		for (i = 0; i < csa.length; i++) {	// main and optional bass
			p = csa[i];
			o = p.search(/[A-G]/)
			if (o < 0)
				continue		// strange chord symbol!
			ip = o + 1
			a = 0
			while (p[ip] == '#' || p[ip] == '\u266f') {
				a++;

//	bbb fb cb gb db ab eb bb  f c g d a e b f# c# g# d# a# e# b# f##
//	 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5  6  7  8  9 10 11 12  13
			n = "FCGDAEB".indexOf(p[o]) - 1
			if (p[ip] == '#' || p[ip] == '\u266f') {
				n += 7
				ip++
			}
			while (p[ip] == 'b' || p[ip] == '\u266d') {
				a--;
			} else if (p[ip] == 'b' || p[ip] == '\u266d') {
				n -= 7
				ip++
			}
			n += tr					// transpose
			n = note_names.indexOf(p[o]) + 16
			b40 = (abc2svg.pab40(n, a) + tr + 200) % 40

//			// remove chords with double sharps/flats
//			if ((!i && n > 7)			// main chord
//			 || (i && n > 12))			// bass
//				n -= 12
//			else if (i < -7)
//				n += 12

			b40 = abc2svg.b40k[b40]
			csa[i] = p.slice(0, o) +
			csa[i] = p.slice(0, o)
					note_names[abc2svg.b40_p[b40]] +
					acc_name[abc2svg.b40_a[b40] + 2] +
					p.slice(ip)
				+ "FCGDAEB"[(n + 22) % 7]
				+ (n >= 13 ? '##'
					: n >= 6 ? '#'
					: n <= -9 ? 'bb'
					: n <= -2 ? 'b'
					: '')
				+ p.slice(ip)
		}
		return csa.join('/')
	} // gch_tr1

// parser: add the parsed list of chord symbols and annotations
//	to the symbol (note, rest or bar)
//	and transpose the chord symbols
︙
224
225
226
227
228
229
230
231

232
233
234
235
236
237
238
227
228
229
230
231
232
233

234
235
236
237
238
239
240
241







-
+







		}
	}

	if (curvoice.tr_sco) {
		for (i = 0; i < a_gch.length; i++) {
			gch = a_gch[i]
			if (gch.type == 'g')
				gch.text = gch_tr1(gch.text)
				gch.text = gch_tr1(gch.text, curvoice.tr_sco)
		}
	}

	if (s.a_gch)
		s.a_gch = s.a_gch.concat(a_gch)
	else
		s.a_gch = a_gch
︙
278
279
280
281
282
283
284


285
286


287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
281
282
283
284
285
286
287
288
289


290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306






307
308
309
310
311
312
313







+
+
-
-
+
+















-
-
-
-
-
-







		/* set the offsets and widths */
		set_font(gch.font);
		gch.text = str2svg(gch.text)
		wh = gch.text.wh
		switch (gch.type) {
		case '@':
			break
		default:
//		case 'g':			// chord symbol
		case '^':			/* above */
		case '_':			/* below */
//		case '^':			/* above */
//		case '_':			/* below */
			xspc = wh[0] * GCHPRE
			if (xspc > 8)
				xspc = 8;
			gch.x = -xspc;
			break
		case '<':			/* left */
			gch.x = -(wh[0] + 6);
			y_left -= wh[1];
			gch.y = y_left + wh[1] / 2
			break
		case '>':			/* right */
			gch.x = 6;
			y_right -= wh[1];
			gch.y = y_right + wh[1] / 2
			break
		default:			// chord symbol
			xspc = wh[0] * GCHPRE
			if (xspc > 8)
				xspc = 8;
			gch.x = -xspc;
			break
		}
	}

	/* move upwards the top and middle texts */
	y_left /= 2;
	y_right /= 2
	for (ix = 0; ix < s.a_gch.length; ix++) {
︙
391
392
393
394
395
396
397
398

399
400

401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418

419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439

440
441
442
443
444
445
446
390
391
392
393
394
395
396

397
398

399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416

417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437

438
439
440
441
442
443
444
445







-
+

-
+

















-
+




















-
+







			if (y2 < staff_tb[s.st].ann_bot)
				staff_tb[s.st].ann_bot = y2
		}
		break
	}

	if (an.type != '@') {
		if (y > 24)
		if (y >= 0)
			y_set(s.st, 1, x, w, y + h + pad + 2)
		else if (y < 0)
		else
			y_set(s.st, 0, x, w, y - pad)
	}

	use_font(an.font)
	set_font(an.font)
	set_dscale(s.st)
	if (user.anno_start)
		user.anno_start("annot", an.istart, an.iend,
			x - 2, y + h + 2, w + 4, h + 4, s)
	xy_str(x, y + dy, an.text)
	if (user.anno_stop)
		user.anno_stop("annot", an.istart, an.iend,
			x - 2, y + h + 2, w + 4, h + 4, s)
} // draw_gchord()

// draw all chord symbols
function draw_all_chsy() {
    var	s, san1, an, i, y, w,
    var	s, san1, an, i, x, y, w,
	n_an = 0,		// max number of annotations
	minmax = new Array(nstaff + 1)

	// set a vertical offset to all the chord symbols/annotations
	function set_an_yu(j) {
	    var	an, i, s, x, y, w

		for (s = san1 ; s; s = s.ts_next) {
			an = s.a_gch
			if (!an)
				continue
			i = an.length - j - 1
			an = an[i]
			if (!an)
				continue
			if (an.pos == C.SL_ABOVE) {
				x = s.x + an.x
				w = an.text.wh[0]
				if (w && x + w > realwidth)
					x = realwidth - w // let the text in the page
				y = y_get(s.st, 1, x, w) + 2	// y / staff
				y = y_get(s.st, 1, x, w)	// y / staff
				if (an.type == 'g' && y < minmax[s.st].yup)
					y = minmax[s.st].yup
			} else if (an.pos == C.SL_BELOW
				|| an.pos == C.SL_HIDDEN) {
				continue
			} else {
				x = s.x + an.x
︙
487
488
489
490
491
492
493

494


495
496

497
498
499
500

501
502
503
504
505
506
507
486
487
488
489
490
491
492
493
494
495
496
497

498
499
500
501

502
503
504
505
506
507
508
509







+

+
+

-
+



-
+







			san1 = s	// first chord symbol / annotation
		i = an.length
		if (i > n_an)
			n_an = i
		while (--i >= 0) {
			if (an[i].type == 'g') {
				an = an[i]
				x = s.x + an.x
				w = an.text.wh[0]
				if (w && x + w > realwidth)
					x = realwidth - w
				if (an.pos == C.SL_ABOVE) {
					y = y_get(s.st, true, s.x, w) + 2
					y = y_get(s.st, true, x, w)
					if (y > minmax[s.st].yup)
						minmax[s.st].yup = y
				} else if (an.pos == C.SL_BELOW) {
					y = y_get(s.st, false, s.x, w) - 2
					y = y_get(s.st, false, x, w) - 2
					if (y < minmax[s.st].ydn)
						minmax[s.st].ydn = y
				}
				break
			}
		}
	}
︙
Changes to core/license.
1
2
3

1
2

3


-
+
// abc2svg - ABC to SVG translator
// @source: https://chiselapp.com/user/moinejf/repository/abc2svg
// Copyright (C) 2014-2023 Jean-Francois Moine - LGPL3+
// Copyright (C) 2014-2024 Jean-Francois Moine - LGPL3+
Changes to core/lyrics.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - lyrics.js - lyrics
//
// Copyright (C) 2014-2022 Jean-Francois Moine
// Copyright (C) 2014-2023 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.
︙
181
182
183
184
185
186
187
188

189
190
191
192
193
194
195
181
182
183
184
185
186
187

188
189
190
191
192
193
194
195







-
+







			}
			s = s.next;
			i++
			continue
		case '-':
		case '_':
			word = p[i]
			ln = 2			// line continuation
			ln = p[i] == '-' ? 2 : 3	// line continuation
			break
		case '*':
			word = ""
			break
		default:
			word = "";
			while (1) {
︙
285
286
287
288
289
290
291
292

293
294
295
296
297
298
299
300
301
302
303
304
305
306



307
308
309
310
311

312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328

329
330
331
332
333
334
335
336
337
338
339
340
341
342
343

344
345
346
347
348
349
350
285
286
287
288
289
290
291

292
293
294
295
296
297
298
299
300
301
302
303
304


305
306
307
308
309
310
311

312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327


328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351







-
+












-
-
+
+
+




-
+















-
-
+















+







		if (!s2.a_ly)
			continue
		i = s2.a_ly.length
		while (--i >= 0) {
			ly = s2.a_ly[i]
			if (!ly)
				continue
			if (ly.ln != 2)
			if (!ly.ln || ly.ln < 2)
				break
		}
		if (i >= 0)
			break
	}

	// define the offset of the words
	for (i = 0; i < a_ly.length; i++) {
		ly = a_ly[i]
		if (!ly)
			continue
		gene.curfont = ly.font
		ly.t = p = str2svg(ly.t)
		if (ly.ln == 2) {
		ly.t = str2svg(ly.t)
		p = ly.t.replace(/<[^>]*>/g, '')	// remove the XML tags
		if (ly.ln >= 2) {
			ly.shift = 0
			continue
		}
		spw = cwid(' ') * ly.font.swfac
		w = p.wh[0] + spw * 1.5
		w = ly.t.wh[0]
		if (s.type == C.GRACE) {		// %%graceword
			shift = s.wl
		} else if ((p[0] >= '0' && p[0] <= '9' && p.length > 2)
			|| p[1] == ':'
			|| p[0] == '(' || p[0] == ')') {
			if (p[0] == '(') {
				sz = spw
			} else {
				j = p.indexOf(' ')
				set_font(ly.font)
				if (j > 0)
					sz = strwh(p.slice(0, j))[0]
				else
					sz = w * .2
			}
			w -= sz
			shift = w * .4
			shift = (w - sz) * .4
			if (shift > 14)
				shift = 14
			shift += sz
			if (p[0] >= '0' && p[0] <= '9') {
				if (shift > align)
					align = shift
			}
		} else {
			shift = w * .4
			if (shift > 14)
				shift = 14
		}
		ly.shift = shift
		if (shift > wl)
			wl = shift		// max left space
		w += spw * 1.5			// space after the syllable
		w -= shift			// right width
		if (w > wx)
			wx = w			// max width
	}

	// set the left space
	while (!s3.seqst)
︙
414
415
416
417
418
419
420

421
422
423
424
425
426



427
428
429
430
431
432
433

434
435
436
437
438

439
440
441

442
443
444
445
446
447
448
449

450
451
452
453
454
455
456
415
416
417
418
419
420
421
422
423
424
425



426
427
428
429
430
431
432
433
434

435
436
437
438
439

440
441
442

443
444
445
446
447
448
449
450

451
452
453
454
455
456
457
458







+



-
-
-
+
+
+






-
+




-
+


-
+







-
+







				}
			}
			continue
		}
		if (ly.font != gene.curfont)		/* font change */
			gene.curfont = ly.font
		p = ly.t;
		ln = ly.ln || 0
		w = p.wh[0]
		shift = ly.shift
		if (hyflag) {
			if (ly.ln == 2 && p == "_") {	// '_'
				p = "-"
			} else if (ly.ln != 2) {	// not '-'
			if (ln == 3) {			// '_'
				ln = 2
			} else if (ln < 2) {		// not '-'
				out_hyph(lastx, y, s.x - shift - lastx);
				hyflag = false;
				lastx = s.x + s.wr
			}
		}
		if (lflag
		 && (ly.ln != 2 || p != "_")) {	// not '_'
		 && ln != 3) {				// not '_'
			out_wln(lastx + 3, y, x0 - lastx + 3);
			lflag = false;
			lastx = s.x + s.wr
		}
		if (ly.ln == 2) {		// '-' or '_'
		if (ln >= 2) {				// '-' or '_'
			if (x0 == 0 && lastx > s.x - 18)
				lastx = s.x - 18
			if (p == '-')
			if (ln == 2)			// '-'
				hyflag = true
			else
				lflag = true;
			x0 = s.x - shift
			continue
		}
		x0 = s.x - shift;
		if (ly.ln)			// '-' at end
		if (ln)					// '-' at end
			hyflag = true
		if (user.anno_start || user.anno_stop) {
			s2 = {
				p_v: s.p_v,
				st: s.st,
				istart: ly.istart,
				iend: ly.iend,
︙
481
482
483
484
485
486
487
488

489
490
491
492
493
494
495
483
484
485
486
487
488
489

490
491
492
493
494
495
496
497







-
+








	/* see if any underscore in the next line */
	for (p_voice.s_next; s; s = s.next) {
		if (s.type == C.NOTE) {
			if (!s.a_ly)
				break
			ly = s.a_ly[j]
			if (ly && ly.ln && ly.t == "_") {
			if (ly && ly.ln == 3) {		 // '_'
				lflag = true;
				x0 = realwidth - 15
				if (x0 < lastx + 12)
					x0 = lastx + 12
			}
			break
		}
︙
508
509
510
511
512
513
514
515


516
517

518
519
520
521
522
523
524
525
526

527
528
529
530
531
532
533
510
511
512
513
514
515
516

517
518
519

520
521
522
523
524
525
526
527
528

529
530
531
532
533
534
535
536







-
+
+

-
+








-
+







	set_font("vocal")
	if (incr > 0) {				/* under the staff */
		if (y > -tsfirst.fmt.vocalspace)
			y = -tsfirst.fmt.vocalspace;
		y *= sc
		for (j = 0; j < nly; j++) {
			y -= a_h[j] * 1.1;
			draw_lyric_line(p_voice, j, y)
			draw_lyric_line(p_voice, j,
				y + a_h[j] * .22)	// (descent)
		}
		return (y - a_h[j - 1] / 6) / sc
		return y / sc
	}

	/* above the staff */
	top = staff_tb[p_voice.st].topbar + tsfirst.fmt.vocalspace
	if (y < top)
		y = top;
	y *= sc
	for (j = nly; --j >= 0;) {
		draw_lyric_line(p_voice, j, y);
		draw_lyric_line(p_voice, j, y + a_h[j] * .22)
		y += a_h[j] * 1.1
	}
	return y / sc
}

// -- draw all the lyrics --
/* (the staves are not yet defined) */
︙
656
657
658
659
660
661
662
663

664
665
666
667
668
669
670
671
672
673
674

675
676
677
678
679
680
681
682
683
684
685
659
660
661
662
663
664
665

666
667
668
669
670
671
672
673
674
675
676

677
678
679
680
681
682
683
684
685
686
687
688







-
+










-
+











	for (v = 0; v < nv; v++) {
		p_voice = voice_tb[v]
		if (!p_voice.sym)
			continue
		st = p_voice.st;
		if (lyst_tb[st].a) {
			top = lyst_tb[st].top + 2
			for (s = p_voice.sym.next; s; s = s.next) {
			for (s = p_voice.sym; s; s = s.next) {
/*fixme: may have lyrics crossing a next symbol*/
				if (s.a_ly) {
/*fixme:should set the real width*/
					y_set(st, 1, s.x - 2, 10, top)
				}
			}
		}
		if (lyst_tb[st].b) {
			bot = lyst_tb[st].bot - 2
			if (nly_tb[p_voice.v] > 0) {
				for (s = p_voice.sym.next; s; s = s.next) {
				for (s = p_voice.sym; s; s = s.next) {
					if (s.a_ly) {
/*fixme:should set the real width*/
						y_set(st, 0, s.x - 2, 10, bot)
					}
				}
			} else {
				y_set(st, 0, 0, realwidth, bot)
			}
		}
	}
}
Changes to core/mei.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - mei.js - MEI front-end
//
// Copyright (C) 2019-2021 Jean-Francois Moine
// Copyright (C) 2019-2023 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.
︙
1229
1230
1231
1232
1233
1234
1235

1236
1237
1238
1239
1240
1241
1242
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243







+







					not2 = s2.notes[m2]
					if (not1.pit == not2.pit) {
						not1.tie_ty = ty
						not1.tie_e = not2
						not2.tie_s = not1
					}
				}
			}
		}
		s1.ti1 = s2.ti2 = true
	}, // tie()

	trill: function(tag) {
	    var	s2,
		s = get_ref(tag)
︙
Changes to core/modules.js.
︙
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
52
53
54
55
56
57
58


59
60
61
62
63
64
65







-
-







	soloffs: {},
	sth: {},
	strtab: {},
	temperament: { fn: 'temper' },
	tropt: {},

	nreq: 0,
	hooks: [],
	g_hooks: [],

	// scan the file and find the required modules
	// @file: ABC file
	// @relay: (optional) callback function for continuing the treatment
	// @errmsg: (optional) function to display an error message if any
	//	This function gets one argument: the message
	// return true when all modules are loaded
︙
Changes to core/music.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - music.js - music generation
//
// Copyright (C) 2014-2023 Jean-Francois Moine
// Copyright (C) 2014-2024 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.
︙
236
237
238
239
240
241
242

243

244
245
246
247
248
249
250
236
237
238
239
240
241
242
243

244
245
246
247
248
249
250
251







+
-
+








	if (p1 > ps + 4) {		// if interval greater than a sixth
		if (dx1 > dx2)
			dx2 = dx1	// align the accidentals
		notes[i1].shac = notes[i2].shac = dx2
	} else {
		notes[i1].shac = dx1
		if (notes[i1].pit != notes[i2].pit)
		dx1 += 7
			dx1 += 7
		notes[i2].shac = dx2 = dx1
	}
	dx2 += 7

	// shift the remaining accidentals
	for (i = i1; --i > i2; ) {		// from top to bottom
		acc = notes[i].acc
︙
345
346
347
348
349
350
351
352
353


354
355
356
357

358
359
360
361
362
363
364
346
347
348
349
350
351
352


353
354
355
356
357

358
359
360
361
362
363
364
365







-
-
+
+



-
+







//fixme
error(2, s, "Bad linkage")
		s.ts_prev = null
	}
	s.seqst = !s.ts_prev
		|| s.time != s.ts_prev.time
		|| (w_tb[s.ts_prev.type] != w_tb[s.type]
		 && w_tb[s.ts_prev.type])
	if (!next)
		 && !!w_tb[s.ts_prev.type])
	if (!next || next.seqst)
		return
	next.seqst = next.time != s.time ||
			(w_tb[s.type] != w_tb[next.type]
			 && w_tb[s.type])
			 && !!w_tb[s.type])
	if (next.seqst) {
		old_wl = next.wl
		self.set_width(next)
		if (next.a_ly)
			ly_set(next)
		if (!next.shrink) {
			next.shrink = next.wl
︙
743
744
745
746
747
748
749
750

751
752
753
754
755
756
757
744
745
746
747
748
749
750

751
752
753
754
755
756
757
758







-
+







				wlnote -= 3
				break
			}
		}

		/* room for the decorations */
		if (s.a_dd)
			wlnote += deco_width(s)
			wlnote = deco_width(s, wlnote)

		/* space for flag if stem goes up on standalone note */
		if (s.beam_st && s.beam_end
		 && s.stem > 0 && s.nflags > 0) {
			if (s.wr < s.xmx + 9)
				s.wr = s.xmx + 9
		}
︙
779
780
781
782
783
784
785
786
787
788
789








790
791
792
793
794
795
796
780
781
782
783
784
785
786




787
788
789
790
791
792
793
794
795
796
797
798
799
800
801







-
-
-
-
+
+
+
+
+
+
+
+







		 && wlnote < 20)
			wlnote = 20

		wlw = wlnote

		if (s2) {
			switch (s2.type) {
			case C.NOTE:	/* extra space when up stem - down stem */
				if (s2.stem > 0 && s.stem < 0) {
					if (wlw < 7)
						wlw = 7
			case C.NOTE:

				// change the spacing when stems in reverse directions
				if (s.stem * s2.stem < 0) {
					if (s.stem < 0)
						wlw += 5
					else
						wlw -= 3
				}

				/* make sure helper lines don't overlap */
				if ((s.y > 27 && s2.y > 27)
				 || (s.y < -3 && s2.y < -3)) {
					if (wlw < 6)
						wlw = 6
︙
804
805
806
807
808
809
810



811
812
813
814
815
816
817
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825







+
+
+







				break
			case C.CLEF:		/* extra space at start of line */
				if (s2.second
				 || s2.clef_small)
					break
				// fall thru
			case C.KEY:
				if (s.a_gch)
					wlw += 4 // have some room for the chord symbols
				// fall thru
			case C.METER:
				wlw += 3
				break
			}
		}

		/* leave room for guitar chord */
︙
830
831
832
833
834
835
836
837

838
839
840
841
842
843
844
838
839
840
841
842
843
844

845
846
847
848
849
850
851
852







-
+







		return
	case C.SPACE:
		xx = s.width / 2;
		s.wr = xx
		if (s.a_gch)
			xx = gchord_width(s, xx, xx)
		if (s.a_dd)
			xx += deco_width(s);
			xx = deco_width(s, xx)
		s.wl = xx
		return
	case C.BAR:
		bar_type = s.bar_type
			switch (bar_type) {
			case "|":
				w = 5		// 3 + 2
︙
864
865
866
867
868
869
870






871
872
873
874
875
876
877
878
879
880
881
882
883
884
885

886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901






902
903
904
905
906
907
908
909
910
911
912
913
914
915
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898

899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924




925
926
927
928
929
930
931







+
+
+
+
+
+














-
+
















+
+
+
+
+
+



-
-
-
-







			s.wl = w
			if (s.next
			 && s.next.type != C.METER)
				s.wr = 7
			else
				s.wr = 5
//			s.notes[0].shhd = (w - 5) * -.5

		// special case for (mainly) "|| !invisible! |:"
		if (s.invis)
//fixme
//		 && s.prev && s.prev.bar_type)
			s.wl = s.wr = 2

			/* if preceeded by a grace note sequence, adjust */
			s2 = s.prev
			if (s2 && s2.type == C.GRACE)
				s.wl -= 6
			for ( ; s2; s2 = s2.prev) {
				if (w_tb[s2.type]) {
					if (s2.type == C.STBRK)
						s.wl -= 12
					break
				}
			}

		if (s.a_dd)
			s.wl += deco_width(s)
			s.wl = deco_width(s, s.wl)

		/* have room for the repeat numbers / chord indication */
		if (s.text && s.text.length < 4
		 && s.next && s.next.a_gch) {
			set_font("repeat");
			s.wr += strwh(s.text)[0] + 2
			if (cfmt.measurenb > 0 & s.bar_num
			 && s.bar_num % cfmt.measurenb)
				s.wr += 4
		}
		return
	case C.CLEF:
// (there may be invisible clefs in empty staves)
		if (s.invis) {
			s.wl = s.wr = 1		// (!! not 0 !!)
			return
		}
		if (s.prev && s.prev.type == C.STBRK) {
			s.wl = 6
			s.wr = 13
			delete s.clef_small
			return
		}
		s.wl = s.clef_small ? 11 : 12
		s.wr = s.clef_small ? 8 : 13
		if (s.prev && s.prev.type == C.STBRK) {
			s.wl -= 6
			delete s.next.clef_small
		}
		return
	case C.KEY:
		if (s.invis) {				// if no accidental
			s.wl = s.wr = 0			// no width
			return
		}
		s.wl = 0
︙
1281
1282
1283
1284
1285
1286
1287




1288
1289
1290
1291
1292
1293
1294
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314







+
+
+
+







				s_chs = s;
			self.set_width(s);
			st = s.st
			if (xl[st] == undefined)
				xl[st] = 0
			if (wr[st] == undefined)
				wr[st] = 0;
			if (s.prev && s.prev.st != st) {
				xl[st] = xl[s.prev.st]
				wr[st] = wr[s.prev.st]
			}
			val = xl[st] + wr[st] + s.wl
			if (val > maxx)
				maxx = val
			if (s.dur && s.dur != s.notes[0].dur	// if in tuplet
			 && first)			// (first time only)
				itup = 1
			s = s.ts_next
︙
1308
1309
1310
1311
1312
1313
1314
1315

1316
1317
1318
1319

1320
1321
1322
1323
1324
1325
1326
1327
1328
1329






1330
1331
1332
1333
1334
1335
1336
1328
1329
1330
1331
1332
1333
1334

1335
1336
1337
1338

1339
1340
1341
1342
1343
1344
1345
1346
1347


1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360







-
+



-
+








-
-
+
+
+
+
+
+







				stup = s2
		} else if (stup && stup.v == s2.v) {
			set_sp_tup(stup, s2)
			stup = null
		}

		if (!s2.shrink) {
		    if (!s2.space && s2.type == C.CLEF
		    if (s2.type == C.CLEF
		     && !s2.ts_prev.bar_type) {
			delete s2.seqst;		/* no space */
			s2.time = tim
		    } else if (s2.dur) {
		    } else {
			s2.shrink = 10			// cannot be null
		    }
		}
		tim = s2.time
		if (!s)
			break

		// update the min left space per staff
		for (st = 0; st < wr.length; st++)
			wr[st] = 0;
		s = s2
		do {
			wr[s.st] = 0
			s = s.ts_next
		} while (!s.seqst)

		xa = maxx
		do {
			st = s2.st;
			xl[st] = xa
			if (s2.wr > wr[st])
				wr[st] = s2.wr
			s2 = s2.ts_next
︙
1523
1524
1525
1526
1527
1528
1529


1530
1531
1532
1533
1534
1535
1536
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562







+
+







			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;
︙
1545
1546
1547
1548
1549
1550
1551


1552
1553
1554
1555
1556
1557
1558
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586







+
+







			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;
︙
1636
1637
1638
1639
1640
1641
1642


1643
1644
1645
1646
1647












































1648
1649
1650
1651
1652
1653
1654
















1655









1656
1657



1658
1659




1660
1661
1662
1663
1664



1665
1666
1667
1668
1669

1670



1671
1672
1673
1674
1675


1676

1677
1678
1679
1680
1681
1682

1683
1684

1685
1686
1687
1688

1689
1690
1691
1692
1693
1694
1695



1696
1697
1698
1699
1700
1701









1702
1703
1704
1705




1706
1707
1708


1709
1710






1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728

1729
1730
1731

1732
1733
1734
1735
1736
1737
1738
1664
1665
1666
1667
1668
1669
1670
1671
1672





1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717






1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743


1744
1745
1746
1747

1748
1749
1750
1751
1752
1753



1754
1755
1756



1757
1758
1759

1760
1761
1762
1763
1764
1765
1766
1767
1768
1769

1770






1771
1772

1773




1774







1775
1776
1777






1778
1779
1780
1781
1782
1783
1784
1785
1786
1787



1788
1789
1790
1791
1792


1793
1794


1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817

1818
1819
1820

1821
1822
1823
1824
1825
1826
1827
1828







+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
+
+
+
+
+
-
-
+
+
+

-
+
+
+
+


-
-
-
+
+
+
-
-
-


+
-
+
+
+





+
+
-
+
-
-
-
-
-
-
+

-
+
-
-
-
-
+
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+

-
-
-
+
+
+
+

-
-
+
+
-
-
+
+
+
+
+
+

















-
+


-
+







			// :][: -> :|] [|:
			i = (t[2].length / 2) | 0
			t1 = t[1] + '|' + t[2].slice(0, i)
			t2 = t[2].slice(i) +'|' + t[3]
		}
	    } // new_typ()

		// change or add a bar for the voice in the previous line
		function eol_bar(s,		// bar |:
		s = so				// start of sequence
		while (s.ts_prev
		 && s.ts_prev.time == so.time) {
			s = s.ts_prev
			if (s.bar_type) {
				 so,		// start of new line
				 sst) {		// first bar (for seqst)
		    var	s1, s2, s3

			// check if a bar in the previous line
			for (s1 = so.ts_prev ; s1.time == s.time; s1 = s1.ts_prev) {
				if (s1.v != s.v)
					continue
				if (s1.bar_type) {
					if (s1.bar_type != '|')
						return	// don't change
					s2 = s1		// last symbol in previous line
					break
				}
				if (!s3)
					s3 = s1.next	// possible anchor for the new bar
			}
			if (!s2) {			// if no symbol in previous line
				s2 = clone(s)
				if (!s3)
					s3 = s
				s2.next = s3
				s2.prev = s3.prev
				if (s2.prev)
					s2.prev.next = s2
				s3.prev = s2
				s2.ts_prev = so.ts_prev	// time linkage
				s2.ts_prev.ts_next = s2
				s2.ts_next = so
				so.ts_prev = s2
				if (s == sst)		// if first inserted bar
					s2.seqst = 1 //true
				if (s2.seqst) {
					for (s = s2.ts_next; !s.seqst; s = s.ts_next)
						;
					s2.shrink = s.shrink
					s.shrink = s2.wr + s.wl
					s2.space = s.space
					s.space = 0
				}
				delete s2.part
			}
			s2.bar_type = "||"
		} // eol_bar()

				// if repeat variant, move the new line
				if (s.bar_type[0] == '['
				 && s.text
				 && s.ts_next == so)
					so = s
				s1 = s		// first previous bar
		// check if there is a left repeat bar at start of the new line
		s = so				// start of new music line
		while (s && s.time == so.time) {
			if (s.bar_type && s.bar_type.slice(-1) == ':') {
				s2 = s
				break
			}
			s = s.ts_next
		}
		if (s2) {
			s = s2
			while (1) {		// loop on all voices
				eol_bar(s2, so, s)
				s2 = s2.ts_next
				if (!s2 || s2.seqst)
					break
			}
			return so
		}

		s = so
		while (s.ts_prev
		 && s.ts_prev.time == so.time) {
			s = s.ts_prev
			if (s.bar_type)
				s1 = s		// first previous bar
//			if (s.type == C.GRACE)
//				so = s		// keep the grace notes in the next line
			else if (!s1 && s.type == C.GRACE && s.seqst)
				so = s		// if grace note after a bar
						// move the start of line
		}
		if (!s1)
		if (!s1
		 || !s1.bar_type
		 || (s1.bar_type.slice(-1) != ':'
		  && !s1.text))
			return so

		// search the insertion point in the new line
		for (s = so; ; s = s.ts_next) {
			switch (s.type) {
		// search the new start of the next line
		for (so = s1; so.time == s1.time; so = so.ts_prev) {
			switch (so.ts_prev.type) {
//			default:
//				if (w_tb[s.type])
//					break
			case C.KEY:
			case C.METER:
//			case C.PART:
			case C.CLEF:
			case C.TEMPO:
			case C.STAVES:
			case C.STBRK:
				continue
			}
			break
		}

		// put the new bar before the end of music line
		s = s1				// keep first bar
		while (s1 != so) {
		while (1) {
		    if (s1.bar_type
		     && s1.next
		     && (s1.bar_type.slice(-1) == ':'
		      || s1.text)
		     && s1.bar_type != ':') {
			new_type(s1)		// return t1 and t2
			new_type(s1)
			s2 = clone(s1)
			s1.bar_type = t1
			s2.bar_type = t1
			delete s1.a_gch
			if (t1 == '|')
				delete s1.rbstop // (needed for play variant)
			s2.bar_type = t2
			s1.bar_type = t2
			lkvsym(s2, s1.next)	// voice
			while (1) {
				if (s.type != C.BAR
//fixme: pb if inverted voices
				 || s.v > s2.v)
					break
				s = s.ts_next
			s2.ts_prev = so.ts_prev
			s2.ts_prev.ts_next = s2
			s2.ts_next = so
			}
			lktsym(s2, s)		// time
			if (s1.seqst)
				s2.seqst = 1
			if (s == so)
				so = s2
			so.ts_prev = s2
			if (s1 == s)
				s2.seqst = 1 //true
			s2.next = s1
			if (s2.prev)
				s2.prev.next = s2
			s1.prev = s2
			if (s1.rbstop)
				s2.rbstop = s1.rbstop
			if (s1.text) {
				s2.invis = true
				delete s1.text
				delete s1.rbstart
				s1.invis = 1 //true
				delete s1.xsh
				delete s2.text
				delete s2.rbstart
			}
			delete s1.part
			delete s2.a_dd
			delete s2.part
			delete s1.a_dd
		    }
			s1 = s1.ts_next
			delete s1.a_gch
			do {
				s1 = s1.ts_next
			} while (!s1.seqst && !s1.bar_type)
			if (s1.seqst)
				break
		}
		return so
	} // bardiv()

	// set the start of line marker
	function set_eol(s) {
		if (cfmt.custos && voice_tb.length == 1)
			custos_add(s)
		s.nl = true
		s = s.ts_prev
		if (s.type != C.BAR)
			add_end_bar(s)
	} // set_eol()

	// put the warning symbols
	// the new symbols go in the previous line
	function do_warn(s) {		// start of next line
	    var s1, s2, s3, s4
	    var s1, s2, s3, s4, w

		// advance in the next line
		for (s2 = s; s2; s2 = s2.ts_next) {
		for (s2 = s; s2 && s2.time == s.time; s2 = s2.ts_next) {
			switch (s2.type) {
			case C.KEY:
				if (!s.fmt.keywarn
				 || s2.invis)
					continue
				for (s1 = s.ts_prev; s1 ;s1 = s1.ts_prev) {
					if (s1.type != C.METER)
︙
1780
1781
1782
1783
1784
1785
1786

1787





1788

1789

1790
1791
1792




1793









1794

1795
1796
1797
1798
1799
1800
1801
1870
1871
1872
1873
1874
1875
1876
1877

1878
1879
1880
1881
1882
1883
1884

1885
1886


1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900

1901
1902
1903
1904
1905
1906
1907
1908







+
-
+
+
+
+
+

+
-
+

-
-
+
+
+
+

+
+
+
+
+
+
+
+
+
-
+







				lkvsym(s3, s1)		// voice link

				// care with spacing
				if (s3.seqst) {
					self.set_width(s3)
					s3.shrink = s3.wl
					s4 = s3.ts_prev
					w = 0
					while (!s4.seqst)
					while (1) {
						if (s4.wr > w)
							w = s4.wr
						if (s4.seqst)
							break
						s4 = s4.ts_prev
					}
					s3.shrink += s4.wr
					s3.shrink += w
					s3.space = 0
					s4 = s3.ts_next
					while (!s4.seqst)
					s4 = s3
					while (1) {
						if (s4.ts_next.seqst)
							break
						s4 = s4.ts_next
					}
					w = 0
					while (1) {
						if (s4.wl > w)
							w = s4.wl
						s4 = s4.ts_next
						if (s4.seqst)
							break
					}
					s4.shrink = s3.wr + s4.wl
					s4.shrink = s3.wr + w
				}
				delete s3.part
				continue
			}
			if (w_tb[s2.type])
				break		// symbol with a width
		}
︙
2125
2126
2127
2128
2129
2130
2131


2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143

2144
2145
2146
2147
2148
2149
2150
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260







+
+












+







				mc = {
					lm: cfmt.leftmargin,
					rm: cfmt.rightmargin
				}
				break
			case "mc_new":
			case "mc_end":
				if (!mc)
					break
				cfmt.leftmargin = mc.lm
				cfmt.rightmargin = mc.rm
				img.chg = 1 //true
				break
			}
		}
		if (!s.ts_next) {
			s = null
		} else if (!s.soln) {
			continue
		} else {
			s.soln = false
//fixme what if new line wanted?
			if (s.time == s2.time)
				continue	// empty music line!
			while (!s.seqst)
				s = s.ts_prev
		}
		set_page()
		lwidth = get_lwidth() - lsh[1] - ckw[0]
︙
2228
2229
2230
2231
2232
2233
2234
2235

2236
2237

2238
2239

2240
2241
2242
2243
2244
2245
2246

2247
2248
2249
2250

2251
2252
2253
2254


2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279

2280
2281
2282
2283
2284

2285
2286
2287
2288
2289
2290
2291
2292

2293
2294
2295
2296
2297

2298
2299
2300
2301
2302














































2303
2304
2305
2306
2307
2308
2309
2338
2339
2340
2341
2342
2343
2344

2345
2346

2347
2348

2349

2350





2351




2352




2353
2354

















2355
2356
2357
2358
2359



2360
2361
2362
2363
2364

2365
2366
2367
2368
2369
2370



2371
2372
2373
2374
2375

2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434







-
+

-
+

-
+
-

-
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-





-
-
-
+




-
+





-
-
-
+




-
+





+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







//		s.ymx = top;
		s.ymx = 24;
		s.ymn = 0
		break
	}
}

// set the ottava decorations and the associated pitch shift
// set the pitch of the notes under an ottava sequence
function set_ottava() {
    var	s, st, delta, note, g, o,
    var	s, s1, st, o, d,
	m = nstaff + 1,
	staff_d = new Int16Array(new Array(m * 2)),	// (-ottava)
	staff_d = new Int8Array(m)
	staff_noo = new Int8Array(new Array(m))		// number of ottava values

	// add an ottava decoration
	function ottava_add(s, ottava, start) {
	    var	dc_st = ["15mb(", "8vb(", null, "8va(", "15ma("],
		dc_en = ["15mb)", "8vb)", null, "8va)", "15ma)"];

	// update the pitches of a symbol
		a_dcn.push((start ? dc_st : dc_en)[2 + ottava])
		deco_cnv(s)
	}

	function sym_ott(s, d) {
	for (st = 0; st <= nstaff; st++) {
		staff_d[st] = 0;
		staff_noo[st] = 0
	}
	    var	g, m, note

	for (s = tsfirst; s; s = s.ts_next) {
		st = s.st
		if (s.ottava != undefined)
		    while (s.ottava.length) {
			o = s.ottava.shift()
			if (o) {
				if (staff_noo[st]++ == 0) {	// if first ottava
					ottava_add(s, o, true)
					staff_d[st] = -o * 7
				}
			} else {
				if (--staff_noo[st] == 0) {	// if last ottava
					ottava_add(s, -staff_d[st] / 7);
					staff_d[st] = 0
				}
			}
		}
		switch (s.type) {
		case C.REST:
			if (voice_tb.length == 1)
				break
		case C.NOTE:
			delta = staff_d[st]
			if (delta
			 && !s.p_v.ckey.k_drum) {
			if (!s.p_v.ckey.k_drum) {
				for (m = s.nhd; m >= 0; m--) {
					note = s.notes[m];
					if (!note.opit)
						note.opit = note.pit;
					note.pit += delta
					note.pit += d
				}
			}
			break
		case C.GRACE:
			for (g = s.extra; g; g = g.next) {
				delta = staff_d[st]
				if (delta
				 && !s.p_v.ckey.k_drum) {
				if (!s.p_v.ckey.k_drum) {
					for (m = 0; m <= g.nhd; m++) {
						note = g.notes[m]
						if (!note.opit)
							note.opit = note.pit
						note.pit += delta
						note.pit += d
					}
				}
			}
			break
		}
	} // sym_ott()

	// remove the ottava decorations of a symbol
	function deco_rm(s) {
		for (var i = s.a_dd.length; --i >= 0;) {
			if (s.a_dd[i].name.match(/1?[85][vm][ab]/))
				s.a_dd.splice(i, 1)
		}
	} // deco_rm()

	for (s = tsfirst; s; s = s.ts_next) {
		st = s.st
		o = s.ottava
		if (o) {				// some ottava start or stop
			if (o[0]) {
				if (staff_d[st] && !o[1]) {
					sym_ott(s, staff_d[st])
					deco_rm(s)
					continue	// same ottava
				}
			} else if (!staff_d[st]) {
				deco_rm(s)
				continue		// already no ottava
			}
			s1 = s
			while (s1 && !s1.seqst)
				s1 = s1.ts_prev
			if (s1) {			// update the previous symbols
				while (s1 != s) {
					if (s1.st == st) {
						if (o[1])
							sym_ott(s1, -staff_d[st])
						if (o[0])
							sym_ott(s1, -o[0] * 7)
					}
					s1 = s1.ts_next
				}
			}
			if (o[0]) {			// ottava start
				staff_d[st] = -o[0] * 7
			} else {
				staff_d[st] = 0
			}
		}
		if (staff_d[st])
			sym_ott(s, staff_d[st])
	}
}

// expand the multi-rests as needed
function mrest_expand() {
    var	s, s2

︙
2327
2328
2329
2330
2331
2332
2333
2334

2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345

2346
2347
2348
2349
2350
2351
2352


2353
2354
2355
2356
2357
2358
2359
2452
2453
2454
2455
2456
2457
2458

2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469

2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486







-
+










-
+







+
+







		s.notes[0].dur = s.dur = s.dur_orig = dur
		s.nflags = -2
		s.head = C.FULL
		s.fmr = 1			// full measure rest

		/* add the bar(s) and rest(s) */
		tim = s.time + dur
		s3 = s2 = s
		s3 = s
		while (--nb > 0) {

			// add the bar
			s2 = clone(bar)
			delete s2.soln
			delete s2.a_gch
			delete s2.a_dd
			delete s2.text
			delete s2.rbstart
			delete s2.rbstop
			lkvsym(s2, bar)
			lkvsym(s2, s.next)	// before symbol at end of rests

			s2.time = tim
			while (s3.time < tim)
				s3 = s3.ts_next	// bar at end of measure
			while (s3 && s3.v < s.v && s3.type == C.BAR)
				s3 = s3.ts_next	// keep in order
			if (s3) {
				if (s3.bar_type)
					s3.seqst = 0 //false
				lktsym(s2, s3)
				if (s3.type == C.BAR)
					delete s3.bar_num
			} else {
				s3 = s
				while (s3.ts_next)
					s3 = s3.ts_next
︙
2393
2394
2395
2396
2397
2398
2399


2400
2401
2402
2403
2404
2405
2406
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535







+
+







				s3 = s3.ts_next
			while (s3 && s3.v < s.v) {
				s3 = s3.ts_next	// keep in order
				if (s3 && s3.seqst)
					break
			}
			if (s3) {
				if (s3.dur)
					s3.seqst = 0 //false
				lktsym(s4, s3)
			} else {
				s3 = s
				while (s3.ts_next)
					s3 = s3.ts_next
				s3.ts_next = s4
				s4.ts_prev = s3
︙
2772
2773
2774
2775
2776
2777
2778
2779
2780


2781
2782
2783
2784
2785




2786






2787
2788
2789
2790
2791
2792
2793

2794
2795
2796
2797
2798
2799
2800
2901
2902
2903
2904
2905
2906
2907


2908
2909
2910




2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927

2928
2929
2930
2931
2932
2933
2934
2935







-
-
+
+

-
-
-
-
+
+
+
+

+
+
+
+
+
+






-
+







}

/* upper and lower space needed by rests */
var rest_sp = [
	[18, 18],
	[12, 18],
	[12, 12],
	[6, 12],
	[6, 8],
	[10, 12],
	[10, 10],
	[10, 10],			/* crotchet */
	[6, 4],
	[10, 0],
	[10, 4],
	[10, 10]
	[8, 4],
	[9, 0],
	[9, 4],
	[6, 8]
]

// set the offsets of a rest
function roffs(s) {
	s.ymx = s.y + rest_sp[5 - s.nflags][0]
	s.ymn = s.y - rest_sp[5 - s.nflags][1]
} // roffs()

// (possible hook)
Abc.prototype.set_pitch = function(last_s) {
	var	s, s2, g, st, delta, pitch, note,
		dur = C.BLEN,
		m = nstaff + 1,
		staff_delta = new Int16Array(new Array(m * 2)),	// delta clef
		staff_delta = new Int16Array(m * 2),	// delta clef
		sy = cur_sy

	// set the starting clefs of the staves
	for (st = 0; st <= nstaff; st++) {
		s = staff_tb[st].clef;
		staff_delta[st] = delta_tb[s.clef_type] + s.clef_line * 2
		if (s.clefpit)
︙
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860



2861
2862

2863
2864
2865

2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2986
2987
2988
2989
2990
2991
2992



2993
2994
2995


2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011









3012
3013
3014
3015
3016
3017
3018







-
-
-
+
+
+
-
-
+



+











-
-
-
-
-
-
-
-
-







			if (s.invis)
				break
			s.y = 12;
			s.ymx = 24 + 15;
			s.ymn = -2
			break
		case C.REST:
			if (voice_tb.length == 1) {
				s.y = 12;		/* rest single voice */
//				s.ymx = 12 + 8;
			s.y = 12
			if (s.rep_nb > 1		// if measure repeat
			 || s.bar_mrep) {
//				s.ymn = 12 - 8
				s.ymx = 24;
				s.ymx = 38		// (24 + 14)
				s.ymn = 0
				break
			}
			roffs(s)
			// fall thru
		case C.NOTE:
			delta = staff_delta[st]
			if (delta
			 && !s.p_v.ckey.k_drum) {
				for (m = s.nhd; m >= 0; m--) {
					note = s.notes[m]
					note.opit = note.pit
					note.pit += delta
				}
			}
//			if (s.type == C.NOTE) {
//				s.ymx = 3 * (s.notes[s.nhd].pit - 18) + 4;
//				s.ymn = 3 * (s.notes[0].pit - 18) - 4;
//			} else {
			if (s.type == C.REST) {
				s.y = (((s.notes[0].pit - 18) / 2) | 0) * 6;
				s.ymx = s.y + rest_sp[5 - s.nflags][0];
				s.ymn = s.y - rest_sp[5 - s.nflags][1]
			}
			if (s.dur < dur)
				dur = s.dur
			break
		}
	}
	if (!last_s)
		smallest_duration = dur
︙
3018
3019
3020
3021
3022
3023
3024
3025

3026
3027
3028
3029
3030
3031
3032
3144
3145
3146
3147
3148
3149
3150

3151
3152
3153
3154
3155
3156
3157
3158







-
+







				 || s.invis)
					break
				if (s.ts_next.a_dd)
					s.a_dd = s.ts_next.a_dd
				if (s.ts_next.a_gch)
					s.a_gch = s.ts_next.a_gch
				unlksym(s.ts_next)
				break
				// fall thru
			case C.NOTE:
			case C.GRACE:
				break
			}

			st = s.st;
			v = s.v;
︙
3086
3087
3088
3089
3090
3091
3092
3093

3094
3095
3096
3097





















3098
3099
3100

3101

3102




3103
3104
3105
3106




3107
3108

3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126




















3127
3128
3129

3130
3131
3132
3133
3134
3135






3136
3137
3138
3139






3140
3141
3142
3143
3144
3145
3146
3147







3148
3149
3150
3151





3152
3153
3154

3155
3156
3157
3158
3159
3160
3161

3162
3163

3164
3165
3166
3167




3168
3169
3170
3171





3172
3173
3174
3175







3176
3177
3178
3179
3180
3181
3182







3183
3184
3185
3186
3187
3188











3189
3190

3191
3192
3193
3194
3195


3196
3197
3198

3199
3200

3201
3202
3203
3204
3205












3206
3207

3208
3209

3210
3211
3212


3213
3214
3215
3216


3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228

















3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3212
3213
3214
3215
3216
3217
3218

3219

3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247

3248
3249
3250
3251
3252
3253




3254
3255
3256
3257


3258


















3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278



3279






3280
3281
3282
3283
3284
3285




3286
3287
3288
3289
3290
3291








3292
3293
3294
3295
3296
3297
3298




3299
3300
3301
3302
3303
3304


3305







3306


3307
3308



3309
3310
3311
3312




3313
3314
3315
3316
3317




3318
3319
3320
3321
3322
3323
3324







3325
3326
3327
3328
3329
3330
3331






3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342


3343





3344
3345



3346


3347





3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359


3360


3361



3362
3363




3364
3365












3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382






3383
3384
3385
3386
3387
3388
3389







-
+
-



+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+



+
-
+

+
+
+
+
-
-
-
-
+
+
+
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+

-
-
+
-
-
-
-
-
-
-
+
-
-
+

-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
+
-
-
-
-
-
+
+
-
-
-
+
-
-
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
-
-
+
-
-
-
+
+
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-







			s = s.ts_next
	}
}

/* -- adjust the offset of the rests when many voices -- */
/* this function is called only once per tune */
function set_rest_offset() {
	var	s, s2, v, end_time, not_alone, v_s, y, ymax, ymin,
   var	s, s2, v, v_s, ymax, ymin, d,
		shift, dots, dx,
		v_s_tb = [],
		sy = cur_sy

	// set a vertical offset on a line 
	function loffs(d) {
		return d > 0
			? Math.ceil(d / 6) * 6
			: -Math.ceil(-d / 6) * 6
	} // loffs()

	// shift a rest to the right
	function rshift() {
	    var	dx = s2.dots ? 15 : 10
		s2.notes[0].shhd = dx
		s2.xmx = dx
		d = (d + v_s.d) / 2
		d = loffs(d)
		s2.y += d
		s2.ymx += d
		s2.ymn += d
		v_s.d = 0
	} // rshift()

	// -- set_rest_off --
	for (s = tsfirst; s; s = s.ts_next) {
		if (s.invis)
			continue
		switch (s.type) {
		if (s.type == C.STAVES)
		case C.STAVES:
			sy = s.sy
			// fall thru
		default:
			continue
		case C.REST:
		if (!s.dur)
			continue
		v_s = v_s_tb[s.v]
		if (!v_s) {
			if (s.invis || !s.multi)
				continue
			v_s = v_s_tb[s.v]
			if (!v_s) {
			v_s = {}
			v_s_tb[s.v] = v_s
				v_s_tb[s.v] = v_s = { d: 0}
		}
		v_s.s = s;
		v_s.st = s.st;
		v_s.end_time = s.time + s.dur
		if (s.type != C.REST)
			continue

		/* check if clash with previous symbols */
		ymin = -127;
		ymax = 127;
		not_alone = dots = false
		for (v = 0; v <= v_s_tb.length; v++) {
			v_s = v_s_tb[v]
			if (!v_s || !v_s.s
			 || v_s.st != s.st
			 || v == s.v)
				continue
			if (v_s.end_time <= s.time)
			} else if (v_s.d) {
				s2 = v_s.s	// set the offsets of the previous rest
				d = loffs(v_s.d)
				s2.y += d
				s2.ymx += d
				s2.ymn += d
				v_s.d = 0
			}

			d = s.multi > 0 ? 0 : 24
				if (s.prev && s.prev.type == C.NOTE)
					d = (s.next && s.next.type == C.NOTE)
						? (s.prev.y + s.next.y) / 2
						: s.prev.y
				else if (s.next && s.next.type == C.NOTE)
					d = s.next.y
			else if (s.prev && s.prev.type == C.REST)
				d = s.prev.y
			if (s.multi > 0) {
				if (d >= 12)
				continue
			not_alone = true;
			s2 = v_s.s
					v_s.d = d - s.y
			if (sy.voices[v].range < sy.voices[s.v].range) {
				if (s2.time == s.time) {
					if (s2.ymn < ymax) {
						ymax = s2.ymn
						if (s2.dots)
							dots = true
			} else {
				if (d <= 12)
					v_s.d = d - s.y
			}

			v_s.s = s
					}
				} else {
					if (s2.y < ymax)
						ymax = s2.y
			v_s.st = s.st
			v_s.end_time = s.time + s.dur
			if (s.fmr)			// if full meeasure rest
				v_s.end_time -= s.p_v.wmeasure * .3
			if (!s.seqst) {
				s2 = s.ts_prev
				}
			} else {
				if (s2.time == s.time) {
					if (s2.ymx > ymin) {
						ymin = s2.ymx
						if (s2.dots)
							dots = true
					}
					if (s2.st == s.st
					 && s.ymx > s2.ymn
					 && !s2.invis) {
						if (s2.type == C.NOTE) {
							v_s.d = s2.ymn - s.ymx
							break
						}
				} else {
					if (s2.y > ymin)
						ymin = s2.y
				}
						if (s2.type == C.REST
						 && s2.y < 18
						 && s.y >= 6)
							v_s.d = -6
					}
			}
		}

			continue
		/* check if clash with next symbols */
		end_time = s.time + s.dur
		for (s2 = s.ts_next; s2; s2 = s2.ts_next) {
			if (s2.time >= end_time)
				break
			if (s2.st != s.st
//			 || (s2.type != C.NOTE && s2.type != C.REST)
		case C.NOTE:
			 || !s2.dur
			 || s2.invis)
			if (s.invis || !s.multi)
				continue
			not_alone = true
			if (sy.voices[s2.v].range < sy.voices[s.v].range) {
				if (s2.time == s.time) {
			break
		}

		// check if any clash with a rest
					if (s2.ymn < ymax) {
						ymax = s2.ymn
						if (s2.dots)
							dots = true
		for (v = 0; v < v_s_tb.length; v++) {
			v_s = v_s_tb[v]
			if (!v_s
			 || v_s.st != s.st
			 || v == s.v
					}
				} else {
					if (s2.y < ymax)
						ymax = s2.y
			 || v_s.end_time <= s.time)
				continue
			s2 = v_s.s				// rest
			if (sy.voices[v].range > sy.voices[s.v].range) {
				if (s2.ymx + v_s.d <= s.ymn)
					continue
				d = s.ymn - s2.ymx		// rest must go down
				}
			} else {
				if (s2.time == s.time) {
					if (s2.ymx > ymin) {
						ymin = s2.ymx
						if (s2.dots)
							dots = true
//				if (s2.time < s.time) {
					if (s.type == C.REST) {
						if (!v_s_tb[s.v])
							v_s_tb[s.v] = {d: 0}
						if (v_s_tb[s.v].d < 6)
							v_s_tb[s.v].d = 6
						d = -6
					}
				} else {
					if (s2.y > ymin)
						ymin = s2.y
				}
			}
					} else {
						d /= 2
						if (s2.fmr)
							d -= 6
					}
//				}
				if (v_s.d) {
					if (v_s.d > 0) {	// if it was go up
						rshift()	// shift the rest
						continue
					}
		}
		if (!not_alone) {
					if (d >= v_s.d)
			s.y = 12;
			s.ymx = 24;
			s.ymn = 0
			continue
		}
						continue
				}
		if (ymax == 127 && s.y < 12) {
			shift = 12 - s.y
			s.y += shift;
			} else {
			s.ymx += shift;
			s.ymn += shift
				if (s2.ymn + v_s.d >= s.ymx)
		}
		if (ymin == -127 && s.y > 12) {
			shift = s.y - 12
			s.y -= shift;
			s.ymx -= shift;
					continue
				d = s.ymx - s2.ymn		// rest must go up
				if (s.type == C.REST		// if rest
				 && s2 == s.ts_prev		// just under a rest
				 && s.y == s2.y) {		// at a same offset
					if (!v_s_tb[s.v])
						v_s_tb[s.v] = {d: 0}
					if (v_s_tb[s.v].d > -6)
						v_s_tb[s.v].d = -6
					d = 6
				} else if (s2.time < s.time) {
					d = s.ymx - s2.y
			s.ymn -= shift
		}
				}
		shift = ymax - s.ymx
		if (shift < 0) {
				if (v_s.d) {
			shift = Math.ceil(-shift / 6) * 6
			if (s.ymn - shift >= ymin) {
				s.y -= shift;
					if (v_s.d < 0) {	// if it was go down
						rshift()	// shift the rest
				s.ymx -= shift;
				s.ymn -= shift
				continue
			}
						continue
					}
			dx = dots ? 15 : 10;
			s.notes[0].shhd = dx;
			s.xmx = dx
			continue
		}
		shift = ymin - s.ymn
		if (shift > 0) {
			shift = Math.ceil(shift / 6) * 6
			if (s.ymx + shift <= ymax) {
				s.y += shift;
				s.ymx += shift;
				s.ymn += shift
					if (d <= v_s.d)
						continue
				}
			}
			v_s.d = d
		}
	}

	// update the offsets of the last rests
	for (v = 0; v < v_s_tb.length; v++) {
		v_s = v_s_tb[v]
		if (v_s && v_s.d) {
			s2 = v_s.s
			d = loffs(v_s.d)
			s2.y += d
			s2.ymx += d
			s2.ymn += d
				continue
			}
			dx = dots ? 15 : 10;
			s.notes[0].shhd = dx;
			s.xmx = dx
			continue
		}
	}
}

/* -- create a starting symbol -- */
// last_s = symbol at same time
function new_sym(s, p_v, last_s) {
︙
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296


3297
3298
3299
3300
3301
3302
3303
3434
3435
3436
3437
3438
3439
3440


3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451







-
-


+
+







			case C.KEY:
				s.p_v.ckey = s
				break
			case C.METER:
				s.p_v.meter = s
				insert_meter = cfmt.writefields.indexOf('M') >= 0
					&& s.a_meter.length
				if (!insert_meter && s.part)
					s.next.part = s.part
				break
			}
			if (s.part)
				s.next.part = s.part
			unlksym(s)
			// fall thru
		case C.TEMPO:
		case C.BLOCK:
		case C.REMARK:
			continue
		}
︙
3341
3342
3343
3344
3345
3346
3347
3348

3349
3350


3351
3352
3353
3354
3355
3356
3357
3489
3490
3491
3492
3493
3494
3495

3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507







-
+


+
+







			delete s.seqst
		}
		if (last_s)
			last_s.ts_prev = s
		delete s.clef_small;
		delete s.part
		s.second = cur_sy.voices[v].second
// (fixme: needed for sample5 X:3 Fugue & staffnonote.xhtml)
// (fixme: needed for sample5 X:3 Fugue & staffnonote.html)
		if (!cur_sy.st_print[st])
			s.invis = true
		else if (!s.clef_none)
			delete s.invis
		s.fmt = fmt
	}

	/* add keysig */
	for (v = 0; v < nv; v++) {
		if (!cur_sy.voices[v]
		 || cur_sy.voices[v].second
︙
3439
3440
3441
3442
3443
3444
3445






3446
3447
3448
3449
3450
3451
3452
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608







+
+
+
+
+
+







	self.set_pitch(last_s);

	s = tsfirst
	s.seqst = true

	for (s = last_s; s.ts_next && !s.ts_next.seqst; s = s.ts_next)
		;
	if (s.ts_next		// a bit further in case different keys per voice
	 && s.ts_next.type != C.CLEF	// (the clef may move in allsymwidth)
	 && !s.tp			// (start of a tuplet)
	 && !s.ts_next.a_ly)		// (don't update next .shrink)
		for (s = s.ts_next; s.ts_next && !s.ts_next.seqst; s = s.ts_next)
			;
	s2 = s.ts_next
	s.ts_next = null
	set_allsymwidth()
	s.ts_next = s2
} // init_music_line()

// check if the tune ends on a measure bar
︙
3547
3548
3549
3550
3551
3552
3553
3554

3555
3556
3557
3558
3559
3560
3561
3703
3704
3705
3706
3707
3708
3709

3710
3711
3712
3713
3714
3715
3716
3717







-
+







				trem_adj(s)
				break
			}

			nflags = s.nflags

			if (s.ntrem)
				nflags += s.ntrem
				nflags -= s.ntrem
			if (s.type == C.REST && s.beam_end
			 && !s.beam_on) {
//				s.beam_end = false;
				start_flag = true
			}
			if (start_flag
			 || nflags <= 0) {
︙
3758
3759
3760
3761
3762
3763
3764
3765

3766
3767

3768

3769
3770
3771
3772
3773


3774
3775
3776
3777
3778

3779
3780
3781
3782
3783
3784
3785
3914
3915
3916
3917
3918
3919
3920

3921
3922
3923
3924

3925
3926
3927
3928
3929

3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944







-
+


+
-
+




-
+
+





+







	return [lsh1, lsho]
} // get_lshift()

/* -- return the left indentation of the staves -- */
function set_indent(lsh) {
    var	st, v, w, p_voice, p, i, j, font,
	vnt = 0,
	nv = voice_tb.length
	fmt = tsnext ? tsnext.fmt : cfmt

	// name or subname?
	if (fmt.systnames) {		// display the names in the staff system
	for (v = 0; v < nv; v++) {
	    for (v = voice_tb.length; --v >= 0; ) {
		p_voice = voice_tb[v]
		if (!cur_sy.voices[v]
		 || !gene.st_print[p_voice.st])
			continue
		if (p_voice.new_name) {
		if (p_voice.nm
		 && (p_voice.new_name || fmt.systnames == 2)) {
			vnt = 2		// full name
			break
		}
		if (p_voice.snm)
			vnt = 1		// subname
	    }
	}
	gene.vnt = vnt			// voice name type for draw
	return vnt == 2 ? lsh[0] : lsh[1]
}

/* -- decide on beams and on stem directions -- */
/* this routine is called only once per tune */
︙
4600
4601
4602
4603
4604
4605
4606




4607

4608
4609
4610
4611
4612
4613
4614
4615
4616




4617
4618
4619
4620
4621
4622
4623
4624
4625
4626




4627
4628
4629
4630
4631
4632
4633
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805







+
+
+
+

+









+
+
+
+










+
+
+
+







	case "pagescale":
	case "pagewidth":
	case "scale":
	case "staffwidth":
		self.set_format(s.subtype, s.param)
		break
	case "mc_start":		// multicol start
		if (multicol) {
			error(1, s, "No end of the previous %%multicol")
			break
		}
		multicol = {
			state: parse.state,
			posy: posy,
			maxy: posy,
			lm: cfmt.leftmargin,
			rm: cfmt.rightmargin,
			w: cfmt.pagewidth,
			sc: cfmt.scale
		}
		break
	case "mc_new":			// multicol new
		if (!multicol || multicol.state != parse.state) {
			error(1, s, "%%multicol new without start")
			break
		}
		if (posy > multicol.maxy)
			multicol.maxy = posy
		cfmt.leftmargin = multicol.lm
		cfmt.rightmargin = multicol.rm
		cfmt.pagewidth = multicol.w
		cfmt.scale = multicol.sc
		posy = multicol.posy
		img.chg = 1 //true
		break
	case "mc_end":			// multicol end
		if (!multicol || multicol.state != parse.state) {
			error(1, s, "%%multicol end without start")
			break
		}
		if (posy < multicol.maxy)
			posy = multicol.maxy
		cfmt.leftmargin = multicol.lm
		cfmt.rightmargin = multicol.rm
		cfmt.pagewidth = multicol.w
		cfmt.scale = multicol.sc
		multicol = undefined
︙
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688

4689
4690
4691
4692
4693
4694
4695
4696
4836
4837
4838
4839
4840
4841
4842














4843
4844
4845

4846

4847
4848
4849
4850
4851
4852
4853







-
-
-
-
-
-
-
-
-
-
-
-
-
-



-
+
-







		break
	case "vskip":
		vskip(s.sk);
		break
	}
}

// -- move some symbols of an empty staff to the next one --
function sym_staff_move(st) {
	for (var s = tsfirst; s; s = s.ts_next) {
		if (s.nl)
			break
		if (s.st == st
		 && s.type != C.CLEF) {
			s.st++
			if (s.type != C.TEMPO)
				s.invis = true
		}
	}
} // sym_staff_move()

/* -- define the start and end of a piece of tune -- */
/* tsnext becomes the beginning of the next line */
function set_piece() {
    var	s, last, p_voice, st, v, nv, tmp,
    var	s, last, p_voice, st, v, nv, tmp, non_empty,
	non_empty = [],
	non_empty_gl = [],
	sy = cur_sy

	function reset_staff(st) {
		var	p_staff = staff_tb[st],
			sy_staff = sy.staves[st]

︙
4766
4767
4768
4769
4770
4771
4772
4773


4774
4775
4776
4777
4778
4779
4780
4923
4924
4925
4926
4927
4928
4929

4930
4931
4932
4933
4934
4935
4936
4937
4938







-
+
+







			if (!non_empty_gl[st])
				continue

			// define the helper lines
			p_staff.hll = 17 + i * 2	// pitch of lowest note
							// without helper line
							// ('D' when standard staff)
			p_staff.hlmap = new Int8Array(new Array((l - i + 1) * 2))
			p_staff.hlmap = new Int8Array((l - i + 1) * 2
						+ 2)	// (bug android 4.0)
			for (j = 1; i < l; i++, j += 2) {
				switch (p_staff.stafflines[i]) {
				case '|':
				case '[':
					p_staff.hlmap[j - 1] = 1; // no helper line
					p_staff.hlmap[j] = 1;
					p_staff.hlmap[j + 1] = 1
︙
4796
4797
4798
4799
4800
4801
4802

4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814

4815
4816
4817
4818

4819
4820
4821
4822
4823
4824
4825
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972

4973
4974
4975
4976

4977
4978
4979
4980
4981
4982
4983
4984







+











-
+



-
+







			 s.next.prev = null
	}

	/* reset the staves */
	nstaff = sy.nstaff
	for (st = 0; st <= nstaff; st++)
		reset_staff(st);
	non_empty = new Uint8Array(nstaff + 1)

	/*
	 * search the next end of line,
	 * and mark the empty staves
	 */
	for (s = tsfirst; s; s = s.ts_next) {
		if (s.nl)
			break
		switch (s.type) {
		case C.STAVES:
			set_brace();
			sy.st_print = new Uint8Array(non_empty);
			sy.st_print = non_empty
			sy = s.sy;
			while (nstaff < sy.nstaff)
				reset_staff(++nstaff)
			non_empty = []
			non_empty = new Uint8Array(nstaff + 1)
			continue

		// the block symbols will be treated after music line generation
		case C.BLOCK:
			if (!s.play) {
				blocks.push(s)
				unlksym(s)
︙
4871
4872
4873
4874
4875
4876
4877
4878

4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912

4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925






4926
4927
4928
4929
4930
4931
4932

4933

4934
4935
4936
4937








4938
4939
4940

4941
4942
4943
4944







4945
4946
4947
4948
4949

4950

4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969










4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989





4990
4991









4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011


5012
5013



5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5030
5031
5032
5033
5034
5035
5036

5037
5038
5039
5040
5041
















5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054

5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079


5080

5081
5082
5083
5084

5085
5086
5087
5088
5089
5090
5091
5092
5093
5094

5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127






5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138

5139





5140
5141
5142
5143
5144
5145
5146





5147
5148
5149
5150
5151


5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189












5190
5191
5192
5193
5194
5195
5196







-
+




-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-













-
+













+
+
+
+
+
+





-
-
+
-
+



-
+
+
+
+
+
+
+
+


-
+




+
+
+
+
+
+
+





+

+













-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+

-

-
-
-
-
-







-
-
-
-
-
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+




















+
+


+
+
+


-
-
-
-
-
-
-
-
-
-
-
-







		}
		non_empty_gl[st] = non_empty[st] = true
	}
	tsnext = s;

	/* set the last empty staves */
	set_brace()
	sy.st_print = new Uint8Array(non_empty);
	sy.st_print = non_empty

	/* define the offsets of the measure bars */
	set_top_bot()

	// move the symbols of the empty staves to the next staff
	for (st = 0; st < nstaff; st++) {
		if (!non_empty_gl[st])
			sym_staff_move(st)
	}

	// set a null height if the last staff is empty
	if (!non_empty_gl[nstaff])
		staff_tb[nstaff].topbar = 0

	/* initialize the music line */
	init_music_line();

	// keep the array of the staves to be printed
	gene.st_print = new Uint8Array(non_empty_gl)

	// if not the end of the tune, set the end of the music line
	if (tsnext) {
		s = tsnext;
		delete s.nl;
		last = s.ts_prev;
		last.ts_next = null;

		// and the end of the voices
		nv = voice_tb.length
		for (v = 0; v < nv; v++) {
			p_voice = voice_tb[v]
			if (p_voice.sym
			 && p_voice.sym.time <= tsnext.time) {
				for (s = tsnext.ts_prev; s; s = s.ts_prev) {
				for (s = last; s; s = s.ts_prev) {
					if (s.v == v) {
						p_voice.s_next = s.next;
						s.next = null;
						break
					}
				}
				if (s)
					continue
			}
			p_voice.s_next = p_voice.sym;
			p_voice.sym = null
		}
	}

	// initialize the music line
	init_music_line()

	// keep the array of the staves to be printed
	gene.st_print = non_empty_gl
}

/* -- position the symbols along the staff -- */
// (possible hook)
Abc.prototype.set_sym_glue = function(width) {
    var	s, g, ll, x,
	some_grace,
    var	g, x, some_grace, stretch,
	spf,			// spacing factor
	cnt = 4,
	xmin = 0,		// sigma shrink = minimum spacing
	xx = 0,			// sigma natural spacing
	xs = 0,			// sigma unexpandable elements with no space
	xse = 0			// sigma unexpandable elements with space
	xse = 0,		// sigma unexpandable elements with space
	ll = !tsnext ||		// last line? yes
		(tsnext.type == C.BLOCK	// no, but followed by %%command
		 && !tsnext.play)
		|| blocks.length,	//	(abcm2ps compatibility)
	s = tsfirst,
	spf = 1,		// spacing factor
	xx0 = 0

	/* calculate the whole space of the symbols */
	for (s = tsfirst; s; s = s.ts_next) {
	for ( ; s; s = s.ts_next) {
		if (s.type == C.GRACE && !some_grace)
			some_grace = s
		if (s.seqst) {
			xmin += s.shrink
			if (xmin > width) {
				error(1, s, "Line too much shrunk $1 $2 $3",
					xmin.toFixed(1),
					xx.toFixed(1),
					width.toFixed(1))
				break
			}
			if (s.space) {
				if (s.space < s.shrink) {
					xse += s.shrink;
					xx += s.shrink
				} else {
//					xx += s.space * spf + s.shrink * (1 - spf)
					xx += s.space
					xx0 += s.shrink
				}
			} else {
				xs += s.shrink
			}
		}
	}

	// can occur when bar alone in a staff system
	if (!xx) {
		realwidth = 0
		return
	}

	// last line?
	ll = !tsnext ||			// yes
		(tsnext.type == C.BLOCK	// no, but followed by %%command
		 && !tsnext.play)
		|| blocks.length	//	(abcm2ps compatibility)

	// stretch or not?
	s = tsfirst

	if (ll) {
		if ((xx - xx0 + xs) / width > (1 - s.fmt.stretchlast))
			stretch = 1 //true
	} else if (s.fmt.stretchstaff) {
		stretch = 1 //true
	}

	// strong shrink
	s = tsfirst
	if (xmin >= width) {
		if (xmin > width)
			error(1, s, "Line too much shrunk $1 $2 $3",
				xmin.toFixed(1),
				xx.toFixed(1),
				width.toFixed(1));
		x = 0
		for ( ; s; s = s.ts_next) {
			if (s.seqst)
				x += s.shrink;
			s.x = x
		}
//		realwidth = width
		spf_last = 0
	} else if ((ll && xx + xs > width * (1 - s.fmt.stretchlast))
		 || (!ll && (xx + xs > width || s.fmt.stretchstaff))) {
		if (xx == xse)			// if no space
			xx += 5
		spf_last = .65
	} else {
		if (stretch) {
			if (xx == xse)			// if no space
				xx += 10
		for (var cnt = 4; --cnt >= 0; ) {
			spf = (width - xs - xse) / (xx - xse);
			spf = (width - xs - xse) / (xx - xse)
		} else {
			spf = spf_last
			if (ll && spf < s.fmt.stretchlast)
				spf = s.fmt.stretchlast
			if (spf > (width - xs) / xx)
				spf = (width - xs) / xx
		}
		while (--cnt >= 0) {
			xx = 0;
			xse = 0;
			x = 0
			for (s = tsfirst; s; s = s.ts_next) {
				if (s.seqst) {
					if (s.space) {
						if (s.space * spf <= s.shrink) {
							xse += s.shrink;
							xx += s.shrink;
							x += s.shrink
						} else {
							xx += s.space;
							x += s.space * spf
						}
					} else {
						x += s.shrink
					}
				}
				s.x = x
			}
			if (!stretch && x < width)
				break
			if (Math.abs(x - width) < 0.1)
				break
			if (xx == xse)			// if no space
				xx += 10
			spf = (width - xs - xse) / (xx - xse)
		}
		spf_last = spf
	} else {			// shorter line
		spf = 1 - s.fmt.maxshrink
		if (spf_last && xx * spf_last + xs < width)
			spf = spf_last
		x = 0
		for ( ; s; s = s.ts_next) {
			if (s.seqst)
				x += s.space <= s.shrink ?
					s.shrink :
					s.shrink * (1 - spf) + s.space * spf
			s.x = x
		}
	}
	realwidth = x

	/* set the x offsets of the grace notes */
	for (s = some_grace; s; s = s.ts_next) {
		if (s.type != C.GRACE)
			continue
︙
5045
5046
5047
5048
5049
5050
5051
5052

5053


5054

5055
5056
5057
5058
5059
5060
5061
5207
5208
5209
5210
5211
5212
5213

5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226







-
+

+
+

+







function set_sym_line() {
    var	p_v, s,
	v = voice_tb.length

	// set the first symbol of each voice
	while (--v >= 0) {
		p_v = voice_tb[v]
		if (p_v.sym && p_v.s_prev)
		if (p_v.sym && p_v.s_prev) {
			p_v.sym.prev = p_v.s_prev
			p_v.s_prev.next = p_v.sym
		}
		s = p_v.s_next			// (set in set_piece)
		p_v.s_next = null
		p_v.sym = s
		if (s) {
			if (s.prev)
				s.prev.next = s
			p_v.s_prev = s.prev	// (save for play)
			s.prev = null
		} else {
︙
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133





5134
5135
5136
5137
5138
5139
5140
5282
5283
5284
5285
5286
5287
5288




5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306







-
-
-
-






+
+
+
+
+







		self.set_stem_dir()	// set the stems direction in 'multi'

	for (v = 0; v < nv; v++)
		set_beams(voice_tb[v].sym);	/* decide on beams */

	self.set_stems()		// set the stem lengths

	gen_init()			// output the blocks and define the page layout
	if (!tsfirst)
		return

	set_acc_shft()			// set the horizontal offset of accidentals
	if (nv > 1) {			// if many voices
		set_rest_offset();	/* set the vertical offset of rests */
		set_overlap();		/* shift the notes on voice overlap */
	}
	set_allsymwidth(1)		// set the width of all symbols

	// output the blocks and define the page layout
	gen_init()
	if (!tsfirst)
		return

	lsh = get_lshift()

	/* if single line, adjust the page width */
	if (cfmt.singleline) {
		v = get_ck_width();
		lwidth = lsh[0] + v[0] + v[1] + get_width(tsfirst, null)[0]
︙
5153
5154
5155
5156
5157
5158
5159
5160

5161
5162
5163
5164
5165
5166
5167
5168
5169


5170
5171




5172
5173

5174
5175
5176
5177
5178
5179

5180
5181
5182
5183
5184
5185
5186
5319
5320
5321
5322
5323
5324
5325

5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337


5338
5339
5340
5341
5342
5343
5344
5345
5346
5347


5348
5349
5350
5351
5352
5353
5354
5355
5356







-
+









+
+
-
-
+
+
+
+


+



-
-

+








	// save symbol pointers for play
	ts1st = tsfirst
	v = nv
	while (--v >= 0)
		voice_tb[v].osym = voice_tb[v].sym

	spf_last = 0				// last spacing factor
	spf_last = .65				// last spacing factor
	while (1) {				/* loop per music line */
		set_piece();
		indent = set_indent(lsh)
		if (!line_height
		 && cfmt.indent
		 && indent < cfmt.indent)
		 	indent = cfmt.indent
		self.set_sym_glue(lwidth - indent)
		if (realwidth) {
			if (img.wx < realwidth)
				img.wx = realwidth
			if (indent)
				posx += indent;
			if (indent) {
				img.wx += indent
				posx += indent
			}
			draw_sym_near();		// delayed output
			line_height = set_staff();
		    if (line_height) {			// if some music
			draw_systems(indent);
			draw_all_sym();
			delayed_update();
//fixme: KO if at start of tune (the header is generated)
			if (output)			// if some music
				vskip(line_height)
		    }
			if (indent)
				posx -= indent;
		}

		blk_flush()
		while (blocks.length)
			self.block_gen(blocks.shift())
︙
Changes to core/parse.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - parse.js - ABC parse
//
// Copyright (C) 2014-2023 Jean-Francois Moine
// Copyright (C) 2014-2024 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.
︙
71
72
73
74
75
76
77

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94





95
96
97
98
99
100
101







+
















-
-
-
-
-







	case 'F':
		s.clef_type = "b";
		s.clef_line = 4
		break
	case 'n':				// none
		i = 4
		s.invis = true
		s.clef_none = 1 //true
		break
	case 't':
		if (clef_def[1] == 'e') {	// tenor
			s.clef_type = "c";
			s.clef_line = 4
			break
		}
		i = 6
	case 'G':
//		s.clef_type = "t"		// treble
		break
	case 'p':
		i = 4
	case 'P':				// perc
		s.clef_type = "p";
		s.clef_line = 3;
		curvoice.key.k_sf = 0;		// no accidental
		curvoice.ckey.k_sf = 0
		curvoice.ckey.k_map = abc2svg.keys[7]
		curvoice.ckey.k_b40 = 2
		curvoice.ckey.k_drum = true	// no transpose
		break
	default:
		syntax(1, "Unknown clef '$1'", clef_def)
		return //undefined
	}
	if (clef_def[i] >= '1' && clef_def[i] <= '9') {
		s.clef_line = +clef_def[i]
︙
186
187
188
189
190
191
192
193

194
195
196
197
198
199
200
182
183
184
185
186
187
188

189
190
191
192
193
194
195
196







-
+







				a = 0		// no accidental
		}
		nt.acc = a
		return an
	}

	// set the microtonal accidental after transposition
	switch (a) {
	switch (an) {
	case -2:
		if (n > 0)
			n -= d * 2
		else
			n -= d
		break
	case -1:
︙
327
328
329
330
331
332
333

334

335
336
337
338
339

340
341
342


343
344
345
346
347
348
349
323
324
325
326
327
328
329
330

331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349







+
-
+





+



+
+







	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	c_v,
	var	s = {
	s = {
			type: C.BLOCK,
			subtype: subtype,
			dur: 0
		}

	c_v = curvoice
	if (subtype.slice(0, 4) != "midi")	// if not a play command
		curvoice = voice_tb[0]		// set the block in the first voice
	sym_link(s)
	if (c_v)
		curvoice = c_v
	return s
}

// set the voice parameters
// (possible hook)
Abc.prototype.set_vp = function(a) {
    var	s, item, pos, val, clefpit,
︙
527
528
529
530
531
532
533




534
535
536
537
538
539
540
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544







+
+
+
+







		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)
			if (cfmt.nedo) {
				syntax(1, errs.notransp)
				break
			}
			val = get_transp(a.shift())
			if (val == undefined) {
︙
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593

594
595
596
597
598
599
600
582
583
584
585
586
587
588









589
590
591
592
593
594
595
596







-
-
-
-
-
-
-
-
-
+







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

	// if transposition
	if (tr_p) {
		curvoice.tr_p = tr_p			// keep this key signature
		tr_p = (curvoice.score | 0)
			+ (curvoice.shift | 0)
			+ (cfmt.transp | 0)
		if (tr_p)
			curvoice.tr_sco = tr_p		// b40 interval
		else if (curvoice.tr_sco)
			curvoice.tr_sco = 0
	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
		else if (curvoice.tr_snd)
			curvoice.tr_snd = 0
	}
︙
908
909
910
911
912
913
914
915

916
917
918
919
920
921
922
904
905
906
907
908
909
910

911
912
913
914
915
916
917
918







-
+







					if (p[i] != ' ' && p[i] != '+')
						break
					if (i >= p.length
					 || p[i + 1] == '(')	/* "M:5 (2/4+3/4)" */
						break
					meter.top += p[i++]
				}
				m1 = +meter.top
				m1 = eval(meter.top)
				break
			}
			if (!in_parenth) {
				if (meter.bot)
					m2 = +meter.bot
				wmeasure += m1 * C.BLEN / m2
			}
︙
974
975
976
977
978
979
980










































981
982
983
984
985
986
987
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







			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,
︙
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081




1082
1083
1084
1085
1086


1087
1088
1089
1090
1091
1092
1093
1105
1106
1107
1108
1109
1110
1111

1112
1113





1114
1115
1116
1117





1118
1119
1120
1121
1122
1123
1124
1125
1126







-


-
-
-
-
-
+
+
+
+
-
-
-
-
-
+
+







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

    var	tim = curvoice.time
	if (!glovar.tempo)
		syntax(0, "No previous tempo")
	if (!parse.ctrl)
		parse.ctrl = {}
	if (!parse.ctrl[tim])
		parse.ctrl[tim] = {}
	parse.ctrl[tim].tempo = s
	s.time = curvoice.time
	text = 'Q' + s.time
	if (parse.pq
	 && parse.pq[text] == s.time)
	s.v = par_sy.top_voice
	s.p_v = voice_tb[s.v]
	s.fmt = cfmt
	s.st = s.p_v.st
	s.time = tim
		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
︙
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157

1158
1159

1160







1161
1162
1163



1164
1165
1166
1167
1168
1169

1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186



1187
1188
1189

1190
1191
1192
1193
1194
1195
1196
1197
1198



1199
1200
1201






1202



1203
1204
1205
1206
1207
1208
1209







-
-
-

+

-
+

+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
+
-
-
-







	case 'P':
		if (!parse.state)
			break
		if (parse.state == 1) {
			info.P = text
			break
		}

		// memorize the part in the control
		tim = curvoice.time
		s = {
			type: C.PART,
			text: text,
			time: tim
			time: curvoice.time
		}
		tim = parse.pq && parse.pq[text] // time of previous P: with same text
		if (tim == s.time)
			break				// already seen
		if (tim != null) {
			syntax(1, "Misplaced P:")	// different dates
			break
		}
		set_ref(s)
		if (cfmt.writefields.indexOf(info_type) < 0)
			s.invis = true

		if (cfmt.writefields.indexOf('P') < 0)
			s.invis = 1 //true
		if (!parse.ctrl)
			parse.ctrl = {}
		if (!parse.ctrl[tim])
			parse.ctrl[tim] = {}
		parse.ctrl[tim].part = s
		s.v = par_sy.top_voice
		link_pq(s, text)
		s.p_v = voice_tb[s.v]
		s.fmt = cfmt
		s.st = s.p_v.st
		break
	case 'Q':
		if (!parse.state)
			break
		new_tempo(text)
		break
	case 'V':
︙
1231
1232
1233
1234
1235
1236
1237
1238
1239

1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1261
1262
1263
1264
1265
1266
1267


1268















1269
1270
1271
1272
1273
1274
1275







-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







		return
	while (s2.type != C.BAR && s2.prev)
		s2 = s2.prev;
	time = s2.time;
	auto_time = curvoice.time - time
	fac = curvoice.wmeasure / auto_time

	/* remove the invisible rest at start of tune */
	if (!time) {
	if (fac == 1)
		while (s2 && !s2.dur)
			s2 = s2.next
		if (s2 && s2.type == C.REST
		 && s2.invis) {
			time += s2.dur * fac
			if (s2.prev)
				s2.prev.next = s2.next
			else
				curvoice.sym = s2.next
			if (s2.next)
				s2.next.prev = s2.prev;
			s2 = s2.next
		}
	}
	if (curvoice.wmeasure == auto_time)
		return				/* already good duration */

	for ( ; s2; s2 = s2.next) {
		s2.time = time
		if (!s2.dur || s2.grace)
			continue
		s2.dur *= fac;
︙
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1325
1326
1327
1328
1329
1330
1331



















1332
1333
1334
1335
1336
1337
1338







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-








	// set the annotations and the decorations
	if (a_gch)
		csan_add(s)
	if (a_dcn.length)
		deco_cnv(s)

	// set the start/stop of ottava
	if (parse.ottava.length) {
		s2 = s
		if (curvoice.cst != curvoice.st) {	// if staff change
			s2 = {
				type: C.SPACE,		// put the decoration on a ...
				fname: parse.fname,
				istart: parse.bol + line.index,
				dur: 0,
				multi: 0,
				invis: true,
				width: 1		// .. small space
			}
			sym_link(s2)
		}
		s2.ottava = parse.ottava
		parse.ottava = []
	}

	/* 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 = '['
︙
1382
1383
1384
1385
1386
1387
1388
1389

1390
1391
1392
1393
1394
1395
1396
1377
1378
1379
1380
1381
1382
1383

1384
1385
1386
1387
1388
1389
1390
1391







-
+







	if (s.text
	 && bar_type.slice(-1) == '['
	 && bar_type != '[')
		bar_type = bar_type.slice(0, -1)

	// there cannot be variants on a left repeat bar
	if (bar_type.slice(-1) == ':') {	// left repeat
		s.rbstop = 2			// stop the bracket
		s.rbstop = 1			// end the bracket
		if (s.text) {
			syntax(1, "Variant ending on a left repeat bar")
			delete s.text
		}
		curvoice.tie_s_rep = null	// no tie anymore on new variant
	}

︙
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417





1418
1419
1420

1421



1422
1423
1424
1425

1426
1427
1428
1429
1430
1431
1432
1433

1434
1435
1436
1437

1438
1439
1440

1441
1442
1443

1444
1445
1446
1447

1448





1449
1450


1451
1452

1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463


1464
1465
1466
1467
1468
1469
1470
1471
1472

1473
1474
1475
1476
1477
1478
1479
1480
1481
1399
1400
1401
1402
1403
1404
1405







1406
1407
1408
1409
1410
1411
1412
1413
1414

1415
1416
1417
1418

1419

1420








1421
1422
1423
1424

1425
1426
1427

1428



1429




1430
1431
1432
1433
1434
1435
1436


1437
1438
1439

1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450

1451
1452
1453
1454
1455
1456





1457


1458
1459
1460
1461
1462
1463
1464







-
-
-
-
-
-
-
+
+
+
+
+



+
-
+
+
+

-

-
+
-
-
-
-
-
-
-
-
+



-
+


-
+
-
-
-
+
-
-
-
-
+

+
+
+
+
+
-
-
+
+

-
+










-
+
+




-
-
-
-
-
+
-
-







			else if (curvoice.acc_tie_rep)
				curvoice.acc_tie_rep = null
		} else {
			curvoice.tie_s = curvoice.tie_s_rep
			if (curvoice.acc_tie_rep)
				curvoice.acc_tie = curvoice.acc_tie_rep.slice()
		}
	}

	if (s.rbstart
	 && curvoice.norepbra
	 && !curvoice.second)
		s.norepbra = true

		if (curvoice.norepbra
		 && !curvoice.second)
			s.norepbra = 1 //true
	}

	if (curvoice.ulen < 0)			// L:auto
		adjust_dur(s);

	// merge ":| |:" into "::" and other cases
	if (bar_type == "[" || bar_type == "|:") {
	if ((bar_type == "[" || bar_type == "|:")
	 && !curvoice.eoln
	 && !s.a_gch && !s.invis) {		// no annotation nor invisible
		s2 = curvoice.last_sym
		if (s2 && s2.time == curvoice.time) {

			// search if a previous bar at this time
		// if the previous symbol is also a bar
			do {
				if (s2.type == C.BAR)
					break
				if (w_tb[s2.type]) // symbol with a width
					break
				s2 = s2.prev
			} while (s2)
			if (s2 && s2.type == C.BAR) {
		if (s2 && s2.type == C.BAR) {
//		&& !s2.a_gch && !s2.a_dd
//		&& !s.a_gch && !s.a_dd) {

				// remove the invisible repeat bars
				// remove the invisible variant bars
				// when no shift is needed
				if ((bar_type == "["
				 && !s2.text
				  && !s2.text)
				 && (!curvoice.st
				  || (par_sy.staves[curvoice.st - 1].flags & STOP_BAR)
				  || s.norepbra))
				 || s.norepbra) {
				 || s2.bar_type == "|") {	// "|" + "|:" => "|:"
					if (bar_type != "[")
						s2.bar_type = bar_type
					if (s.text)
					if (s.text) {
						s2.text = s.text
						if (curvoice.st && !s.norepbra
						 && !(par_sy.staves[curvoice.st - 1]
								.flags & STOP_BAR))
							s2.xsh = 4	// volta shift
					}
					if (s.a_gch)
						s2.a_gch = s.a_gch
//					if (s.a_gch)
//						s2.a_gch = s.a_gch
					if (s.norepbra)
						s2.norepbra = s.norepbra
						s2.norepbra = 1 //true
					if (s.rbstart)
						s2.rbstart = s.rbstart
					if (s.rbstop)
						s2.rbstop = s.rbstop
//--fixme: pb when on next line and empty staff above
					return
				}

				// merge back-to-back repeat bars
				if (bar_type == "|:") {
					if (s2.bar_type == ":|") {
					switch (s2.bar_type) {
					case ":|":		// :| + |: => ::
						s2.bar_type = "::";
						s2.rbstop = 2
						return
					}
					if (s2.bar_type == "||") {
						s2.bar_type = "||:";
						s2.rbstop = 2
						return
					}
				}
				}
			}
		}
	}

	/* set some flags */
	switch (bar_type) {
	case "[":
	case "[]":
︙
1502
1503
1504
1505
1506
1507
1508
1509

1510
1511
1512
1513
1514


1515
1516
1517
1518
1519
1520

1521
1522
1523
1524
1525
1526
1527

1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1485
1486
1487
1488
1489
1490
1491

1492





1493
1494






1495







1496



1497
1498
1499
1500
1501
1502
1503







-
+
-
-
-
-
-
+
+
-
-
-
-
-
-
+
-
-
-
-
-
-
-
+
-
-
-







	if (!curvoice.sym_restart)
		curvoice.sym_restart = s

	sym_link(s);

	s.st = curvoice.st			/* original staff */

	/* if repeat bar and shift, add a repeat bar */
	// possibly shift the volta bracket if not on the first staff
	if (s.rbstart
	 && bar_type != "["
	 && !curvoice.norepbra
	 && s.st > 0
	 && !(par_sy.staves[s.st - 1].flags & STOP_BAR)) {
	if (s.text && s.st > 0 && !s.norepbra
	 && !(par_sy.staves[s.st - 1].flags & STOP_BAR)
		s2 = {
			type: C.BAR,
			fname: s.fname,
			istart: s.istart,
			iend: s.iend,
			bar_type: "[",
	 && bar_type != '[')
			multi: 0,
			invis: true,
			text: s.text,
			rbstart: 2
		}
		sym_link(s2);
		s2.st = s.st
		s.xsh = 4			// volta shift
		delete s.text;
		s.rbstart = 0
	}

	if (!s.bar_dotted && !s.invis)
		curvoice.acc = []		// no accidental anymore
}

// parse %%staves / %%score
// return an array of [vid, flags] / null
︙
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799




1800
1801
1802
1803
1804
1805


1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817














1818
1819
1820
1821
1822
1823
1824
1755
1756
1757
1758
1759
1760
1761




1762
1763
1764
1765
1766
1767
1768
1769


1770
1771
1772
1773
1774
1775
1776
1777
1778





1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799







-
-
-
-
+
+
+
+




-
-
+
+







-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+







// - key    = 'k' + scale index
// - all    = 'all'
// The 'map' is stored in the note. It is an array of
//	[0] array of heads (glyph names)
//	[1] print (note)
//	[2] color
//	[3] play (note)
function set_map(note, acc) {
    var	pit = note.pit,
	nn = not2abc(pit, acc),
	map = maps[curvoice.map]	// never null
function set_map(p_v, note, acc,
		 trp) {			// transpose done
    var	nn = not2abc(note.pit, acc),
	map = maps[p_v.map]		// never null

	if (!map[nn]) {
		nn = 'o' + nn.replace(/[',]+/, '')	// ' octave
		if (!map[nn]) {
			nn = 'k' + ntb[(pit + 75 -
					curvoice.ckey.k_sf * 11) % 7]
			nn = 'k' + ntb[(note.pit + 75 -
					p_v.ckey.k_sf * 11) % 7]
			if (!map[nn]) {
				nn = 'all'		// 'all'
				if (!map[nn])
					return
			}
		}
	}
	note.map = map = map[nn]
	if (map[1]) {				// if print map
		note.pit = pit = map[1].pit
		note.acc = map[1].acc
	}
	map = map[nn]
	if (!trp) {				// transpose not done yet
		if (map[1]) {			// if note shift
			note.pit = map[1].pit
			note.acc = map[1].acc
			if (map[1].notrp) {
				note.notrp = 1 //true	// no transpose
				note.noplay = 1 //true	// no play
			}
		}
		return
	}
	note.map = map

	if (map[2])				// if color
		note.color = map[2]
	nn = map[3]
	if (nn)					// if play map
		note.midi = pit2mid(nn.pit + 19, nn.acc)
}

︙
1852
1853
1854
1855
1856
1857
1858



1859
1860
1861
1862
1863
1864
1865
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843







+
+
+







	switch (line.next_char()) {
	case "'":
		line.index++
		return ty + C.SL_ABOVE
	case ",":
		line.index++
		return ty + C.SL_BELOW
	case '?':				// slur between staves (like ~)
		line.index++
		return ty + C.SL_CENTER
	}
	return ty + C.SL_AUTO
}

// on end of slur, create the slur
function slur_add(s, nt) {		// nt = note if slur ending on note
    var	i, s2, sl
︙
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
1965
1966
1967
1968
1969
1970
1971

1972
1973
1974
1975
1976
1977
1978







-







				if (!not1.tie_ty)
					continue
				if (not1.midi == mid
				 && (!se
				  || !not1.tie_e)) {	// (if unison)
					not2.tie_s = not1
					not2.s = s
					delete not2.acc	// (if transposing)
					if (se) {
						not1.tie_e = not2
						not1.s = tie_s
					}
					nt++
					break
				}
︙
2091
2092
2093
2094
2095
2096
2097




2098
2099
2100
2101
2102
2103
2104
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085







+
+
+
+







			s.fmr = 1		// full measure rest
			s.notes = [{
				pit: 18,
				dur: s.dur
			}]
		} else {
			glovar.mrest_p = true
			if (par_sy.voices.length == 1) {
				s.tacet = curvoice.tacet
				delete s.invis	// show the 'H' when 'Xn'
			}
		}
		break
	case 'y':
		s.type = C.SPACE;
		s.invis = true;
		s.dur = 0;
		c = line.next_char()
︙
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214



2215

2216
2217
2218
2219
2220
2221
2222
2223

2224
2225
2226
2227
2228
2229
2230
2179
2180
2181
2182
2183
2184
2185





2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211







-
-
-
-
-





+
+
+

+








+







				else if (cfmt["propagate-accidentals"][0] != 'n')
					curvoice.acc[apit] = i
			}

			if (acc_tie && acc_tie[apit])
				i = acc_tie[apit]	// tied note

			// map
			if (curvoice.map
			 && maps[curvoice.map])
				set_map(note, i)

			// set the MIDI pitch
			if (!note.midi)		// if not map play
				note.midi = pit2mid(apit, i)

			// transpose
			if (curvoice.map
			 && maps[curvoice.map])
				set_map(curvoice, note, i)	// transpose not done
			if (curvoice.tr_sco) {
			    if (!note.notrp) {
				i = nt_trans(note, i)
				if (i == -3) {		// if triple sharp/flat
					error(1, s, "triple sharp/flat")
					i = note.acc > 0 ? 1 : -1
					note.pit += i
					note.acc = i
				}
				dpit = note.pit + 19 - apit
			    }
			}
			if (curvoice.tr_snd)
				note.midi += curvoice.tr_snd

//fixme: does not work if transposition
			if (i) {
				switch (cfmt["writeout-accidentals"][1]) {
︙
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463


2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2435
2436
2437
2438
2439
2440
2441



2442
2443




2444
2445
2446
2447
2448
2449
2450







-
-
-
+
+
-
-
-
-







			curvoice.sym_restart = s
	}

	if (a_dcn_sav.length) {
		a_dcn = a_dcn_sav
		deco_cnv(s, s.prev)
	}
	if (parse.ottava.length) {
		if (grace)
			grace.ottava = parse.ottava
	if (grace && s.ottava)
		grace.ottava = s.ottava
		else
			s.ottava = parse.ottava
		parse.ottava = []
	}
	if (parse.stemless)
		s.stemless = true
	s.iend = parse.bol + line.index
	return s
}

// adjust the duration of the elements in a tuplet
︙
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528

2529
2530
2531
2532
2533
2534
2535
2536
2493
2494
2495
2496
2497
2498
2499





2500

2501
2502
2503
2504
2505
2506
2507







-
-
-
-
-
+
-







			syntax(1, "No end of decoration")
			return
		}
		if (c == '!')
			break
		dcn += c
	}
	if (ottava[dcn] != undefined) {
		glovar.ottava = true;
		parse.ottava.push(ottava[dcn])
	} else {
		a_dcn.push(dcn)
	a_dcn.push(dcn)
	}
} // get_deco()

// characters in the music line (ASCII only)
var nil = "0",
    char_tb = [
	nil, nil, nil, nil,		/* 00 - .. */
	nil, nil, nil, nil,
︙
2563
2564
2565
2566
2567
2568
2569
2570

2571
2572
2573
2574
2575
2576
2577
2578
2579
2534
2535
2536
2537
2538
2539
2540

2541


2542
2543
2544
2545
2546
2547
2548







-
+
-
-







	"d", "d", "d", "d",		/* h i j k */
	"d", "d", "d", "d",		/* l m n o */
	"d", "d", "d", "d",		/* p q r s */
	"d", "!upbow!",
		"!downbow!", "d",	/* t u v w */
	"n", "n", "n", "{",		/* x y z { */
	"|", "}", "!gmark!", nil,	/* | } ~ (del) */
],
] // char_tb[]
    ottava = {"8va(":1, "8va)":0, "15ma(":2, "15ma)":0,
	"8vb(":-1, "8vb)":0, "15mb(":-2, "15mb)":0}

function parse_music_line() {
	var	grace, last_note_sav, a_dcn_sav, no_eol, s, tps,
		tp = [],
		tpn = -1,
		sls = [],
		line = parse.line
︙
Changes to core/subs.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - subs.js - text output
//
// Copyright (C) 2014-2022 Jean-Francois Moine
// Copyright (C) 2014-2023 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.
︙
82
83
84
85
86
87
88
89
90


















91
92
93

94
95
96
97
98
99
100
101

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

118
119
120
121
122
123
124
125
126
127

128
129
130
131
132
133
134
135
136
82
83
84
85
86
87
88


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

109
110
111
112
113
114
115
116

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

133
134
135
136
137
138
139
140
141
142
143
144
145

146
147
148
149
150
151
152







-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


-
+







-
+















-
+










+

-







	.722,.278,.500,.667,.556,.833,.722,.778,
	.667,.778,.722,.667,.611,.722,.667,.944,	// 50
	.667,.667,.611,.278,.278,.278,.469,.556,
	.333,.556,.556,.500,.556,.556,.278,.556,	// 60
	.556,.222,.222,.500,.222,.833,.556,.556,
	.556,.556,.333,.500,.278,.556,.500,.722,	// 70
	.500,.500,.500,.334,.260,.334,.584,.512]),

    cw_tb = sw_tb				// current width table
// monospace
    mw_tb = new Float32Array([
	.0,.0,.0,.0,.0,.0,.0,.0,		// 00
	.0,.0,.0,.0,.0,.0,.0,.0,
	.0,.0,.0,.0,.0,.0,.0,.0,		// 10
	.0,.0,.0,.0,.0,.0,.0,.0,
	.52,.52,.52,.52,.52,.52,.52,.52,	// 20
	.52,.52,.52,.52,.52,.52,.52,.52,
	.52,.52,.52,.52,.52,.52,.52,.52,	// 30
	.52,.52,.52,.52,.52,.52,.52,.52,
	.52,.52,.52,.52,.52,.52,.52,.52,	// 40
	.52,.52,.52,.52,.52,.52,.52,.52,
	.52,.52,.52,.52,.52,.52,.52,.52,	// 50
	.52,.52,.52,.52,.52,.52,.52,.52,
	.52,.52,.52,.52,.52,.52,.52,.52,	// 60
	.52,.52,.52,.52,.52,.52,.52,.52,
	.52,.52,.52,.52,.52,.52,.52,.52,	// 70
	.52,.52,.52,.52,.52,.52,.52,.52])

/* -- return the character width -- */
function cwid(c) {
function cwid(c, font) {
	var i = c.charCodeAt(0)		// utf-16

	if (i >= 0x80) {		// if not ASCII
		if (i >= 0x300 && i < 0x370)
			return 0;	// combining diacritical mark
		i = 0x61		// 'a'
	}
	return cw_tb[i]
	return (font || gene.curfont).cw_tb[i]
}
// return the character width with the current font
function cwidf(c) {
	return cwid(c) * gene.curfont.swfac
}

// estimate the width and height of a string ..
var strwh

(function() {
    if (typeof document != "undefined") {

    // .. by the browser

	// create a text element if not done yet
    var	el = abc2svg.eltxt
      var	el

	// change the function
	strwh = function(str) {
		if (str.wh)
			return str.wh
		if (!el) {
			el = document.createElement('text')
			el.style.position = 'absolute'
			el.style.top = '-1000px'
			el.style.padding = '0'
			el.style.visibility = "hidden"
			document.body.appendChild(el)
			abc2svg.eltxt = el	// reused after new Abc()
		}

	    var	c,
		font = gene.curfont,
		h = font.size,
		w = 0,
		n = str.length,
︙
217
218
219
220
221
222
223
224

225
226
227
228
229
230
231
233
234
235
236
237
238
239

240
241
242
243
244
245
246
247







-
+







			j = str.indexOf(';', i)
			if (j > 0 && j - i < 10) {
				i = j;
				c = 'a'		// XML character reference
			}
			break
		}
		w += cwid(c) * swfac
		w += cwid(c, font) * swfac
	}
	return [w, h]
    }
  }
})()

// convert a string to a SVG text, handling the font changes
︙
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
315
316
317
318
319
320
321

322
323
324
325
326
327
328







-







	return o
} // str2svg()

// set the default and current font
function set_font(xxx) {
	if (typeof xxx == "string")
		xxx = get_font(xxx)
	cw_tb = xxx.name.slice(0, 4) == 'sans' ? ssw_tb : sw_tb
	gene.curfont = gene.deffont = xxx
}

// output a string handling the font changes
function out_str(str) {
	output += str2svg(str)
}
︙
321
322
323
324
325
326
327
















328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368

369
370
371
372
373
374

375
376
377
378
379
380
381







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+










-






-







function xy_str(x, y,
		str,		// string or object String with attribute 'wh'
		action,		// default: align left
		w,		// needed for justify
		wh) {		// optional [width, height]
	if (!wh)
		wh = str.wh || strwh(str)
	if (cfmt.trimsvg) {
	    var wx = wh[0]
		switch (action) {
		case 'c':
			wx = wh[0] / 2
			break
		case 'j':
			wx = w
			break
		case 'r':
			wx = 0
			break
		}
		if (img.wx < x + wx)
			img.wx = x + wx
	}

	output += '<text class="' + font_class(gene.deffont)
	if (action != 'j' && str.length > 5
	 && gene.deffont.wadj)
		output += '" lengthAdjust="' + gene.deffont.wadj +
			'" textLength="' + wh[0].toFixed(1);
	output += '" x="';
	out_sxsy(x, '" y="', y)
	switch (action) {
	case 'c':
		x -= wh[0] / 2;
		output += '" text-anchor="middle">'
		break
	case 'j':
		output += '" textLength="' + w.toFixed(1) + '">'
		break
	case 'r':
		x -= wh[0];
		output += '" text-anchor="end">'
		break
	default:
		output += '">'
		break
	}
	out_str(str);
︙
378
379
380
381
382
383
384


385
386
387
388
389
390
391
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422







+
+







	if (cfmt.titlecaps)
		return title.toUpperCase()
	return title
}

// return the width of the music line
function get_lwidth() {
	if (img.chg)
		set_page()
	return (img.width - img.lm - img.rm
					- 2)	// for bar thickness at eol
			/ cfmt.scale
}

// header generation functions
function write_title(title, is_subtitle) {
︙
401
402
403
404
405
406
407
408

409
410
411
412
413
414
415
432
433
434
435
436
437
438

439
440
441
442
443
444
445
446







-
+







	} else {
		set_font("title");
		h = cfmt.titlespace
	}
	wh = strwh(title)
	wh[1] += gene.curfont.pad * 2
	vskip(wh[1] + h + gene.curfont.pad)
	h = gene.curfont.pad
	h = gene.curfont.pad + wh[1] * .22	// + descent
	if (cfmt.titleleft)
		xy_str(0, h, title, null, null, wh)
	else
		xy_str(get_lwidth() / 2, h, title, "c", null, wh)
}

/* -- output a header format '111 (222)' -- */
︙
671
672
673
674
675
676
677
678

679
680
681

682




683
684

685
686

687
688
689
690
691
692
693
702
703
704
705
706
707
708

709
710
711

712
713
714
715
716
717
718

719
720

721
722
723
724
725
726
727
728







-
+


-
+

+
+
+
+

-
+

-
+







			h = gene.curfont.size * cfmt.lineskipfac
		}
		head = names[i].slice(2)
		if (head[0] == '"')
			head = head.slice(1, -1);
		vskip(h);
		wh = strwh(head);
		xy_str(0, 0, head, null, null, wh);
		xy_str(0, wh[1] * .22, head, null, null, wh);
		w = wh[0];
		str = str.split('\n');
		xy_str(w, 0, str[0])
		xy_str(w, wh[1] * .22, str[0])
		for (j = 1; j < str.length; j++) {
			if (!str[j]) {			// new paragraph
				vskip(gene.curfont.size * cfmt.parskipfac)
				continue
			}
			vskip(h);
			xy_str(w, 0, str[j])
			xy_str(w, wh[1] * .22, str[j])
		}
		vskip(h * .3);
		vskip(h * cfmt.parskipfac)
		use_font(gene.curfont)
	}
}

/* -- write heading with format -- */
var info_font_init = {
	A: "info",
︙
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941


942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966

967
968
969
970

971
972
973
974
975
976

977
978
979
980
981

982

983
984
985
986
987
988
989
990
991
992
993
994
995
996
997



998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013








1014
1015

1016
1017
1018
960
961
962
963
964
965
966

967
968
969
970
971
972
973


974
975
976
977
978
979
980
981
982
983
984
985

986
987
988
989
990
991
992
993
994
995

996


997

998
999

1000
1001
1002
1003
1004
1005

1006
1007
1008
1009
1010
1011
1012

1013

1014
1015


1016
1017
1018
1019
1020
1021
1022
1023


1024
1025
1026

1027



1028
1029
1030
1031
1032
1033





1034
1035
1036
1037
1038
1039
1040
1041


1042
1043
1044
1045







-







-
-
+
+










-










-

-
-
+
-


-
+





-
+





+
-
+
-


-
-








-
-
+
+
+
-

-
-
-






-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
+



			}
			write_title(info.T.slice(i, j), i != 0);
			i = j + 1
		}
	}

	/* rhythm, composer, origin */
//	down1 = cfmt.composerspace + gene.curfont.size
	down1 = down2 = 0
	if (parse.ckey.k_bagpipe
	 && !cfmt.infoline
	 && cfmt.writefields.indexOf('R') >= 0)
		rhythm = info.R
	if (rhythm) {
		set_font("composer");
		xy_str(0, -cfmt.composerspace, rhythm);
		down1 = cfmt.composerspace
		down1 = cfmt.composerspace + gene.curfont.size + 2
		xy_str(0, -down1 + gene.curfont.size *.22, rhythm)
	}
	area = info.A
	if (cfmt.writefields.indexOf('C') >= 0)
		composer = info.C
	if (cfmt.writefields.indexOf('O') >= 0)
		origin = info.O
	if (composer || origin || cfmt.infoline) {
		var xcomp, align;

		set_font("composer");
		vskip(cfmt.composerspace)
		if (cfmt.aligncomposer < 0) {
			xcomp = 0;
			align = ' '
		} else if (cfmt.aligncomposer == 0) {
			xcomp = lwidth * .5;
			align = 'c'
		} else {
			xcomp = lwidth;
			align = 'r'
		}
		down2 = down1
		if (composer || origin) {
			if (cfmt.aligncomposer >= 0
			 && down1 != down2)
			down2 = cfmt.composerspace + 2
				vskip(down1 - down2);
			i = 0
			while (1) {
				vskip(gene.curfont.size)
				down2 += gene.curfont.size
				if (composer)
					j = composer.indexOf("\n", i)
				else
					j = -1
				if (j < 0) {
					put_inf2r(xcomp, 0,
					put_inf2r(xcomp, -down2 + gene.curfont.size *.22,
						composer ? composer.substring(i) : null,
						origin,
						align)
					break
				}
				xy_str(xcomp, -down2 + gene.curfont.size *.22,
				xy_str(xcomp, 0, composer.slice(i, j), align);
					composer.slice(i, j), align);
				down1 += gene.curfont.size;
				i = j + 1
			}
			if (down2 > down1)
				vskip(down2 - down1)
		}

		rhythm = rhythm ? null : info.R
		if ((rhythm || area) && cfmt.infoline) {

			/* if only one of rhythm or area then do not use ()'s
			 * otherwise output 'rhythm (area)' */
			set_font("info");
			vskip(gene.curfont.size + cfmt.infospace);
			put_inf2r(lwidth, 0, rhythm, area, 'r');
			down2 += cfmt.infospace + gene.curfont.size
			put_inf2r(lwidth, -down2 + gene.curfont.size *.22,
				rhythm, area, 'r')
			down1 += gene.curfont.size + cfmt.infospace
		}
//		down2 = 0
	} else {
		down2 = cfmt.composerspace
	}

	/* parts */
	if (info.P
	 && cfmt.writefields.indexOf('P') >= 0) {
		set_font("parts");
		down1 = cfmt.partsspace + gene.curfont.size - down1
		if (down1 > 0)
			down2 += down1
		if (down2 > .01)
			vskip(down2);
		i = cfmt.partsspace + gene.curfont.size + gene.curfont.pad
		if (down1 + i > down2)
			down2 = down1 + i
		else
			down2 += i
		xy_str(0, -down2 + gene.curfont.size *.22, info.P)
		down2 += gene.curfont.pad
	} else if (down1 > down2) {
		xy_str(0, 0, info.P);
		down2 = 0
		down2 = down1
	}
	vskip(down2 + cfmt.musicspace)
}
Changes to core/svg.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - svg.js - svg functions
//
// Copyright (C) 2014-2022 Jean-Francois Moine
// Copyright (C) 2014-2023 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.
︙
28
29
30
31
32
33
34
35
36



37
38
39
40
41
42
43
28
29
30
31
32
33
34


35
36
37
38
39
40
41
42
43
44







-
-
+
+
+







\n.box{outline:1px solid black;outline-offset:1px}',
	font_style = '',
	posx = cfmt.leftmargin / cfmt.scale,	// default x offset of the images
	posy = 0,		// y offset in the block
	img = {			// image
		width: cfmt.pagewidth,	// width
		lm: cfmt.leftmargin,	// left and right margins
		rm: cfmt.rightmargin
//		chg: false
		rm: cfmt.rightmargin,
		wx: 0,			// used width between the left and right margins
		chg: 1 //true
	},
	defined_glyph = {},
	defs = '',
	fulldefs = '',		// unreferenced defs as <filter>
	stv_g = {		/* staff/voice graphic parameters */
		scale: 1,
		dy: 0,
︙
58
59
60
61
62
63
64
65
66
67
68




69
70
71
72
73
74
75
59
60
61
62
63
64
65




66
67
68
69
70
71
72
73
74
75
76







-
-
-
-
+
+
+
+







  brace: {x:0, y:0, c:"\ue000"},
  lphr: {x:0, y:23, c:"\ue030"},
  mphr: {x:0, y:23, c:"\ue038"},
  sphr: {x:0, y:26, c:"\ue039"},
  short: {x:0, y:32, c:"\ue038"},
  tick: {x:0, y:29, c:"\ue039"},
  rdots: {x:-1, y:0, c:"\ue043"},	// repeat dots
  dsgn: {x:-4, y:-4, c:"\ue045"},	// D.S.
  dcap: {x:-4, y:-4, c:"\ue046"},	// D.C.
  sgno: {x:-6, y:0, c:"\ue047"},	// segno
  coda: {x:-12, y:-6, c:"\ue048"},
  dsgn: {x:-12, y:0, c:"\ue045"},	// D.S.
  dcap: {x:-12, y:0, c:"\ue046"},	// D.C.
  sgno: {x:-5, y:0, c:"\ue047"},	// segno
  coda: {x:-10, y:0, c:"\ue048"},
  tclef: {x:-8, y:0, c:"\ue050"},
  cclef: {x:-8, y:0, c:"\ue05c"},
  bclef: {x:-8, y:0, c:"\ue062"},
  pclef: {x:-6, y:0, c:"\ue069"},
  spclef: {x:-6, y:0, c:"\ue069"},
  stclef: {x:-8, y:0, c:"\ue07a"},
  scclef: {x:-8, y:0, c:"\ue07b"},
︙
127
128
129
130
131
132
133
134
135
136
137




138
139

140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171

















172
173
174
175
176
177
178
179







180
181
182
183
184
185
186
128
129
130
131
132
133
134




135
136
137
138
139

140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155

















156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173







174
175
176
177
178
179
180
181
182
183
184
185
186
187







-
-
-
-
+
+
+
+

-
+















-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
-
-
-
-
-
+
+
+
+
+
+
+







  sacc1: {x:-2, y:0, sc: .7, c:"\ue262"},	// small sharp (editorial)
  acc2: {x:-3, y:0, c:"\ue263"},	// double sharp
 "acc-2": {x:-3, y:0, c:"\ue264"},	// double flat
 "acc-1_2": {x:-2, y:0, c:"\ue280"},	// quarter-tone flat
 "acc-3_2": {x:-3, y:0, c:"\ue281"},	// three-quarter-tones flat
  acc1_2: {x:-1, y:0, c:"\ue282"},	// quarter-tone sharp
  acc3_2: {x:-3, y:0, c:"\ue283"},	// three-quarter-tones sharp
  accent: {x:-3, y:2.5, c:"\ue4a0"},
  stc: {x:-1, y:-2, c:"\ue4a2"},	// staccato
  emb: {x:-4, y:-2, c:"\ue4a4"},
  wedge: {x:-1, y:0, c:"\ue4a8"},
  accent: {x:-3, y:2, c:"\ue4a0"},
  stc: {x:0, y:-2, c:"\ue4a2"},		// staccato
  emb: {x:0, y:-2, c:"\ue4a4"},
  wedge: {x:0, y:0, c:"\ue4a8"},
  marcato: {x:-3, y:-2, c:"\ue4ac"},
  hld: {x:-7, y:-2, c:"\ue4c0"},	// fermata
  hld: {x:-7, y:-2, c:"\ue4c0"},		// fermata
  brth: {x:0, y:0, c:"\ue4ce"},
  caes: {x:0, y:8, c:"\ue4d1"},
  r00: {x:-1.5, y:0, c:"\ue4e1"},
  r0: {x:-1.5, y:0, c:"\ue4e2"},
  r1: {x:-3.5, y:-6, c:"\ue4e3"},
  r2: {x:-3.2, y:0, c:"\ue4e4"},
  r4: {x:-3, y:0, c:"\ue4e5"},
  r8: {x:-3, y:0, c:"\ue4e6"},
  r16: {x:-4, y:0, c:"\ue4e7"},
  r32: {x:-4, y:0, c:"\ue4e8"},
  r64: {x:-4, y:0, c:"\ue4e9"},
  r128: {x:-4, y:0, c:"\ue4ea"},
//  mrest: {x:-10, y:0, c:"\ue4ee"},
  mrep: {x:-6, y:0, c:"\ue500"},
  mrep2: {x:-9, y:0, c:"\ue501"},
  p: {x:-4, y:-6, c:"\ue520"},
  f: {x:-2.5, y:-6, c:"\ue522"},
  pppp: {x:-15, y:-6, c:"\ue529"},
  ppp: {x:-11, y:-6, c:"\ue52a"},
  pp: {x:-8, y:-6, c:"\ue52b"},
  mp: {x:-8.5, y:-6, c:"\ue52c"},
  mf: {x:-8, y:-6, c:"\ue52d"},
  ff: {x:-6, y:-6, c:"\ue52f"},
  fff: {x:-9, y:-6, c:"\ue530"},
  ffff: {x:-12, y:-6, c:"\ue531"},
  sfz: {x:-9, y:-6, c:"\ue539"},
  trl: {x:-4, y:-2, c:"\ue566"},	// trill
  turn: {x:-5, y:3, c:"\ue567"},
  turnx: {x:-5, y:3, c:"\ue569"},
  umrd: {x:-7, y:2, c:"\ue56c"},
  lmrd: {x:-7, y:2, c:"\ue56d"},
  dplus: {x:-4, y:0, c:"\ue582"},	// plus
  p: {x:-3, y:0, c:"\ue520"},
  f: {x:-3, y:0, c:"\ue522"},
  pppp: {x:-15, y:0, c:"\ue529"},
  ppp: {x:-14, y:0, c:"\ue52a"},
  pp: {x:-8, y:0, c:"\ue52b"},
  mp: {x:-8, y:0, c:"\ue52c"},
  mf: {x:-8, y:0, c:"\ue52d"},
  ff: {x:-7, y:0, c:"\ue52f"},
  fff: {x:-10, y:0, c:"\ue530"},
  ffff: {x:-14, y:0, c:"\ue531"},
  sfz: {x:-10, y:0, c:"\ue539"},
  trl: {x:-5, y:-2, c:"\ue566"},	// trill
  turn: {x:-5, y:0, c:"\ue567"},
  turnx: {x:-5, y:0, c:"\ue569"},
  umrd: {x:-6, y:2, c:"\ue56c"},
  lmrd: {x:-6, y:2, c:"\ue56d"},
  dplus: {x:-3, y:0, c:"\ue582"},	// plus
  sld: {x:-8, y:12, c:"\ue5d0"},	// slide
  grm: {x:-2, y:0, c:"\ue5e2"},		// grace mark
  dnb: {x:-4, y:0, c:"\ue610"},		// down bow
  upb: {x:-3, y:0, c:"\ue612"},		// up bow
  opend: {x:-2, y:0, c:"\ue614"},	// harmonic
  roll: {x:0, y:2, c:"\ue618"},
  thumb: {x:0, y:0, c:"\ue624"},
  snap: {x:-2, y:0, c:"\ue630"},
  grm: {x:-3, y:-2, c:"\ue5e2"},	// grace mark
  dnb: {x:-3, y:0, c:"\ue610"},		// down bow
  upb: {x:-2, y:0, c:"\ue612"},		// up bow
  opend: {x:-2, y:-2, c:"\ue614"},	// harmonic
  roll: {x:0, y:0, c:"\ue618"},
  thumb: {x:-2, y:-2, c:"\ue624"},
  snap: {x:-2, y:-2, c:"\ue630"},
  ped: {x:-10, y:0, c:"\ue650"},
  pedoff: {x:-5, y:0, c:"\ue655"},
// "mtro.": {x:0, y:0, c:"\ue910"},	// (unused)
  mtro:   {x:0, y:0, c:"\ue911"},		// tempus perfectum
// "mtro|": {x:0, y:0, c:"\ue912"},	// (unused)
// "mtrc.": {x:0, y:0, c:"\ue914"},	// (unused)
  mtrc:   {x:0, y:0, c:"\ue915"},	// tempus imperfectum
︙
881
882
883
884
885
886
887
888

889
890
891


892
893

894
895
896

897
898
899
900
901
902

903
904
905
906
907

908
909

910
911



912
913
914
915


916
917
918
919
920
921
922




923
924
925
926
927
928
929
930












931
932
933
934

935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952

953
954
955
956
957
958
959
960
961

962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
882
883
884
885
886
887
888

889
890
891

892
893
894

895
896
897

898
899
900
901
902
903

904





905
906
907
908
909

910
911
912
913
914


915
916
917
918


919


920
921
922
923
924
925






926
927
928
929
930
931
932
933
934
935
936
937
938
939
940

941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958

959
960
961
962
963
964
965
966
967

968
969
970
971
972
973
974
975
976
977
978
979
980
981
982

983
984
985
986
987
988
989







-
+


-
+
+

-
+


-
+





-
+
-
-
-
-
-
+


+

-
+
+
+


-
-
+
+


-
-

-
-
+
+
+
+


-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+



-
+

















-
+








-
+














-







function out_wln(x, y, w) {
	out_XYAB('<path class="stroke" stroke-width="0.8" d="mX YhF"/>\n',
		x, y + 1, w)
}

// decorations with string
var deco_str_style = {
crdc:	{
crdc:	{				// cresc., decresc., dim., ...
		dx: 0,
		dy: 5,
		style: 'font:italic 14px text,serif'
		style: 'font:italic 14px text,serif',
		anchor: ' text-anchor="middle"'
	},
dacs:	{
dacs:	{				// long repeats (da capo, fine...)
		dx: 0,
		dy: 3,
		style: 'font:16px text,serif',
		style: 'font:bold 15px text,serif',
		anchor: ' text-anchor="middle"'
	},
pf:	{
		dx: 0,
		dy: 5,
		style: 'font:italic bold 16px text,serif'
		style: 'font:italic bold 16px text,serif',
	},
'@':	{
		dx: 0,
		dy: 5,
		style: 'font:12px text,sans-serif'
		anchor: ' text-anchor="middle"'
	}
}
deco_str_style.at = deco_str_style.crdc

function out_deco_str(x, y, name, str) {
function out_deco_str(x, y, de) {
    var	name = de.dd.glyph			// class

	if (name == 'fng') {
		out_XYAB('\
<text x="X" y="Y" style="font-size:14px" text-anchor="middle">A</text>\n',
			x, y, m_gl(str))
<text x="X" y="Y" style="font-size:14px">A</text>\n',
			x - 2, y, m_gl(de.dd.str))
		return
	}
	var	a, f,
		a_deco = deco_str_style[name]

	if (!a_deco) {
		xygl(x, y, name)
	if (name == '@') {			// compatibility
		name = 'at'
	} else if (!/^[A-Za-z][A-Za-z\-_]*$/.test(name)) {
		error(1, de.s, "No function for decoration '$1'", de.dd.name)
		return
	}
	x += a_deco.dx;
	y += a_deco.dy;
	if (!a_deco.def) {
		style += "\n." + name + " {" + a_deco.style + "}";
		a_deco.def = true
	}

    var	f,
		a_deco = deco_str_style[name]

	if (!a_deco)
		a_deco = deco_str_style.crdc	// default style
	else if (a_deco.style)
		style += "\n." + name + "{" + a_deco.style + "}",
		delete a_deco.style

	x += a_deco.dx;
	y += a_deco.dy;
	out_XYAB('<text x="X" y="Y" class="A"B>', x, y,
		name, a_deco.anchor || "");
	set_font("annotation");
	out_str(str);
	out_str(de.dd.str)
	output += '</text>\n'
}

function out_arp(x, y, val) {
	g_open(x, y, 270);
	x = 0;
	val = Math.ceil(val / 6)
	while (--val >= 0) {
		xygl(x, 6, "ltr");
		x += 6
	}
	g_close()
}
function out_cresc(x, y, val, defl) {
	x += val * stv_g.scale
	val = -val;
	out_XYAB('<path class="stroke"\n\
	d="mX YlF ', x, y + 5, val)
	d="mX YlF ', x, y, val)
	if (defl.nost)
		output += '-2.2m0 -3.6l' + (-val).toFixed(1) + ' -2.2"/>\n'
	else
		output += '-4l' + (-val).toFixed(1) + ' -4"/>\n'

}
function out_dim(x, y, val, defl) {
	out_XYAB('<path class="stroke"\n\
	d="mX YlF ', x, y + 5, val)
	d="mX YlF ', x, y, val)
	if (defl.noen)
		output += '-2.2m0 -3.6l' + (-val).toFixed(1) + ' -2.2"/>\n'
	else
		output += '-4l' + (-val).toFixed(1) + ' -4"/>\n'
}
function out_ltr(x, y, val) {
	y += 4;
	val = Math.ceil(val / 6)
	while (--val >= 0) {
		xygl(x, y, "ltr");
		x += 6
	}
}
Abc.prototype.out_lped = function(x, y, val, defl) {
	y += 4;
	if (!defl.nost)
		xygl(x, y, "ped");
	if (!defl.noen)
		xygl(x + val + 6, y, "pedoff")
}
function out_8va(x, y, val, defl) {
	if (val < 18) {
︙
1130
1131
1132
1133
1134
1135
1136

1137


1138
1139

1140
1141
1142












































1143
1144
1145
1146
1147
1148
1149
1136
1137
1138
1139
1140
1141
1142
1143

1144
1145
1146

1147


1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199







+
-
+
+

-
+
-
-

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+








var deco_l_tb = {
	glisq: out_glisq,
	gliss: out_gliss
}

function out_deco_long(x, y, de) {
    var	s, p_v, m, nt, i,
	var	name = de.dd.glyph
	name = de.dd.glyph,
	de1 = de.start

	if (deco_l_tb[name])
	if (!deco_l_tb[name]) {
		deco_l_tb[name](x, y, de)
	else
		error(1, null, "No function for decoration '$1'", name)
		return
	}

	// if no start or no end, get the y offset of the other end
	p_v = de.s.p_v				// voice
	if (de.defl.noen) {			// if no end
		s = p_v.s_next			// start of the next music line
		while (s && !s.dur)
			s = s.next
		if (s) {
			for (m = 0; m <= s.nhd; m++) {
				nt = s.notes[m]
				if (!nt.a_dd)
					continue
				for (i = 0; i < nt.a_dd.length; i++) {
					if (nt.a_dd[i].name == de.dd.name) {
						y = 3 * (nt.pit - 18)
							+ staff_tb[de.s.st].y
						break
					}
				}
			}
		}
		x += 8				// (there is no note width)
	} else if (de.defl.nost) {		// no start
		s = p_v.s_prev			// end of the previous music line
		while (s && !s.dur)
			s = s.prev
		if (s) {
			for (m = 0; m <= s.nhd; m++) {
				nt = s.notes[m]
				if (!nt.a_dd)
					continue
				for (i = 0; i < nt.a_dd.length; i++) {
					if (nt.a_dd[i].name == de1.dd.name) {
						de1.y = 3 * (nt.pit - 18)
						break
					}
				}
			}
		}
		de1.x -= 8			// (there is no note width)
	}
	deco_l_tb[name](x, y, de)
}

// return a tempo note
function tempo_note(s, dur) {
    var	p,
	elts = identify_note(s, dur)

︙
1280
1281
1282
1283
1284
1285
1286




1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300


1301
1302
1303

1304
1305
1306
1307


1308
1309

1310
1311

1312
1313
1314
1315


1316
1317
1318
1319
1320
1321
1322
1323









1324
1325
1326
1327
1328
1329
1330
1331
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352


1353
1354



1355




1356
1357


1358


1359




1360
1361








1362
1363
1364
1365
1366
1367
1368
1369
1370

1371
1372
1373
1374
1375
1376
1377







+
+
+
+












-
-
+
+
-
-
-
+
-
-
-
-
+
+
-
-
+
-
-
+
-
-
-
-
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-








// create the SVG image of the block
function svg_flush() {
	if (multicol || !output || !user.img_out || posy == 0)
		return

    var	i, font,
	fmt = tsnext ? tsnext.fmt : cfmt,
	w = Math.ceil((fmt.trimsvg || fmt.singleline == 1)
		? (cfmt.leftmargin + img.wx * cfmt.scale + cfmt.rightmargin + 2)
		: img.width),
	head = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1"\n\
	xmlns:xlink="http://www.w3.org/1999/xlink"\n\
	fill="currentColor" stroke-width=".7"',
	g = ''

	glout()

	font = get_font("music")
	head += ' class="' + font_class(font) +
		' tune' + tunes.length + '"\n'	// tune index for play

	posy *= cfmt.scale
	if (user.imagesize) {
		head += user.imagesize +
	if (user.imagesize != undefined)
		head += user.imagesize
			' viewBox="0 0 ' + img.width.toFixed(0) + ' ' +
			 posy.toFixed(0) + '">\n'
	} else {
	else
		head += ' viewBox="0 0 ' + img.width.toFixed(0) + ' ' +
			posy.toFixed(0) +
			'" width="' + img.width.toFixed(0) +
			'px" height="' + posy.toFixed(0) + 'px">\n'
		head += ' width="' + w
			+ 'px" height="' + posy.toFixed(0) + 'px"'
	}

	head += ' viewBox="0 0 ' + w + ' '
	head += fulldefs

		+ posy.toFixed(0) + '"'
	if (style || font_style) {
		head += '<style>' + font_style
		if (cfmt.fgcolor || cfmt.bgcolor) {
			head += '\n.f' + font.fid + (cfmt.fullsvg || '')
	if (cfmt.fgcolor || cfmt.bgcolor)
		head += ' style="'
				+ '{'
				+ (cfmt.fgcolor ? ('color:' + cfmt.fgcolor + ';')
						: '')
				+ (cfmt.bgcolor ? ('background-color:' + cfmt.bgcolor)
						: '')
				+ '}'
		}
		head += style + '\n</style>\n'
			+ (cfmt.fgcolor ? ('color:' + cfmt.fgcolor + ';')
					: '')
			+ (cfmt.bgcolor ? ('background-color:' + cfmt.bgcolor)
					: '')
			+ '"'
	head += '>\n' + fulldefs

	if (style || font_style)
		head += '<style>' + font_style + style + '\n</style>\n'
	}

	if (defs)
		head += '<defs>' + defs + '\n</defs>\n'

	// if %%pagescale != 1, do a global scale
	// (with a container: transform scale in <svg> does not work
	//	the same in all browsers)
︙
1348
1349
1350
1351
1352
1353
1354
1355
1356


1357
1358
1359
1360
1361
1362

1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1394
1395
1396
1397
1398
1399
1400


1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420







-
-
+
+






+











	}
	user.img_out(head + output + g + "</svg>");
	output = ""

	font_style = ''
	if (cfmt.fullsvg) {
		defined_glyph = {}
		for (i = 0; i < font_tb.length; i++)
			font_tb[i].used = false
		for (i = 0; i < abc2svg.font_tb.length; i++)
			abc2svg.font_tb[i].used = false
	} else {
		style = '';
		fulldefs = ''
	}
	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 || cfmt.splittune)) {
		user.img_out('</div>')
		blkdiv = 0
	}
}
Abc.prototype.blk_flush = blk_flush
Changes to core/tail.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - tail.js
//
// Copyright (C) 2014-2022 Jean-Francois Moine
// Copyright (C) 2014-2024 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.
︙
19
20
21
22
23
24
25

26
27
28
29
30
31
32
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33







+








// initialize
	init_tune()

// Abc functions used by the modules
Abc.prototype.a_de = function() { return a_de }
Abc.prototype.add_style = function(s) { style += s };
Abc.prototype.anno_a = anno_a
Abc.prototype.cfmt = function() { return cfmt };
Abc.prototype.clone = clone;
Abc.prototype.deco_put = function(nm, s) {
	a_dcn.push(nm)
	deco_cnv(s)
}
Abc.prototype.defs_add = defs_add
︙
74
75
76
77
78
79
80

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

98
99

100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

99


100

























101
102
103
104
105
106
107
108
109
110







+
















-
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-










Abc.prototype.psdeco = empty_function;
Abc.prototype.psxygl = empty_function;
Abc.prototype.set_cur_sy = function(sy) { cur_sy = sy };
Abc.prototype.set_dscale = set_dscale;
Abc.prototype.set_font = set_font;
Abc.prototype.set_a_gch = function(s, a) { a_gch = a; csan_add(s) }
Abc.prototype.set_hl = set_hl
Abc.prototype.set_page = set_page
Abc.prototype.set_pagef = function() { blkdiv = 1 }
Abc.prototype.set_realwidth = function(v) { realwidth = v }
Abc.prototype.set_scale = set_scale;
Abc.prototype.set_sscale = set_sscale
Abc.prototype.set_tsfirst = function(s) { tsfirst = s };
Abc.prototype.set_v_param = set_v_param;
Abc.prototype.strwh = strwh;
Abc.prototype.stv_g = function() { return stv_g };
Abc.prototype.svg_flush = svg_flush;
Abc.prototype.syntax = syntax;
Abc.prototype.tunes = tunes
Abc.prototype.unlksym = unlksym;
Abc.prototype.use_font = use_font;
Abc.prototype.vskip = vskip
Abc.prototype.xy_str = xy_str;
Abc.prototype.xygl = xygl;

Abc.prototype.y_get = y_get
    var	hook_init		// set after setting the first module hooks

Abc.prototype.y_set = y_set
    // export functions and/or set module hooks
    function set_hooks() {
    var	h = abc2svg.modules.hooks,
	gh = abc2svg.modules.g_hooks

	function set_hs(hs) {
		for (var k = 0; k < hs.length; k++)
			hs[k](self)
	} // set_hs()

	if (hook_init) {			// if new modules
		if (h.length) {
			set_hs(h);
			gh.push.apply(gh, h);
			abc2svg.modules.hooks = []
		}
	} else {				// all modules
		if (h.length) {
			gh.push.apply(gh, h);
			abc2svg.modules.hooks = []
		}
		set_hs(gh);
		hook_init = true
	}
    } // set_hooks()
}	// end of Abc()

// compatibility
var Abc = abc2svg.Abc

// nodejs
if (typeof module == 'object' && typeof exports == 'object') {
	exports.abc2svg = abc2svg;
	exports.Abc = Abc
}
Changes to core/tune.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - tune.js - tune generation
//
// Copyright (C) 2014-2023 Jean-Francois Moine
// Copyright (C) 2014-2024 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.
︙
65
66
67
68
69
70
71


72
73
74
75
76
77
78
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80







+
+







		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)
︙
112
113
114
115
116
117
118
119
120


121
122
123
124
125


126
127
128
129
130

131
132

133
134
135
136
137
138
139
140

141
142
143
144
145

146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165

166
167
168

169
170
171
172
173
174


175
176
177


178
179
180
181



182
183















184
185
186
187




188

189
190
191
192
193
194
195


196
197

198
199










200


201
202
203
204
205
206


207
208
209
210
211
212
213
214
215
216

217















218
219
220









221
222
223
224
225
226
227
114
115
116
117
118
119
120


121
122
123
124
125


126
127
128
129
130
131

132
133

134
135
136
137
138
139
140
141

142
143
144
145
146

147
















148
149
150

151

152

153
154
155
156
157
158

159
160
161
162
163
164
165
166
167
168
169
170
171
172


173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189


190
191
192
193
194
195
196
197
198
199
200
201

202
203
204
205
206


207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223


224
225
226
227
228


229
230
231
232

233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265







-
-
+
+



-
-
+
+




-
+

-
+







-
+




-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-



-
+
-

-
+





-
+
+



+
+




+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


-
-
+
+
+
+

+






-
+
+


+
-
-
+
+
+
+
+
+
+
+
+
+

+
+




-
-
+
+



-
-




-
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+







	}
	return s
}

/* -- sort all symbols by time and vertical sequence -- */
// weight of the symbols !! depends on the symbol type !!
var w_tb = new Uint8Array([
	5,	// bar
	1,	// clef
	6,	// bar
	2,	// clef
	8,	// custos
	6,	// sm (sequence marker, after bar)
	0,	// grace (must be null)
	2,	// key
	3,	// meter
	3,	// key
	4,	// meter
	9,	// mrest
	9,	// note
	0,	// part
	9,	// rest
	4,	// space (before bar)
	5,	// space (before bar)
	0,	// staves
	7,	// stbrk
	1,	// stbrk
	0,	// tempo
	0,	// (free)
	0,	// block
	0	// remark
])

function sort_all() {
    var	s, s2, time, w, wmin, ir, fmt,
    var	s, s2, time, w, wmin, ir, fmt, v, p_voice, prev,
	fl, new_sy,
	nv = voice_tb.length,
	vtb = [],
	vn = [],			// voice indexed by range
	sy = cur_sy,			// first staff system
	sy = cur_sy			// first staff system
	v = sy.top_voice,
	p_voice = voice_tb[v],		// top voice
	prev = {			// symbol defining the first staff system
		type: C.STAVES,
		dur: 0,
		v: v,
		p_v: p_voice,
		time: 0,
		st: 0,
		sy: sy,
		next: p_voice.sym,
		seqst: true
	}

	if (!p_voice.sym)
		return

	// check if different bars at the same time
	function b_chk() {
	    var	ir, bt, s, s2, v
	    var	bt, s, s2, v, t,

		ir = 0
		bt = ""

		while (1) {
			v = vn[ir++]
			if (v == undefined)
				break
			s = vtb[v]
			if (!s || !s.bar_type || s.invis)
			if (!s || !s.bar_type || s.invis
			 || s.time != time)
				continue
			if (!bt) {
				bt = s.bar_type
				if (s.text && bt == '|')
					t = s.text
				continue
			}
			if (s.bar_type != bt)
				break
			if (s.text && !t && bt == '|') {
				t = s.text
				break
		}
		if (!v)
			}
		}

		// if the previous symbol is a grace note at the same offset as the bar
		// remove the grace notes from the previous time sequence
		if (!fl) {
			while (prev.type == C.GRACE
			    && vtb[prev.v] && !vtb[prev.v].bar_type) {
				vtb[prev.v] = prev
				prev = prev.ts_prev
				fl = 1 //true
			}
		}

		if (v == undefined)
			return			// no problem

		
		if (bt == "::" || bt == ":|") {
		// change "::" to ":| |:"
		// and    "|1" to "| [1"
		if (bt == "::" || bt == ":|"
		 || t) {
			ir = 0
			bt = t ? '|' : "::"
			while (1) {
				v = vn[ir++]
				if (v == undefined)
					break
				s = vtb[v]
				if (!s || s.invis
				 || s.bar_type != "::")
				 || s.bar_type != bt
				 || (bt == '|' && !s.text))
					continue
				s2 = clone(s)
				if (bt == "::") {
				s.bar_type = ":|"
				s2.bar_type = "|:"
					s.bar_type = ":|"
					s2.bar_type = "|:"
				} else {
//					s.bar_type = '|'
					delete s.text
					delete s.rbstart
					s2.bar_type = '['
					s2.invis = 1 //true
					s2.xsh = 0
				}
				s2.next = s.next
				if (s2.next)
					s2.next.prev = s2
				s2.prev = s
				s.next = s2
			}
		} else {
			error(2, s, "Different bars $1 and $2",
				bt, s.bar_type)
			error(1, s, "Different bars $1 and $2",
				(bt + (t || '')), (s.bar_type + (s.text || '')))
		}
	} // b_chk()

	prev.fmt = fmt = p_voice.sym.fmt	// starting format

	// set the first symbol of each voice
	for (v = 0; v < nv; v++) {
		s = voice_tb[v].sym
		vtb[v] = s
		if (sy.voices[v])
		if (sy.voices[v]) {
			vn[sy.voices[v].range] = v
			if (!prev && s) {
				fmt = s.fmt
				p_voice = voice_tb[v]
				prev = {	// symbol defining the first staff system
					type: C.STAVES,
					fname: parse.fname,
					dur: 0,
					v: v,
					p_v: p_voice,
					time: 0,
					st: 0,
					sy: sy,
					next: s,
					fmt: fmt,
					seqst: true
	}

	// insert the first staff system in the top voice
				}
			}
		}
	}

	if (!prev)
		return					// no symbol yet

	// insert the first staff system in the first voice
	p_voice.sym = tsfirst = s = prev
	if (s.next)
		s.next.prev = s
	else
		p_voice.last_sym = s

	// if Q: from tune header, put it at start of the music
︙
248
249
250
251
252
253
254
255
256
257
258
259
260















261
262
263
264
265
266
267
286
287
288
289
290
291
292


293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318







-
-




+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







	if (nv == 1) {
		s = tsfirst
		s.ts_next = s.next
		while (1) {
			s = s.next
			if (!s)
				return
			s.ts_prev = s.prev
			s.ts_next = s.next
			if (s.time != s.prev.time
			 || w_tb[s.prev.type]
			 || s.type == C.GRACE && s.prev.type == C.GRACE)
				s.seqst = 1 //true
			if (s.type == C.PART) {		// move the part
				s.prev.next =
					s.prev.ts_next = s.next
				if (s.next) {
					s.next.part = s	// to the next symbol
					s.next.prev = s.prev
					if (s.soln)
						s.next.soln = 1 //true
					if (s.seqst)
						s.next.seqst = 1 //true
				}
				continue
			}
			s.ts_prev = s.prev
			s.ts_next = s.next
		}
		// not reached
	}

	// loop on the symbols of all voices
	while (1) {
		if (new_sy) {
︙
296
297
298
299
300
301
302
303

304
305
306
307
308
309
310
311
312
313


314
315

316

317




318
319













320

321
322
323
324
325
326
327
328
329
330
331
332

333

334
335
336
337

338

339



































340
341
342
343
344
345
346
347
348
349
350
351
352
353

354
355
356
357
358
359
360
361
362
363

364
365
366
367
368

369
370
371
372
373
374


375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402

403
404
405
406
407
408

409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452







-
+









-
+
+


+
-
+

+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+

+












+
-
+




+
-
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







			}
		}

		if (wmin > 127)
			break			// done

		// check the type of the measure bars
		if (wmin == 5)			// weight of bars
		if (wmin == 6)			// !! weight of bars
			b_chk()

		/* link the vertical sequence */
		ir = 0
		while (1) {
			v = vn[ir++]
			if (v == undefined)
				break
			s = vtb[v]
			if (!s)
			if (!s
			 || s.time != time)
				continue
			w = w_tb[s.type]
			if (!w
			if (s.type == C.GRACE && s.next && s.next.type == C.GRACE)
			 && s.type == C.GRACE && s.next && s.next.type == C.GRACE)
				w--
			if (w != wmin)
				continue
			if (!w
			 && s.type == C.PART) {		// move the part
			if (s.time != time
			 || w != wmin)
				if (s.prev)
					s.prev.next = s.next
				else
					s.p_v.sym = s.next
				vtb[v] = s.next
				if (s.next) {
					s.next.part = s	// to the next symbol
					s.next.prev = s.prev
					if (s.soln)
						s.next.soln = 1 //true
//				} else {
// ignored
				}
				continue
			}
			if (s.type == C.STAVES)
				new_sy = s.sy
			if (fl) {
				fl = 0;
				s.seqst = true
			}
			s.ts_prev = prev
			prev.ts_next = s
			prev = s

			vtb[v] = s.next
		}
		if (wmin)			// if some width
		fl = wmin		/* start a new sequence if some width */
			fl = 1 //true		// start a new sequence
	}
}

// adjust some voice elements
// (possible hook)
function voice_adj(sys_chg) {
Abc.prototype.voice_adj = function (sys_chg) {
    var	p_voice, s, s2, v, sl

	// insert the delayed P: and Q: in the top_voice
	function ins_pq() {
	    var	s, s2,
		p_v = voice_tb[par_sy.top_voice]

		while (1) {
			s = parse.pq_d.shift()
			if (!s)
				break
			for (s2 = p_v.sym; ; s2 = s2.next) {
				if (s2.time >= s.time
				 && s2.dur) {
					s.next = s2
					s.prev = s2.prev
					s.prev.next =
						s2.prev = s
					s.v = s2.v
					s.p_v = p_v
					s.st = s2.st
					break
				}
			}
		}
	} // ins_pq()

	// do the note mapping stuff
	function do_map(s) {
	    var	m, nt

		for (m = 0; m <= s.nhd; m++) {
			nt = s.notes[m]
			set_map(s.p_v, nt, nt.acc, 1)		// transpose done
		}
	} // do_map()

	// set the duration of the notes under a feathered beam
	function set_feathered_beam(s1) {
		var	s, s2, t, d, b, i, a,
			d = s1.dur,
			n = 1

︙
383
384
385
386
387
388
389








390
391
392
393
394
395
396
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510







+
+
+
+
+
+
+
+








	// terminate voice cloning
	if (curvoice && curvoice.clone) {
		parse.istart = parse.eol
		do_cloning()
	}

	// if only one voice and a time skip,
	// fill the voice with the sequence "Z |" (multi-rest and bar)
	if (par_sy.one_v)			// if one voice
		fill_mr_ba(voice_tb[par_sy.top_voice])

	if (parse.pq_d)
		ins_pq()			// insert delayed P: and Q:

	for (v = 0; v < voice_tb.length; v++) {
		p_voice = voice_tb[v]
		if (!sys_chg) {			// if not %%score
			delete p_voice.eoln
			while (1) {		// set the end of slurs
				sl = p_voice.sls.shift()
				if (!sl)
︙
451
452
453
454
455
456
457
458
459
460
461








462
463
464
465
466
467
468
565
566
567
568
569
570
571




572
573
574
575
576
577
578
579
580
581
582
583
584
585
586







-
-
-
-
+
+
+
+
+
+
+
+







						s.a_ly = s2.a_ly;
						s2.a_ly = null
						break
					}
					break
				}
				continue
			}

			if (s.feathered_beam)
				set_feathered_beam(s)
			case C.NOTE:
				if (s.feathered_beam)
					set_feathered_beam(s)
				if (p_voice.map
				 && maps[p_voice.map])
					do_map(s)
				break
			}
		}
	}
}

/* -- create a new staff system -- */
function new_syst(init) {
    var	st, v, sy_staff, p_voice,
︙
542
543
544
545
546
547
548
549


550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565


566
567


568
569
570
571
572
573
574
575
576
577

578
579
580
581
582
583
584
585
586
587
588
589

590
591
592
593

594
595
596
597
598
599
600
601
602
603
604

605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622

623
624
625

626
627
628
629
630


631
632
633
634
635
636
637

638
639
640
641
642
643
644
645
660
661
662
663
664
665
666

667
668
669
670
671
672
673
674
675
676
677
678
679
680




681
682
683
684
685
686
687
688
689
690
691
692
693
694
695

696
697
698
699
700
701
702
703
704
705
706
707

708
709
710
711

712
713
714
715
716
717
718
719
720
721
722

723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740

741



742
743
744
745


746
747


748
749
750
751

752

753
754
755
756
757
758
759







-
+
+












-
-
-
-
+
+


+
+









-
+











-
+



-
+










-
+

















-
+
-
-
-
+



-
-
+
+
-
-




-
+
-







			break
		}
		break
	}

	// at start of tune, check for an anacrusis
	for (s2 = s.ts_next; s2; s2 = s2.ts_next) {
		if (s2.type == C.BAR && s2.time) {
		if (s2.type == C.BAR && s2.time
		 && !s2.invis && !s2.bar_dotted) {
			if (s2.time < wmeasure) {	// if anacrusis
				s = s2
				bar_tim = s.time
			}
			break
		}
	}

	// set the measure number on the top bars
	for ( ; s; s = s.ts_next) {
		switch (s.type) {
		case C.METER:
			if (s.time == bar_tim)
				break		// already seen
		    if (wmeasure != 1)		// if not M:none
			bar_num += (s.time - bar_tim) / wmeasure
			if (wmeasure != 1)		// if not M:none
				bar_num += (s.time - bar_tim) / wmeasure
			bar_tim = s.time
			wmeasure = s.wmeasure
			while (s.ts_next && s.ts_next.wmeasure)
				s = s.ts_next
			break
		case C.BAR:
			if (s.time <= tim)
				break			// already seen
			tim = s.time

			nu = 1 //true			// no num update
			txt = ""
			for (s2 = s; s2; s2 = s2.next) {
				if (s2.time > tim || s2.dur)
				if (s2.time > tim)
					break
				if (!s2.bar_type)
					continue
				if (s2.bar_type != '[')
					nu = 0 //false	// do update
				if (s2.text)
					txt = s2.text
			}
			if (s.bar_num) {
				bar_num = s.bar_num	// (%%setbarnb)
				ptim = bar_tim = tim
				continue
				break
			}
			if (wmeasure == 1) {		// if M:none
				if (s.bar_dotted)
					continue
					break
				if (txt) {
					if (!cfmt.contbarnb) {
						if (txt[0] == '1')
							rep_tim = bar_num
						else
							bar_num = rep_tim
					}
				}
				if (!nu)
					s.bar_num = ++bar_num
				continue
				break
			}

			n = bar_num + (tim - bar_tim) / wmeasure
			k = n - (n | 0)
			if (cfmt.checkbars
			 && k
			 && check_meas())
				error(0, s, "Bad measure duration")
			if (tim > ptim + wmeasure) {	// if more than one measure
				n |= 0
				k = 0
				bar_tim = tim		// re-synchronize
				bar_num = n
			}

			if (txt) {
				if (txt[0] == '1') {
					if (cfmt.contbarnb)
					if (!cfmt.contbarnb)
						rep_tim = bar_tim + k * wmeasure
					else
						rep_tim = tim
						rep_tim = tim - bar_tim
					if (!nu)
						s.bar_num = n
				} else {
					if (cfmt.contbarnb)
						bar_tim = rep_tim
					if (!cfmt.contbarnb)
						bar_tim = tim - rep_tim
					else
						bar_tim += tim - rep_tim
					n = bar_num + (tim - bar_tim) / wmeasure
					if (n == (n | 0))
						s.bar_num = n
				}
			} else {
			} else if (n == (n | 0)) {
				n |= 0
				s.bar_num = n
			}
			if (!k)
				ptim = tim
			break
		}
	}
︙
679
680
681
682
683
684
685
686

687
688
689
690
691
692
693
793
794
795
796
797
798
799

800
801
802
803
804
805
806
807







-
+







		return

    var	i, note, notes, map, tmp, ns,
	ty = '',
	a = text.split(/\s+/)

	if (a.length < 3) {
		syntax(1, not_enough_p)
		syntax(1, errs.not_enough_p)
		return
	}
	ns = a[1]
	if (ns[0] == '*' || ns.indexOf("all") == 0) {
		ns = 'all'
	} else {
		if (ns.indexOf("octave,") == 0	// remove the octave part
︙
737
738
739
740
741
742
743
744

745
746
747
748
749
750

751
752

753
754
755
756
757


758
759
760
761
762
763
764
765

766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852




853
854
855
856
857
858
859
851
852
853
854
855
856
857

858
859
860
861
862
863
864
865
866

867
868
869
870
871
872
873
874
875
876
877
878
879
880
881

882
883
884
885
886
887
888
889
890




























































891
892
893
894
895
896
897
898
899
900
901
902
903
904
905




906
907
908
909
910
911
912
913
914
915
916







-
+






+

-
+





+
+







-
+








-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-















-
-
-
-
+
+
+
+







		}
	}

	for (; i < a.length; i++) {
		switch (a[i]) {
		case "heads=":
			if (!a[++i]) {
				syntax(1, not_enough_p)
				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, not_enough_p)
				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, not_enough_p)
				syntax(1, errs.not_enough_p)
				break
			}
			map[2] = a[i]
			break
		}
	}
}

// set the transposition in the first key signature or in a new key
function set_transp() {
    var	s

	if (curvoice.ckey.k_bagpipe || curvoice.ckey.k_drum)
		return

	if (cfmt.transp && curvoice.shift)	// if %%transpose and shift=
		syntax(0, "Mix of old and new transposition syntaxes");

	if (is_voice_sig()) {			// if no symbol yet
		curvoice.okey.fmt = cfmt
		curvoice.key = s = clone(curvoice.okey)
	} else {
		s = clone(curvoice.ckey)
		s.k_old_sf = s.k_sf
		sym_link(s)
	}
	delete s.invis			// needed if K:C/none at start of tune
	key_transp(s)
	curvoice.ckey = clone(s)
	if (curvoice.key.k_none)
		s.k_sf = 0
}

// set the control values (P: and Q:)
function set_ctrl() {
    var	s, tim, e

	for (tim in parse.ctrl) {
//		if (!parse.ctrl.hasOwnProperty(tim))
//			continue
		e = parse.ctrl[tim]
		s = tsfirst
		while (s.next && s.next.time < tim)
			s = s.next
		while (s && s.time < tim)
			s = s.ts_next
		if (!s) {
			//fixme: insert at the end
		} else {

			// put the P: and/or Q: on a note or rest
			while (s.time == tim && s.ts_next
			 && !s.dur)
				s = s.ts_next
			if (e.part) {
//				if (s.time != tim) {
//					// fixme: insert a part (?)
//				}
				s.part = e.part
			}
			if (e.tempo) {
				lkvsym(e.tempo, s)
				lktsym(e.tempo, s)
			}
		}
	}
} // set_ctrl()

// 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
		return (((val / 12) | 0) - 3) * 40 +
			(param.slice(-1) == 'b' ?
					abc2svg.ifb40 :
					abc2svg.isb40)[val % 12]
		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) {
︙
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950

951













952
953
954
955
956
957


958
959
960


961
962







963
964
965
966
967
968
969
969
970
971
972
973
974
975





976
977




978








979







980
981
982

983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002

1003
1004
1005
1006
1007
1008
1009


1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023







-
-
-
-
-


-
-
-
-

-
-
-
-
-
-
-
-

-
-
-
-
-
-
-



-
+

+
+
+
+
+
+
+
+
+
+
+
+
+





-
+
+



+
+
-
-
+
+
+
+
+
+
+







			}
			par_sy.voices[curvoice.v][cmd[0] == 'm' ? "maxsep" : "sep"] =
					val
			return
		}
		break
	case "multicol":
		if (parse.state >= 2) {
			curvoice = voice_tb[0]
			s = new_block("mc_" + param)
			break
		}
		switch (param) {
		case "start":
			self.block_gen({
				subtype: "mc_start"
			})
			break
		case "new":
			if (!multicol) {
				syntax(1, "%%multicol new without start")
				break
			}
			self.block_gen({
				subtype: "mc_new"
			})
			break
		case "end":
			if (!multicol) {
				syntax(1, "%%multicol end without start")
				break
			}
			self.block_gen({
				subtype: "mc_end"
			})
			break
		default:
			syntax(1, "Unknown keyword '$1' in %%multicol", param)
			break
			return
		}
		s = {
			type: C.BLOCK,
			subtype: "mc_" + param,
			dur: 0
		}
		if (parse.state >= 2) {
			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) {
		if (isNaN(n) || n < -2 || n > 2
		 || (!n && !curvoice.ottava)) {
			syntax(1, errs.bad_val, "%%ottava")
			return
		}
		k = n
		if (n) {
		glovar.ottava = true;
		parse.ottava.push(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)
︙
1085
1086
1087
1088
1089
1090
1091




1092
1093
1094
1095
1096
1097
1098
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156







+
+
+
+







			}
			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":
︙
1132
1133
1134
1135
1136
1137
1138
1139
1140


1141
1142
1143
1144
1145
1146
1147
1190
1191
1192
1193
1194
1195
1196


1197
1198
1199
1200
1201
1202
1203
1204
1205







-
-
+
+







		case 0:
			cfmt.transp = 0
			// fall thru
		case 1:
			cfmt.transp = (cfmt.transp || 0) + val
			return
		}
		curvoice.tr_sco = val
		set_transp()
		curvoice.shift = val
		key_trans()
		return
	case "tune":
//fixme: to do
		return
	case "user":
		set_user(param)
		return
︙
1262
1263
1264
1265
1266
1267
1268
1269

1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286

1287
1288
1289




1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1320
1321
1322
1323
1324
1325
1326

1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343

1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360



1361
1362
1363
1364
1365
1366
1367







-
+
















-
+



+
+
+
+









-
-
-







}

/* -- generate a piece of tune -- */
function generate() {
    var s, v, p_voice;

	if (a_dcn.length) {
		syntax(1, "Decoration without symbol")
		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 ? '|' : ')')
	}

	voice_adj();
	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

	if (parse.ctrl)
		set_ctrl()		// set control values

	// 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)
︙
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326















1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338

































1339
1340
1341
1342
1343
1344
1345

1346
1347
1348


1349
1350
1351

1352
1353
1354
1355
1356
1357




















































1358
1359
1360
1361
1362
1363
1364








1365
1366
1367
1368
1369



1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384


1385
1386
1387
1388
1389
1390
1391
1376
1377
1378
1379
1380
1381
1382



1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398











1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433

1434
1435
1436
1437
1438
1439


1440
1441



1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535



1536
1537
1538
1539
1540
1541
1542
1543
1544







-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


-




+

-
-
+
+
-
-
-
+






+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







+
+
+
+
+
+
+
+





+
+
+












-
-
-
+
+








	if (tsfirst) {		// if non void, keep tune data for upper layers
		tunes.push([tsfirst, voice_tb, info, cfmt])
		tsfirst = null
	}
}

// transpose a key
function key_transp(s) {
	if (s.k_none)			// no key
// 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

    var	n, a_acc,
	b40 = (s.k_b40 + 200 + curvoice.tr_sco) % 40,
	d = abc2svg.b40k[b40] - b40

	if (d) {
		if (curvoice.tr_sco > 0)
			curvoice.tr_sco -= d
		else
			curvoice.tr_sco += d
		b40 += d
	}

	// get the current key or create a new one
	if (is_voice_sig()) {			// if no symbol yet
		curvoice.key = s		// new root key of the voice
	} else if (curvoice.time != ti) {	// if no K: at this time
		s = clone(s.orig || s)		// new key
		if (!curvoice.new)
			s.k_old_sf = curvoice.ckey.k_sf
		sym_link(s)
	}
	curvoice.ckey = s			// current key

	if (cfmt.transp && curvoice.shift)	// if %%transpose and shift=
		syntax(0, "Mix of old and new transposition syntaxes");

	// define the new key
	curvoice.tr_sco = n			// b40 interval

	n = abc2svg.b40l5[(n + 202) % 40]	// transpose in the line of fifth
		+ s.orig.k_sf			// + old = new sf
	if (n < -7) {
		n += 12
		curvoice.tr_sco -= 4
	} else if (n > 7) {
		n -= 12
		curvoice.tr_sco += 4
	}
	if (!s.k_none)
		s.k_sf = n
	for (b40 = 0; b40 < 40; b40++) {
		if (abc2svg.b40l5[b40] == n)
			break
	}
	s.k_b40 = b40
	s.k_sf = abc2svg.b40sf[b40]

	// transpose the accidental list
	if (!s.k_a_acc)
		return
	d = b40 - s.orig.k_b40
	a_acc = []
	for (n = 0; n < s.k_a_acc.length; n++) {
		b40 = abc2svg.pab40(s.k_a_acc[n].pit, s.k_a_acc[n].acc)
	for (i = 0; i < s.k_a_acc.length; i++) {
		b40 = abc2svg.pab40(s.k_a_acc[i].pit, s.k_a_acc[i].acc) + d
			+ curvoice.tr_sco

		a_acc[n] = {
		a_acc[i] = {
			pit: abc2svg.b40p(b40),
			acc: abc2svg.b40a(b40) || 3
		}
	}
	s.k_a_acc = a_acc
}

// fill a voice with a multi-rest and a bar
function fill_mr_ba(p_v) {
    var	v, p_v2,
	mxt = 0

	for (v = 0; v < voice_tb.length; v++) {
		if (voice_tb[v].time > mxt) {
			p_v2 = voice_tb[v]
			mxt = p_v2.time
		}
	}
	if (p_v.time >= mxt)
		return

    var	p_v_sav = curvoice,
	dur = mxt - p_v.time,
	s = {
		type: C.MREST,
		stem: 0,
		multi: 0,
		nhd: 0,
		xmx: 0,
		frm: 1, //true			// full measure rest
		dur: dur,
		dur_orig: dur,
		nmes: dur / p_v.wmeasure,
		notes: [{
			pit: 18,
			dur: dur
		}],
		tacet: p_v.tacet
	},
	s2 = {
		type: C.BAR,
		bar_type: '|',
		dur: 0,
		multi: 0
	}

	if (p_v2.last_sym.bar_type)
		s2.bar_type = p_v2.last_sym.bar_type
//	s2.soln = p_v2.last_sym.soln

	glovar.mrest_p = 1 //true

	curvoice = p_v
	sym_link(s)
	sym_link(s2)

	curvoice = p_v_sav
} // fill_mr_ba()

/* -- get staves definition (%%staves / %%score) -- */
function get_staves(cmd, parm) {
    var	s, p_voice, p_voice2, i, flags, v, vid, a_vf,
	st, range,
	nv = voice_tb.length,
	maxtime = 0

	// if sequence with many voices, load the other voices
	if (curvoice && curvoice.clone) {
		i = parse.eol
		parse.eol = parse.bol		// remove the %%staves line
		do_cloning()
		parse.eol = i
	}

	if (parm) {
		a_vf = parse_staves(parm)	// => array of [vid, flags]
		if (!a_vf)
			return
	} else if (staves_found < 0) {
		syntax(1, errs.bad_val, '%%' + cmd)
		return
	}

	/* create a new staff system */
	for (v = 0; v < nv; v++) {
		p_voice = voice_tb[v]
		if (p_voice.time > maxtime)
			maxtime = p_voice.time
	}
	if (!maxtime) {				// if first %%staves
		par_sy.staves = []
		par_sy.voices = []
	} else {

		if (nv)					// if many voices
			voice_adj(true)
//		if (nv)					// if many voices
		self.voice_adj(1)
		/*
		 * create a new staff system and
		 * link the 'staves' symbol in a voice which is seen from
		 * the previous system - see sort_all
		 */
		for (v = 0; v < par_sy.voices.length; v++) {
			if (par_sy.voices[v]) {
︙
1421
1422
1423
1424
1425
1426
1427
1428
1429










1430
1431
1432
1433
1434
1435
1436
1574
1575
1576
1577
1578
1579
1580


1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597







-
-
+
+
+
+
+
+
+
+
+
+








	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.ignore
		delete p_voice.floating
		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);
		p_voice.time = maxtime;
		v = p_voice.v
︙
1445
1446
1447
1448
1449
1450
1451


1452
1453
1454
1455
1456
1457
1458
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621







+
+







			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
︙
1558
1559
1560
1561
1562
1563
1564

1565
1566
1567
1568
1569
1570
1571
1572
1573

1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736

1737
1738
1739
1740


1741
1742
1743
1744
1745
1746
1747







+








-
+



-
-








		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
		if (st > 0 && p_voice.norepbra == undefined
		 && !(par_sy.staves[st - 1].flags & STOP_BAR))
			p_voice.norepbra = true
	}
	if (!maxtime && nv)		// if first staff system and many voices
		voice_adj(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
︙
1708
1709
1710
1711
1712
1713
1714
1715

1716
1717
1718
1719
1720
1721
1722
1870
1871
1872
1873
1874
1875
1876

1877
1878
1879
1880
1881
1882
1883
1884







-
+







	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 = null
		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 = {
︙
1748
1749
1750
1751
1752
1753
1754













1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771





















1772
1773
1774
1775






1776
1777
1778
1779
1780
1781


1782



1783
1784
1785
1786
1787

1788
1789
1790
1791


1792
1793
1794





1795
1796



1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812

1813


1814
1815

1816
1817
1818

1819
1820

1821
1822
1823
1824
1825
1826



1827
1828
1829
1830
1831
1832
1833
1834
1835








1836
1837
1838
1839

1840
1841
1842
1843
1844


1845
1846
1847
1848




1849
1850
1851



1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866

1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936










1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957




1958
1959
1960
1961
1962
1963

1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978

1979
1980
1981
1982

1983
1984
1985
1986
1987
1988
1989
1990
1991
1992


1993
1994
1995
1996
1997
1998
1999
2000
2001


2002
2003



2004
2005

2006
2007
2008
2009
2010

2011



2012


2013






2014
2015
2016
2017
2018







2019
2020
2021
2022
2023
2024
2025
2026




2027


2028


2029
2030




2031
2032
2033
2034



2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051

2052








2053
2054
2055
2056
2057
2058
2059







+
+
+
+
+
+
+
+
+
+
+
+
+







-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
-





+
+

+
+
+




-
+



-
+
+



+
+
+
+
+
-
-
+
+
+






-
-


-
-
-


-
+

+
+

-
+
-
-
-
+
-
-
+
-
-
-
-
-
-
+
+
+


-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
+
-
-

-
-
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+














-
+
-
-
-
-
-
-
-
-







		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
	}

	// clef change
	sym_link(s);
	s.clef_small = true

	// move the clef before a (not right repeat) bar
    var	s2 = s.prev
	if (!s.invis			// if not 'K: clef=none'
	 && s2 && s2.type == C.BAR
	 && s2.bar_type[0] != ':') {
		s.next = s2
	// 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
	}
	if (s2
	 && s2.time == curvoice.time
	 && s2.bar_type && s2.bar_type[0] != ':')
		s3 = s2				// move before a measure bar
		s.prev = s2.prev
		if (s.prev)
			s.prev.next = s
		s2.prev = s
	if (s3) {
		s2 = curvoice.last_sym
		curvoice.last_sym = s3.prev
		sym_link(s)
		s.next = s3
		s3.prev = s
		s2.next = null
		curvoice.last_sym = s2
		if (s.soln) {
			delete s.soln
			curvoice.eoln = true
		}
	} else {
		sym_link(s)
	}

	if (s.prev)				// if not the first clef of the voice
		s.clef_small = 1 //true		// have a small clef
}

// treat K: (kp = key signature + parameters)
function get_key(parm) {
    var	v, p_voice, transp, sndtran, tr_p, nt,
    var	v, p_voice,
//		[s_key, a] = new_key(parm)	// KO with nodejs
		a = new_key(parm),
		s_key = a[0],
		s = s_key
		s = s_key,
		empty = s.k_sf == undefined && !s.k_a_acc

	a = a[1]

	if (empty)
		s.invis = 1 //true		// don't display empty K:
	else
		s.orig = s			// new transposition base

	if (parse.state == 1) {		// in tune header (first K:)
		if (s_key.k_sf == undefined && !s_key.k_a_acc) { // empty K:
	if (parse.state == 1) {			// in tune header (first K:)
		parse.ckey = s			// root key
		if (empty) {
			s_key.k_sf = 0;
			s_key.k_none = true
			s_key.k_map = abc2svg.keys[7]
		}
		for (v = 0; v < voice_tb.length; v++) {
			p_voice = voice_tb[v];
			p_voice.key = clone(s_key);
			p_voice.okey = clone(s_key);
			p_voice.ckey = clone(s_key)
		}
		parse.ckey = s_key
		if (!glovar.ulen)
			glovar.ulen = C.BLEN / 8;
		if (a.length) {
			memo_kv_parm('*', a)
			a = ''
			a = []
		}
		if (!glovar.ulen)
			glovar.ulen = C.BLEN / 8;
		goto_tune()
	} else {
	} else if (!empty) {
		set_kv_parm(a)
	}

		if (curvoice.tr_sco)
	tr_p = curvoice.tr_p			// transposition change 1=sco, 2=snd
	curvoice.tr_p = 0
			curvoice.tr_sco = undefined
	if (s.k_sf == undefined) {		// if no key
		if (!s.k_a_acc			// if no accidental list
		 && !(tr_p & 1))		// and no score transposition
			return			// not a key signature
		s_key.k_sf = curvoice.okey.k_sf	// set the same key
		s_key.k_b40 = curvoice.okey.k_b40
		s.k_old_sf = curvoice.ckey.k_sf	// memorize the previous key
		curvoice.ckey = s
		sym_link(s)
	}


	if (curvoice.tr_sco)			// if transpose score
		key_transp(s)
	curvoice.okey = clone(s_key)

	s_key.k_old_sf = curvoice.ckey.k_sf	// memorize the key changes

	// set the voice parameters
	if (!curvoice) {			// if first K:
		if (!voice_tb.length) {
			curvoice = new_voice("1")
		    var	def = 1 // true
		} else {
			curvoice = voice_tb[staves_found < 0 ? 0 : par_sy.top_voice]
		}
	if ((!s_key.k_a_acc || !s_key.k_a_acc.length)
	 && !s_key.k_sf && !s_key.k_old_sf)
		s_key.invis = true		// don't display the key signature

	}
	if (!s_key.k_b40)
		s_key.k_b40 = curvoice.ckey.k_b40

	curvoice.ckey = s_key
	if (is_voice_sig()) {
	p_voice = curvoice.clone
	if (p_voice)
		s_key.fmt = cfmt
		curvoice.key = clone(s_key)
		if (s_key.k_none)
			curvoice.key.k_sf = 0
		curvoice.clone = null		// don't stop the multi-voice sequence
	get_voice(curvoice.id + ' ' + a.join(' '))
	if (p_voice)
		curvoice.clone = p_voice
	} else {
		sym_link(s_key)			// (don't move the key)
	}

	if (def)
		curvoice.default = 1 //true
}

// get / create a new voice
function new_voice(id) {
    var	v, p_v_sav,
	p_voice = voice_tb[0],
	n = voice_tb.length

	// if first explicit voice and no music, replace the default V:1
	if (n == 1
	 && p_voice.default) {
		delete p_voice.default
		if (!p_voice.time) {		// if no symbol yet
			p_voice.id = id
			delete p_voice.init	// reload the global attributes
			p_voice.init = 0	// set back the global voice parameters
			if (cfmt.transp	// != undefined
			 && parse.state >= 2) {
				p_v_sav = curvoice;
				curvoice = p_voice;
				curvoice.tr_sco = cfmt.transp
				set_transp();
				curvoice = p_v_sav
			}
			return p_voice		// default voice
		}
	}
	for (v = 0; v < n; v++) {
		p_voice = voice_tb[v]
		if (p_voice.id == id)
			return p_voice		// old voice
︙
1897
1898
1899
1900
1901
1902
1903
1904
1905


1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922











1923
1924
1925
1926
1927
1928
1929
2075
2076
2077
2078
2079
2080
2081


2082
2083

2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117







-
-
+
+
-
















+
+
+
+
+
+
+
+
+
+
+







//			vol: 0
		},
		scale: 1,
//		st: 0,
//		cst: 0,
		ulen: glovar.ulen,
		dur_fact: 1,
		key: clone(parse.ckey),		// key at start of tune (parse / gene)
		ckey: clone(parse.ckey),	// current key (parse / gene)
//		key: clone(parse.ckey),		// key at start of tune (parse / gene)
//		ckey: clone(parse.ckey),	// current key (parse / gene)
		okey: clone(parse.ckey),	// key without transposition (parse)
		meter: clone(glovar.meter),
		wmeasure: glovar.meter.wmeasure,
		staffnonote: 1,
		clef: {
			type: C.CLEF,
			clef_auto: true,
			clef_type: "a",		// auto
			time: 0
		},
		acc: [],		// accidentals of the measure (parse)
		sls: [],		// slurs - used in parsing and in generation
		hy_st: 0
	}

	voice_tb.push(p_voice);

	if (parse.state == 3) {
//		p_voice.key = parse.ckey	// (done later in music.js)
		p_voice.ckey = clone(parse.ckey)
		if (p_voice.ckey.k_bagpipe
		 && !p_voice.pos.stm) {
			p_voice.pos = clone(p_voice.pos)
			p_voice.pos.stm &= ~0x07
			p_voice.pos.stm |= C.SL_BELOW
		}
	}
	
//	par_sy.voices[v] = {
//		range: -1
//	}

	return p_voice
}

︙
1942
1943
1944
1945
1946
1947
1948
1949

1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963

1964
1965
1966
1967
1968
1969
1970
2130
2131
2132
2133
2134
2135
2136

2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150

2151
2152
2153
2154
2155
2156
2157
2158







-
+













-
+







// treat V: with many voices
function do_cloning() {
    var	i,
	clone = curvoice.clone,
	vs = clone.vs,
	a = clone.a,
	bol = clone.bol,
	eol = parse.istart,
	eol = parse.eol,
	parse_sav = parse,
	file = parse.file

	delete curvoice.clone

	if (file[eol - 1] == '[')	// if stop on [V:xx]
		eol--

	// insert the music sequence in each voice
	include++;
	for (i = 0; i < vs.length; i++) {
		parse = Object.create(parse_sav) // create a new parse context
		parse.line = Object.create(parse_sav.line)
		get_voice(vs[i], a)
		get_voice(vs[i] + ' ' + a.join(' '))
		tosvg(parse.fname, file, bol, eol)
	}
	include--
	parse = parse_sav	// restore the parse context
}

// treat a 'V:' info
︙
2006
2007
2008
2009
2010
2011
2012
2013

2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024


2025
2026
2027
2028
2029
2030
2031
2194
2195
2196
2197
2198
2199
2200

2201
2202
2203
2204
2205
2206
2207
2208




2209
2210
2211
2212
2213
2214
2215
2216
2217







-
+







-
-
-
-
+
+







	curvoice = new_voice(vs[0])

	// if many voices, memorize the start of sequence
	if (vs.length > 1) {
		vs.shift()
		curvoice.clone = {
			vs: vs,
			a: a,
			a: a.slice(0),		// copy the parameters
			bol: parse.iend
		}
		if (parse.file[curvoice.clone.bol - 1] != ']')
			curvoice.clone.bol++	// start of new line
	}

	set_kv_parm(a)
	if (curvoice.tr_p) {
		curvoice.tr_p = 0
		set_transp()
	}

	key_trans()

	v = curvoice.v
	if (curvoice.new) {			// if new voice
		delete curvoice.new
		if (staves_found < 0) {		// if no %%score/%%staves
			curvoice.st = curvoice.cst = ++nstaff;
			par_sy.nstaff = nstaff;
︙
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086

2087
2088
2089
2090
2091
2092
2093
2250
2251
2252
2253
2254
2255
2256











2257
2258
2259
2260

2261
2262
2263
2264
2265
2266
2267
2268







-
-
-
-
-
-
-
-
-
-
-




-
+







		glovar.new_nbar = 0
	} else {
		gene.nbar = 1
	}

	parse.state = 3				// in tune body

	// if no voice yet, create the default voice
	if (!voice_tb.length) {
		get_voice("1");
		curvoice.clef.istart = curvoice.key.istart;
		curvoice.clef.iend = curvoice.key.iend;
//		nstaff = 0;
		curvoice.default = true
	} else {
		curvoice = voice_tb[staves_found < 0 ? 0 : par_sy.top_voice]
	}

	// update some voice parameters
	for (v = 0; v < voice_tb.length; v++) {
		p_voice = voice_tb[v];
		p_voice.ulen = glovar.ulen
		if (p_voice.ckey.k_bagpipe
		if (parse.ckey.k_bagpipe
		 && !p_voice.pos.stm) {
			p_voice.pos = clone(p_voice.pos)
			p_voice.pos.stm &= ~0x07
			p_voice.pos.stm |= C.SL_BELOW
		}
	}

︙
Changes to dist_bin.
1
2
3
4
5
6
7

8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15







+







COPYING
COPYING.LESSER
MIDI-1.js
Scc1t2/
abc2svg-1.js
abc2svg.ttf
abc2svg.woff
abc2svg.woff2
abcdoc-1.js
abcjsc
abcmjs
abcnode
abcqjs
abctopdf
abcweb1-1.js
︙
Changes to editor/edit.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// edit.js - file used in the abc2svg editor
//
// Copyright (C) 2014-2022 Jean-Francois Moine
// Copyright (C) 2014-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
︙
24
25
26
27
28
29
30






31
32
33
34
35
36
37
38
39
40
41
42
43

44
45
46
47
48
49
50
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57







+
+
+
+
+
+













+







			"\nLine: " + line)
	else if (typeof msg == 'object')
		alert("window error: " + msg.type + ' ' + msg.target.src)
	else
		alert("window error: " + msg)
	return false
}

// function called before the page is closed
window.onbeforeunload = function () {
	if (chg)			// if the textarea has been modified
		return ""		// ask close page confirmation
}

var	abc_images,			// image buffer
	abc_fname = ["noname.abc", ""],	// file names
	abc_mtime = [],			// associated last modification time
	abc,				// Abc object
	syms,				// music symbol at source index
	ctxMenu,			// context menu for play
	elt_ref = {},			// pointers to page HTML elements
	selx = [0, 0],			// selected source indexes
	selx_sav = [],			// (saved while playing/printing)
	play = {},			// play data
	pop,				// current popup message
	texts = {},			// language specific texts
	chg = 0,			// > 0 when the textarea is modified
	jsdir = document.currentScript ?
		document.currentScript.src.match(/.*\//) :
		(function() {
		     var s_a = document.getElementsByTagName('script')
			for (var k = 0; k < s_a.length; k++) {
				if (s_a[k].src.indexOf('edit-') >= 0)
					return s_a[k].src.match(/.*\//) || ''
︙
164
165
166
167
168
169
170

171
172
173
174
175
176
177
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185







+








	// Closure to capture the file information
	reader.onloadend = function(evt) {
	    var	s = srcidx == 0 ? "source" : "src1";

		elt_ref[s].value = evt.target.result;
		elt_ref["s" + srcidx].value = abc_fname[srcidx];
		chg = -1			// no change yet
		src_change()
	}

	// Read the file as text
	reader.readAsText(files[0], "UTF-8")
}

︙
207
208
209
210
211
212
213

214
215
216
217
218
219
220
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229







+







			selsrc(1);
			alert(texts.load + sl.value)
			return
		}
	}
	elt_ref.diverr.innerHTML = '';
	selx[0] = selx[1] = 0;
	chg++					// textarea modified
	render2()
}
function render2() {
    var	content = elt_ref.source.value,
	def = (abc2svg.a_inc && abc2svg.a_inc["default.abc"]) || ''

	// load the required modules
︙
447
448
449
450
451
452
453


454
455
456
457
458
459
460
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471







+
+







	link.style.display = "none";

	// add the link to the DOM
	document.body.appendChild(link);

	// click the new link
	link.click()

	chg = 0					// no change anymore
}

// destroy the clicked element
function destroyClickedElement(evt) {
	document.body.removeChild(evt.target)
}

︙
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
546
547
548
549
550
551
552

553
554
555
556
557
558
559







-







			play.stop = -1;
			play.abcplay.stop()
		}
		return
	}

	// search a symbol to play

	function gnrn(sym, loop) {	// go to the next real note (not tied)
	    var	i
		while (1) {
			switch (sym.type) {
			case C.NOTE:
				i = sym.nhd + 1
				while (--i >= 0) {
︙
569
570
571
572
573
574
575

576
577
578
579
580
581
582
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593







+







					return gprn(sym, 1)
				return sym
			}
			sym = sym.ts_next
		}
		// not reached
	}

	function gprn(sym, loop) {	// go to the previous real note (not tied)
	    var	i
		while (1) {
			switch (sym.type) {
//			case C.BAR:
//fixme: there may be a right repeat!
//			break
︙
607
608
609
610
611
612
613




614

615
616
617
618
619
620
621
618
619
620
621
622
623
624
625
626
627
628

629
630
631
632
633
634
635
636







+
+
+
+
-
+







			}
			sym = sym.ts_prev
		}
		// not reached
	}

	function gsot(si) {		// go to the first symbol of a tune
	    var	sym = syms[si].p_v.sym

		while (!sym.seqst)
			sym = sym.ts_prev
		return syms[si].p_v.sym
		return sym
	}
	function get_se(si) {			// get the starting symbol
	    var	sym = syms[si]

		while (!sym.seqst)
			sym = sym.ts_prev
		return sym
︙
891
892
893
894
895
896
897

898
899
900
901
902
903
904
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920







+







	if (data.length) {
	    var reader = new FileReader(),
		s = srcidx == 0 ? "source" : "src1"

		elt_ref["s" + srcidx].value = abc_fname[srcidx] = data[0].name
		reader.onload = function(evt) {
			elt_ref[s].value = evt.target.result
			chg = -1			// no change yet
			src_change()
		}
		reader.readAsText(data[0],"UTF-8")
//		return
	}
}

︙
Changes to editor/edit.xhtml.
︙
12
13
14
15
16
17
18
19

20
21
22
23
24
25

26
27
28

29
30

31
32
33
34
35

36
37
38
39
40
41

42
43
44

45
46
47

48
49
50
51

52
53
54
55

56
57
58
59
60
61
62
63
64

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

82
83
84
85
86
87


88
89
90
91
92
93
94
12
13
14
15
16
17
18

19
20
21
22
23
24

25
26
27

28
29

30
31
32
33
34

35
36
37
38
39
40

41
42
43

44
45
46

47
48
49
50

51
52
53
54

55
56
57
58
59
60
61
62
63

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

81
82
83
84
85


86
87
88
89
90
91
92
93
94







-
+





-
+


-
+

-
+




-
+





-
+


-
+


-
+



-
+



-
+








-
+
















-
+




-
-
+
+







<body ontouchstart="" bgcolor="#faf0e6" spellcheck="false">

<!-- left -->
<div id="dleft">

<!-- menu bar -->
    <ul id="nav">
	<li class="dropbutton"><label id="f">File</label>
	<li class="dropbutton"><span id="f">File</span>
		<ul class="droplinks">
		    <li><input type="file" id="abcfile" accept="*"
				style="display:none" onchange="loadtune()"/>
			<label id="fl" for="abcfile">Load file</label>
		    </li>
		    <li><label id="saveas">Save file</label></li>
		    <li><span id="saveas">Save file</span></li>
		</ul>
	</li>
	<li class="dropbutton"><label id="pr">Preferences</label>
	<li class="dropbutton"><span id="pr">Preferences</span>
		<ul class="droplinks">
			<li><label id="fs">Font size</label>
			<li><span id="fs">Font size</span>
			    <input type="number" id="fontsize"
				 min="10" max="20" value="14" onchange="setfont()"/>
			</li>
			<li id="playdiv1" style="display: none">
				<label id="sful">Sound font URL</label>
				<span id="sful">Sound font URL</span>
				 <input id="sfu" type="text" maxlength="120"
					size="50"
					onblur="set_sfu(this.value)"/>
			</li>
			<li id="playdiv3" style="display: none">
				<label id="gv">Volume</label>
				<span id="gv">Volume</span>
				 <input id="gvol" type="range" min="1" max="10" value="7"
					onchange="set_vol(this.value / 10)"/>
				<label id="gvl">0.70</label>
				<span id="gvl">0.70</span>
			</li>
			<li id="playdiv4" style="display: none">
				<label id="sp">Speed</label>
				<span id="sp">Speed</span>
				 <input id="spv" type="range"
					min="1" max="20" value="10" step=".5"
					onchange="set_speed(this.value)"/>
				<label id="spvl">1</label>
				<span id="spvl">1</span>
			</li>
		</ul>
	</li>
	<li class="dropbutton"><label id="lg">Language</label>
	<li class="dropbutton"><span id="lg">Language</span>
		<ul class="droplinks">
		<li onclick="loadlang('de')">Deutsch</li>
		<li onclick="loadlang('en')">English</li>
		<li onclick="loadlang('fr')">Français</li>
		<li onclick="loadlang('it')">Italiano</li>
		<li onclick="loadlang('pt_BR')">Português do Brasil</li>
		</ul>
	</li>
	<li class="dropbutton"><label id="h">Help</label>
	<li class="dropbutton"><span id="h">Help</span>
		<ul class="droplinks">
			<li id="ha" onclick="popshow('help', true)">Help</li>
			<li><a id="df" target="_blank"
 href="http://moinejf.free.fr/abcm2ps-doc/features.html">abc2svg features</a>
			</li>
			<li><a id="dp" target="_blank"
 href="http://moinejf.free.fr/abcm2ps-doc/index.html">abc2svg parameters</a>
			</li>
			<li id="a" onclick="popshow('about', true)">About</li>
		</ul>
	</li>
    </ul>
<br/>

<!-- buttons -->
<p>
<label id="b">ABC files:</label>
<span id="b">ABC files:</span>
<input id="s0" type="button" style="display: inline; background-color: #80ff80"
	value="(noname)"/>
<input id="s1" type="button" style="display: none; background-color: #ffd0d0"
	value=""/>
<label id="er" onclick="popshow('errlist', true)"
 style="display: none; background: #ff8080">Errors</label>
<span id="er" onclick="popshow('errlist', true)"
 style="display: none; background: #ff8080">Errors</span>

<!-- ABC source in textarea (main and include) -->
</p>
<textarea id="source" rows="40" cols="73" wrap="off"
	style="font: 14px monospace"
	ondrop="drop(event)" ondragenter="drag_enter(event)"
	oninput="src_change()"></textarea>
︙
140
141
142
143
144
145
146
147

148
149
150
151
152
153
154
155
156
157
158
159
140
141
142
143
144
145
146

147
148
149
150
151
152
153
154
155
156
157
158
159







-
+












</ul>
</div>

<!-- about popup window -->
<div id="about" class="popup" style="width: 350px">
<div class="close" onclick="popshow('about')">x</div>
<p id="abc2svg">abc2svg</p>
<p>Copyright &#x00A9; 2016-2022 <a
<p>Copyright &#x00A9; 2016-2024 <a
href="http://moinejf.free.fr">Jean-François Moine</a></p>
</div>

<!-- javascript must be enabled -->
<noscript>
<div id="okjs" class="popup" style="width:50%;background:#ff8080;visibility:visible">
Please enable Javascript.
</div>
</noscript>

</body>
</html>
Changes to err-de.js.
︙
74
75
76
77
78
79
80
81

82
83

84
85
86
87
88
89
90
74
75
76
77
78
79
80

81
82
83
84
85
86
87
88
89
90
91







-
+


+







	"Cannot have %%beginml with %%pageheight":
				"Cannot have %%beginml with %%pageheight",
    "Cannot have a bar in grace notes": "Taktstrich in Vorschlagnote nicht erlaubt",
	"Cannot have a broken rhythm in grace notes": "gebrochener Rythmus in Ziernoten nicht erlaubt",
    "Cannot have V:* in tune body": "V:* im Notenbereich nicht erlaubt",
    "Cannot read file '$1'": "File '$1' kann nicht gelesen werden",
    "Decoration ignored": "Dekoration ignoriert",
	"Decoration without symbol": "Decoration without symbol",
	"Decoration(s) without symbol: $1": "Decoration(s) without symbol: $1",
	"Double voice in %%score": "Double voice in %%score",
    "Empty line in tune header - ignored": "Leerzeile in Kopfbereich - ignoriert",
	"End of file in tune header": "End of file in tune header",
	"End of slur without start": "End of slur without start",
	"Erroneous end of voice overlay":
			"Fehlerhaftes Ende einer Stimme in Stimm-Überlagerung",
	"Error in %%pos": "Error in %%pos",
	"Error loading the module $1": "Error loading the module $1",
    "Incorrect 1st value in %%repeat": "erster Wert fehlerhaft in %%repeat",
    "Incorrect 2nd value in %%repeat": "zweiter Wert fehlerhaft in %%repeat",
︙
103
104
105
106
107
108
109

110
111
112
113
114
115
116
117
118
119
120
121
122

123
124
125
126
127
128
129
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132







+













+







		"Probleme beim Aufteilen der Zeile - justiere maxshrink und/oder breaklimit",
    "Line too much shrunk $1 $2 $3": "Zeile zu stark geschrumpft $1 $2 $3",
    "Line underfull ($1pt of $2pt)": "Zeile nicht voll genug ($1pt of $2pt)",
	"Microtone transposition not coded":
				"Microtone transposition not coded",
    "Misplaced '$1' in %%score": "'$1' fehlerhaft platziert in %%score",
    "Misplaced dot": "fehlerhaft platzierter Punkt",
	"Misplaced P:": "Misplaced P:",
	"Mix of old and new transposition syntaxes":
				"Mix von alter und neuer Transponierungs-syntax",
	"multi-measure rest, but no measure!":
			"multi-measure rest, but no measure!",
    "No $1 after %%$2": "kein $1 nach %%$2",
    "No </defs> in %%beginsvg sequence": "kein </defs> in %%beginsvg squenz",
    "No </style> in %%beginsvg sequence": "kein </style> in %%beginsvg sequenz",
    "No accidental after 'exp'": "kein Vorzeichen nach 'exp'",
    "No end of decoration": "kein Ende der Dekoration",
	"No end of grace note sequence": "kein Ende der Vorschlagnoten",
    "No end of chord symbol/annotation": "kein Ende des Akkordsymbols",
    "No end of repeat string": "kein Ende des Wiederholungszeichens",
	"No end of string in font family": "No end of string in font family",
	"No end of the previous %%multicol": "No end of the previous %%multicol",
    "No end of tuplet": "kein Ende des Tuplets",
    "No end of tuplet in this music line":
			"Kein Ende des Tuplets in dieser Zeile",
	"No end of url in font family": "No end of url in font family",
	"No end of voice overlay": "kein Ende der Stimmüberlagerung",
    "No function for decoration '$1'": "keine Funktion für Dekoration '$1'",
    "No note before '-'": "keine Note vor '-'",
︙
Changes to err-fr.js.
︙
80
81
82
83
84
85
86

87

88
89
90


91
92
93
94
95
96
97
80
81
82
83
84
85
86
87

88
89
90
91
92
93
94
95
96
97
98
99
100







+
-
+



+
+







			"Il ne peut pas y avoir de barre dans les notes d'agrément",
	"Cannot have a broken rhythm in grace notes":
			"Il ne peut pas y avoir '<' ou '>' dans les notes d'agrément",
	"Cannot have V:* in tune body":
			"Il ne peut pas y avoir V:* dans le corps du morceau",
	"Cannot read file '$1'": "Fichier '$1' inexistant",
	"Decoration ignored": "Décoration ignorée",
	"Decoration(s) without symbol: $1":
	"Decoration without symbol": "Pas de symbole où mettre la décoration",
			"Pas de symbole où mettre les décorations: $1",
	"Double voice in %%score": "Voix en double dans %%score",
	"Empty line in tune header - ignored":
				"Ligne vide dans en-tête de morceau - ignorée",
	"End of file in tune header":
				"Fin de fichier dans entête de morceau",
	"End of slur without start": "Fin de liaison sans début",
	"Erroneous end of voice overlay": "Fin de superposition de voix erronée",
	"Error in %%pos": "Erreur dans %%pos",
	"Error loading the module $1": "Erreur de chargement du module $1",
	"Incorrect 1st value in %%repeat": "Première valeur incorrecte dans %%repeat",
	"Incorrect 2nd value in %%repeat": "Deuxième valeur incorrecte dans %%repeat",
	"Invalid 'r' in tuplet": "'r' invalide dans le tuplet",
︙
109
110
111
112
113
114
115

116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

132
133
134
135
136
137
138
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143







+
















+







		"Problème de découpe en lignes - ajuster maxshrink et/ou breaklimit",
	"Line too much shrunk $1 $2 $3": "Ligne trop compressée $1 $2 $3",
	"Line underfull ($1pt of $2pt)": "Trop d'espacement ($1pt of $2pt)",
	"Microtone transposition not coded":
				"Transposition de microtonalité pas codée",
	"Misplaced '$1' in %%score": "'$1' mal placé dans %%score",
	"Misplaced dot": "Point mal placé",
	"Misplaced P:": "P: mal placé",
	"Mix of old and new transposition syntaxes":
			"Mélange des syntaxes de transposition ancienne et nouvelle",
	"multi-measure rest, but no measure!":
			"silence multi-mesure, mais pas de mesure!",
	"No $1 after %%$2": "Pas de $1 après %%$2",
	"No </defs> in %%beginsvg sequence":
				"Pas de </defs> dans séquence %%beginsvg",
	"No </style> in %%beginsvg sequence":
				"Pas de </style> dans séquence %%beginsvg",
	"No accidental after 'exp'": "Pas d'altération après 'exp'",
	"No end of decoration": "Pas de fin de décoration",
	"No end of grace note sequence": "Pas de fin de notes d'agrément",
	"No end of chord symbol/annotation": "Pas de fin d'accord/annotation",
	"No end of repeat string": "Chaine de répétition non terminée",
	"No end of string in font family":
			"Pas de fin de chaine dans le nom de famille de la police",
	"No end of the previous %%multicol": "Pas de 'end' du %%multicol précédent",
	"No end of tuplet": "Pas de fin de tuplet",
	"No end of tuplet in this music line":
				"Pas de fin de tuplet dans cette ligne de musique",
	"No end of url in font family": "Pas de fin de l'url de la police",
	"No end of voice overlay": "Pas de fin de superposition de voix",
	"No function for decoration '$1'": "Pas de fonction pour décoration '$1'",
	"No note before '-'": "Pas de note devant '-'",
︙
Changes to err-it.js.
︙
80
81
82
83
84
85
86
87

88
89
90

91
92
93
94
95
96
97
80
81
82
83
84
85
86

87
88
89
90
91
92
93
94
95
96
97
98







-
+



+







			"Stanghette non consentite nelle note di abbellimento",
	"Cannot have a broken rhythm in grace notes":
			"'Broken rhythm' non consentito nelle note di abbellimento",
	"Cannot have V:* in tune body":
			"V:* non consentito nel corpo del brano",
	"Cannot read file '$1'": "File '$1' inesistente",
	"Decoration ignored": "Decorazione ignorata",
	"Decoration without symbol": "Decoration without symbol",
	"Decoration(s) without symbol: $1": "Decoration(s) without symbol: $1",
	"Double voice in %%score": "Double voice in %%score",
	"Empty line in tune header - ignored":
				"Linea vuota nella testata - ignorata",
	"End of file in tune header": "End of file in tune header",
	"End of slur without start": "End of slur without start",
	"Erroneous end of voice overlap": "Fine di voice overlay errata",
	"Error in %%pos": "Error in %%pos",
	"Error loading the module $1": "Error loading the module $1",
	"Incorrect 1st value in %%repeat": "Primo valore in %%repeat errato",
	"Incorrect 2nd value in %%repeat": "Secondo valore in %%repeat errato",
	"Invalid 'r' in tuplet": "'r' non valido in gruppo irregolare",
︙
109
110
111
112
113
114
115

116
117
118
119
120
121
122
123
124
125
126
127
128
129
130

131
132
133
134
135
136
137
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140







+















+







		"Problema di linea divisa - modificare maxshrink e/o breaklimit",
	"Line too much shrunk $1 $2 $3": "Linea troppo compressa $1 $2 $3",
	"Line underfull ($1pt of $2pt)": "Linea troppo vuota ($1pt di $2pt)",
	"Microtone transposition not coded":
				"Microtone transposition not coded",
	"Misplaced '$1' in %%score": "'$1' in posizione errata in %%score",
	"Misplaced dot": "Punto in posizione errata",
	"Misplaced P:": "Misplaced P:",
	"Mix of old and new transposition syntaxes":
			"Sintassi di trasposizione vecchia e nuova allo stesso tempo",
	"multi-measure rest, but no measure!":
			"multi-measure rest, but no measure!",
	"No $1 after %%$2": "Manca $1 dopo %%$2",
	"No </defs> in %%beginsvg sequence":
				"Manca </defs> nella sequenza %%beginsvg",
	"No </style> in %%beginsvg sequence":
				"manca </style> nella sequenza %%beginsvg",
	"No accidental after 'exp'": "Manca l'alterazione dopo 'exp'",
	"No end of chord symbol/annotation": "Accordo di accompagnamento non terminato",
	"No end of decoration": "Decorazione non terminata",
	"No end of grace note sequence": "Sequenza di note di abbellimento non terminata",
	"No end of repeat string": "Stringa di ripetizione non terminata",
	"No end of string in font family": "No end of string in font family",
	"No end of the previous %%multicol": "No end of the previous %%multicol",
	"No end of tuplet": "Gruppo irregolare non terminato",
	"No end of tuplet in this music line":
				"Gruppo irregolare non terminato in questa linea",
	"No end of url in font family": "No end of url in font family",
	"No end of voice overlay": "No end of voice overlay",
	"No function for decoration '$1'": "Funzione inesistente per la decorazione '$1'",
	"No note before '-'": "Nota mancante davanti a '-'",
︙
Changes to err-pt_BR.js.
︙
78
79
80
81
82
83
84
85

86
87
88

89
90
91
92

93
94
95
96
97
98
99
78
79
80
81
82
83
84

85
86
87
88
89
90
91
92

93
94
95
96
97
98
99
100







-
+



+



-
+







	"Cannot have a bar in grace notes":
			"Não pode haver barra de compasso em grupo de notinhas ornamentais",
	"Cannot have a broken rhythm in grace notes":
			"Não pode haver ritmo quebrado em notinhas ornamentais",
	"Cannot have V:* in tune body": "Não pode haver V:* no corpo da música",
	"Cannot read file '$1'": "Arquivo '$1' não pôde ser aberto ou não existe",
	"Decoration ignored": "Decoração ignorada",
	"Decoration without symbol": "Decoração sem símbolo",
	"Decoration(s) without symbol: $1": "Decoração(ões) sem símbolo: $1",
	"Double voice in %%score": "Voz duplicada em %%score",
	"Empty line in tune header - ignored":
				"Linha em branco no cabeçalho da música - ignorada",
	"End of file in tune header": "Fim de arquivo em cabeçalho de música",
	"End of slur without start": "Fim de ligadura sem início",
	"Erroneous end of voice overlay": "Terminação incorreta de superposição de vozes",
	"Error in %%pos": "Erro em %%pos",
	"Error loading the module $1": "Error loading the module $1",
	"Error loading the module $1": "Erro ao carregar o módulo $1",
	"Incorrect 1st value in %%repeat": "Primeiro valor incorreto em %%repeat",
	"Incorrect 2nd value in %%repeat": "Segundo valor incorreto em %%repeat",
	"Invalid 'r' in tuplet": "'r' inválido em quiáltera",
	"Invalid decoration '$1'": "Decoração '$1' inválida",
	"Invalid note duration $1": "Duração de nota $1 inválida",
	"K:P is deprecated": "K:P é obsoleto",
	"Key with double sharps/flats": "Tonalidade com sustenidos/bemóis duplos",
︙
107
108
109
110
111
112
113

114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

130
131
132
133
134
135
136
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139







+
















+







		"Problema de quebra de linha - ajuste maxshrink e/ou breaklimit",
	"Line too much shrunk $1 $2 $3": "Linha muito encolhida $1 $2 $3",
	"Line underfull ($1pt of $2pt)": "Linha muito espaçada ($1pt de $2pt)",
	"Microtone transposition not coded":
				"A transposição de microtons não está codificada",
	"Misplaced '$1' in %%score": "'$1' deslocado em %%score",
	"Misplaced dot": "Ponto fora de lugar",
	"Misplaced P:": "P: fora de lugar",
	"Mix of old and new transposition syntaxes":
				"Mistura de sintaxes de transposição antiga e nova",
	"multi-measure rest, but no measure!":
		"Pausa de múltiplos compassos, porém o compasso não foi definido!",
	"No $1 after %%$2": "Falta $1 após %%$2",
	"No </defs> in %%beginsvg sequence":
				"Falta </defs> em bloco %%beginsvg",
	"No </style> in %%beginsvg sequence":
				"Falta </style> em bloco %%beginsvg",
	"No accidental after 'exp'": "Falta acidente após 'exp'",
	"No end of decoration": "Decoração sem término",
	"No end of grace note sequence": "Grupo de notinhas ornamentais não terminado",
	"No end of chord symbol/annotation": "Acorde cifrado/anotação sem término",
	"No end of repeat string": "Cadeia de repetição não terminada",
	"No end of string in font family":
			"Cadeia de caracteres incompleta em família de fonte",
	"No end of the previous %%multicol": "Falta fechar ('end') o %%multicol anterior",
	"No end of tuplet": "Quiáltera incompleta",
	"No end of tuplet in this music line":
				"Falta terminar quiáltera nesta linha de música",
	"No end of url in font family": "URL incompleta em família de fonte",
	"No end of voice overlay": "Falta fim de divisão de vozes",
	"No function for decoration '$1'": "Falta função para decoração '$1'",
	"No note before '-'": "Falta nota antes de '-'",
︙
Changes to font.js.
1
2
3
4
5
6
7
8






9
10
11
12
13



14
15
16

17
18
19
20
21

22
23
24

25
26
27



28
29
30
31
32









33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

























63
64
65
66
67
68
69
70
71
72
73
74
75
76
77











78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93




















94
95
96
97
98
99
100
101
102
103
104
105
106
107
108










109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130

























131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200







































































201
202
203


204
205
206
207
208
209
210
211
212
213












214
215
216
217
218







219
220
221
222








223
224
225
226
227



228
229
230
231
232
233

234
235
236
237
238
239
240








241
242
243
244
245
246













247
248
249
250
251
252
253
254
255
256
257



258
259
260
261
262
263
264







265
266
267
268
269
270
271
272
273
274























275
276
277
278
279
280
281
282



283
284
285
286
287
288
289
290
291
292
293
294




295
296

297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337











































338
339
340
341
342

343
344
345
346
347
348
349
350
351
352
353
354
355

















356
357
358
359
360
361
362
363
364
365
366
367
368
369
370













371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398




























399
400
1
2






3
4
5
6
7
8
9
10



11
12
13
14
15

16
17
18
19
20

21



22



23
24
25





26
27
28
29
30
31
32
33
34
35
36
37


38
39

























40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64















65
66
67
68
69
70
71
72
73
74
75
















76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95















96
97
98
99
100
101
102
103
104
105






















106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130






































































131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201



202
203










204
205
206
207
208
209
210
211
212
213
214
215





216
217
218
219
220
221
222




223
224
225
226
227
228
229
230





231
232
233






234







235
236
237
238
239
240
241
242






243
244
245
246
247
248
249
250
251
252
253
254
255











256
257
258







259
260
261
262
263
264
265










266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288








289
290
291












292
293
294
295


296









































297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339





340













341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357















358
359
360
361
362
363
364
365
366
367
368
369
370




























371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398

399


-
-
-
-
-
-
+
+
+
+
+
+


-
-
-
+
+
+


-
+




-
+
-
-
-
+
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+



-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
-
-
-
-
-
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-

// abc2svg music font
var musicfont = 'url("data:application/octet-stream;base64,\
AAEAAAAOAIAAAwBgRkZUTY1L868AAFgoAAAAHEdERUYAFQAUAABYDAAAABxPUy8yWMFdCgAAAWgA\
AABWY21hcFz/TQsAAAQIAAADemN2dCAAIgKIAAAHhAAAAARnYXNw//8AAwAAWAQAAAAIZ2x5Zg27\
S/YAAAiwAABGeGhlYWQTZto6AAAA7AAAADZoaGVhCWn/GwAAASQAAAAkaG10eNlp+7kAAAHAAAAC\
SGxvY2HP4L6kAAAHiAAAASZtYXhwANkBFgAAAUgAAAAgbmFtZdbpNH4AAE8oAAADJHBvc3SIfxKM\
AABSTAAABbUAAQAAAAEAAF56eDVfDzz1AAsEAAAAAADRlyIXAAAAAN4tda//OPzvBUsEiAAAAAgA\
AgAAAAAAAAABAAAEiPzvAFwEJf84/XQFSwABAAAAAAAAAAAAAAAAAAAAkgABAAAAkgDlAAUAAAAA\
AAEAAAAOAIAAAwBgRkZUTZHVOuoAAFgMAAAAHEdERUYAFQAUAABX8AAAABxPUy8yWMFdCgAAAWgA\
AABWY21hcHlUuFMAAAQIAAAD5mN2dCAAIgKIAAAH8AAAAARnYXNw//8AAwAAV+gAAAAIZ2x5ZqUq\
QgUAAAkcAABF/GhlYWQVmDJzAAAA7AAAADZoaGVhCWn/GwAAASQAAAAkaG10eNm9+0EAAAHAAAAC\
SGxvY2HHqraAAAAH9AAAASZtYXhwANkBEgAAAUgAAAAgbmFtZeq7sB0AAE8YAAADFXBvc3SIfxKM\
AABSMAAABbUAAQAAAAEAANGbj/xfDzz1AAsEAAAAAADRlyIXAAAAAOBezej/OPzvBUsEiAAAAAgA\
AgAAAAAAAAABAAAEiPzvAFwEJf84/XQFSwABAAAAAAAAAAAAAAAAAAAAkgABAAAAkgDhAAUAAAAA\
AAIAAAABAAEAAABAAC4AAAAAAAEBgAGQAAUACAKZAswAAACPApkCzAAAAesAMwEJAAACAAUDAAAA\
AAAAAAAAARAAAAAAAAAAAAAAAFBmRWQAQAAA7LcDOP84AFwEiAMRAAAAAQAAAAAAAAF2ACIAAAAA\
AVUAAAGQAAACWAAAAFcAAAAjAAAAJQAAACT//wBkAAAEIwAABCUAAAHg/9wDXgB6AwsAAALSAAAC\
v/+6AdYAAAMLAAADDgAAAyf/yADIAAABaP//Aa4AAAEiAAABkAAAAXwAAAGQAAABkAAAAYEAAAGQ\
AAABkAAAAYEAAAGZAAkBmAAJAfQAAAEEABQBBAAKAmsAJAISAAABwgAAAUkAAAFAAAABSv/+ASwA\
AVUAAAGQAAACWAAAAFcAAAAjAAAAJQAAACT//wBkAAAEIwAABCUAAAHg/9wDugAAAwsAAALSAAAC\
v/+6AdYAAAMLAAADDgAAAyf/yADIAAABaAAAAa4AAAEiAAABkAAAAXwAAAGQAAABkAAAAYEAAAGQ\
AAABkAAAAYEAAAGZAAkBmAAJAfQAAAEEABQBBAAKAmsAJAISAAABwgAAAUIAAAFAAAABSv/+ASwA\
AAIwAAABSgAAAUoAAABkAAABQAAAAUAAAAFAAAABQAAAAGQAAAE2AAAA5gAAATYAAAE7AAABOwAA\
ATsAAAE7AAABOwAAATsAAAE7AAABOwAAATsAAAE7AAABDQAAAMgAAAD/AAABCwAUAW4AAACMAAAA\
jAAAAQ0AMgFu//UAqQAAAToAAAFA//0AUAAAAVQAAABkAAABGAAAAlgAAAC2AAABkAAEAIIAAACC\
jAAAAQ0AMgFu//UAqQAAAToAAAFA//0AUAAAAVQAAABkAAABGAAAAlgAAAC2AAABkAAFAIIAAACC\
AAABLAAAASwAAADuAAAA/wAAAUkAAAGPAAAB2AAAAdgAAAIz//ADIP/hAXv/tAG4/9sBFv9+ARP/\
2wDcAAAA6P/kAr//tAIz/7QCv/+0Ayv/2wFf/9sCaf9+AV//fgJp/34BXwAAAf0ABQG1AAABtQAA\
AkQADQJEAA0BGAAAATYAAAEs//8BLAAAAPoAAADIAAABGP84APoAAADIAAAEDQAAAhwADAH0AAAB\
9AAAAfQAAAH0AAAB9AAAAfQAAAB4AAAALQAAAhwAAAD6AAAA+v/oAcIAAAFIAAABQAAAAgoAAAIK\
AAAAZAAAAAAAAwAAAAMAAAAcAAEAAAAAAnQAAwABAAAAHAAEAlgAAACSAIAABgASAAAAIOAA4DDg\
AAAAZAAAAAAAAwAAAAMAAAAcAAEAAAAAAuAAAwABAAAAHAAEAsQAAABgAEAABQAgAAAAIOAA4DDg\
OeBD4EjgUOBc4GLgaeB+4IzgleCk4Kngs+EB4bnhu+Hn4fLh9OH34fnh/OIA4kniZOJr4oPkoOSi\
5KTkqOSs5MDkzuTR5OrlAeUl5S3lMeU55WflaeVt5YLl0OXi5hDmEuYU5hjmJOYw5lDmVekS6RXp\
GOkg6SXpXeoC6qTso+yl7Kfsqey3//8AAAAAACDgAOAw4DjgQ+BF4FDgXOBi4GngeuCA4JTgoOCp\
OeBI4FDgXOBi4GngjOCV4KTgqeCz4QHhu+Hn4gDiSeJk4mvig+Ss5MDk0eTq5QHlMeU55W3lguXQ\
4LPhAeG54bvh5+Hy4fTh9+H54fzh/uJA4mDiauKA5KDkouSk5KjkrOTA5M7k0eTh5QDlIOUp5S/l\
OeVm5WnlbOWC5dDl4uYQ5hLmFOYY5iTmMOZQ5lXpEOkU6RjpIOkl6V3qAuqk7KLspeyn7Knst///\
AAP/5CAFH9Yfzx/GH8Ufvh+zH64fqB+YH5cfkB+GH4IfeR8sHnUedB5JHj8ePh48HjseOR44Hfkd\
5eLmGOYk5jDmUOZV6RjpIOkl6V3qAuqk7Knst///AAAAAAAg4ADgMOA44EPgUOBc4GLgaeB64JTg\
oOCp4LPhAeG54efh8uJA4mDiauKA5KDkwOTO5OHlAOUg5TnlZuWC5dDl4uYQ5iTmMOZQ5lXpEOkg\
6SXpXeoC6qTsouy3//8AA//kIAUf1gAAAAAfvh+zH64fqAAAAAAAAB+CH3kfLAAAHkkAAAAAAAAA\
4x3eHcobrhutG6wbqRumG5MbhhuEG3UbYBtCGz8bPhs3GwsbChsIGvQapxqWGmkaaBpnGmQaWRpO\
Gi8aKxdxF3AXbhdnF2MXLBaIFecT6hPpE+gT5xPaAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAQYAAAMAAAAAAAAAAQIAAAACAAAAAAAAAAAAAAAAAAAAAQAABAAAAAAAAAAAAAAA\
AAAAAAAbkwAAAAAAAAAAGzcAABr0GqcalgAAGlkaThovGisAABdnF2MXLBaIFecAABPaAAEAAAAA\
AAAAAABYAFoAAAAAAAAAAABcAIAAggAAAAAAAACEAAAAhgCiALQAvAC+AMQAAADaAOAA8gD0AAAB\
FAAAAAAAAAEcAAAAAAAAAAABJAAAAAAAAAAAAAABKgAAAAAABwAIAAkAAAAKAAsADAANABIAEwAU\
ABUAFgAAABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgAuAAAALwAxAAAA\
MgAAAAAAMwAAADQAAAAAADUAAAA2ADcAOAA5ADoAOwA8AD0APgA/AEAAQQBCAEMARABFAEYARwBI\
AEkASgBLAEwATQBOAAAATwAAAFAAAAAAAAAAUQAAAAAAAABSAFQAAAAAAFUAVgBXAFgAWQBaAFsA\
XABdAF4AXwBgAGEAYgBjAGQAZQBmAGcAAAAAAAAAaABpAGoAawBsAAAAbQBuAG8AcQByAAAAcwAA\
AAAAdAB1AHkAAAB6AAAAewAAAAAAAAB8AIEAggCDAAAAhACFAAAAAACGAIwAjQAAAI4AAACPAAAA\
kAAAAQYAAAMAAAAAAAAAAQIAAAACAAAAAAAAAAAAAAAAAAAAAQAABAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiAogAAAAqACoAKgA2\
AD4AbgB6AIYAkgCwASQBgAHwAjICvgNQA7ADxARgBPIFSgWKBiQGRgZaBqwG/AccB2IHogfcCCgI\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiAogAAAAqACoAKgA2AD4AbgB6\
AIYAkgCwASQBgAHwAjQCwANSA7IDxgRkBPYFTgWOBhAGMgZGBpgG6AcIB04HjgfICBQIVAiaCPQJ\
aAiuCQgJHAlCCWgJmgm2CdgKBAoaCjQKagp4CoQKkAqiCr4K4AruCwILFAskC3ALgAuaC7QL7Awk\
DHIMvg0kDYYOBA58DqIOvA7sDxYPbg+ID6IPyBAiEEIQgBCoELwQyBDWEOYRDhE0EWwReBGEEZAR\
nBG+EeQSGhJoEsgTPBNiE5AT5BRYFKwU7BUwFYYWpBd+GBQYxhmOGiYa/hwYHQwdTh2SHdwd9h4a\
Hi4eQh5yHoIelB6wHsYe6h8aH/ggtCDcIPohLCFqIZwh3iHwIf4iGiI0IloifCKqIsQi7iMqIzwA\
AAACACIAAAEyAqoAAwAHAC6xAQAvPLIHBADtMrEGBdw8sgMCAO0yALEDAC88sgUEAO0ysgcGAfw8\
sgECAO0yMxEhESczESMiARDuzMwCqv1WIgJmAAABAAAAAAGRAZAAAwAAMREhEQGRAZD+cAABAAAA\
AAAAAAAAAAAAMQAAAQAAAAAAVwQDACAAABE1NjU0JyY1NDcGFRQXFhUUBxYVFAcGFRQXJjU0NzY1\
NDUjElc/FSVNTSUVP1cSIwIDAhhDNmA5NGY6MksiOWFNYRgYZkxgOSVKMjpmNDlgNkgAAQAAAAAA\
IwPoAAMAABEzESMjIwPo/BgAAQAAAfQAJQPoAAMAABEzESMlJQPo/gwAAf//A2QAJARgAAMAABEz\
ByMkASQEYPwAAgAAAUAAZAKeAAcADwAAEiImNDYyFhQCIiY0NjIWFEcqHR0qHR0qHR0qHQI6HSod\
HSr+6R0qHR0qAAAABQAAAAAEJAGuAC8ANwA/AEcAUwAAITUzHgEzMjY1NCcuBDU0NjMyFhc3Mxcj\
LgEjIgYVFB4DFx4BFRQGIyInByAiJjQ2MhYUBCImNDYyFhQBETMyNjQmIwM1MxEjNTMyFhUUIwJO\
HhVPMik7lBkaKhYRWT0kJxkeHgceD0owHzkQIhkyCE5NW09FLiMBmyodHSod/eoqHR0qHf6JKDxG\
RjzcRkbccYn6oDxLICEtKAcIFBQjFUNNCw4ZmzpIKBsPFw8JCwIVNzM6TiAgHSodHSodHSodHSoB\
af6YYaZh/noeAWgeZ2vSAAUAAAAABCQBrgAaACIAKgAyAD4AACEiJjU0NjMyFhc3MxcHJiMiBhQW\
MzI2NxcOATIiJjQ2MhYUBCImNDYyFhQBETMyNjQmIwM1MxEjNTMyFhUUIwMCZ3WCWiUpGx4eCCEk\
Xjg2Njg2TREjFFmxKh0dKh396iodHSod/okoPEZGPNxGRtxxifprZ2V3DBIepgSMbZhtST4KSlEd\
Kh0dKh0dKh0dKgFp/phhpmH+eh4BaB5na9IAAAAD/9wAAgHeArMABwAPAE0AAAAiJjQ2MhYUBCIm\
NDYyFhQXNDYzMhYVFAcWMzI2NTQvAQMnEy4BNTQ+ATc2MzIWFRQGIyImNTQ3JiMiBhUUHwETFwMe\
ARUUDgEHBiMiJgGeIBgYIBj+fiAYGCAYWxsUEx4sFykmNiZ7zyvRWkgcExQmMzA4GxQTHiwXKSY2\
JnrUK9VaSBwTFCYzMDgBUhggGBggVBggGBgg0xIcGhEdDhctJi0mZf7eIAElR3E4Fi0RERM4IRIc\
GhEdDhctJi0mZQEmH/7XR3I4Fi0RERM4AAUAev80A14CVAAXABsAHwAjACcAAAEzFR4BFzMVIw4B\
BxUjNS4BJyM1Mz4BNxEjFhc3FTY3JzMmJwc1BgcB2ChVeAeKigd4VShVeAeKigd4VXAFayhrBXBw\
BWsoawUCVIkIi2AoYIsIiYkIi2AoYokI/uW6DsjIDrooug7IyQ67AAAAAAQAAP1vAqcEiAALAEQA\
TgBjAAABBhUUFz4BNTQnDgETFxUUBiMiJjU0NjMyFhQGBxYzMjY9AScGIyImNTQ3PgY/ASY1NDY3\
CAkuCVQJhgmiCcQJ7AoCChwKUgpgCmwKeAqKCqYKyArWCuoK/AsMC1gLaAuCC5wL1AwMDFoMpg0M\
DW4N7A5kDooOpA7UDv4PVg9wD4oPsBAKECoQaBCQEKQQsBC+EM4Q9hEeEVYRYhFuEXoRhhGoEc4S\
BBJSErITJhNME3oTzhRCFJYU1hUaFXAWihdiF/gYqhlsGf4a0BvkHNAdEh1WHaAduh3eHfIeBh42\
HkYeWB50Hooerh7eH7ogdiCeILwg7iEsIV4hoCGyIcAh3CH2IhwiPiJsIoYisCLsIv4AAAACACIA\
AAEyAqoAAwAHAC6xAQAvPLIHBADtMrEGBdw8sgMCAO0yALEDAC88sgUEAO0ysgcGAfw8sgECAO0y\
MxEhESczESMiARDuzMwCqv1WIgJmAAABAAAAAAGRAZAAAwAAMREhEQGRAZD+cAABAAAAAAAAAAAA\
AAAAMQAAAQAAAAAAVwQDACAAABE1NjU0JyY1NDcGFRQXFhUUBxYVFAcGFRQXJjU0NzY1NDUjElc/\
FSVNTSUVP1cSIwIDAhhDNmA5NGY6MksiOWFNYRgYZkxgOSVKMjpmNDlgNkgAAQAAAAAAIwPoAAMA\
ABEzESMjIwPo/BgAAQAAAfQAJQPoAAMAABEzESMlJQPo/gwAAf//A2QAJARgAAMAABEzByMkASQE\
YPwAAgAAAUAAZAKeAAcADwAAEiImNDYyFhQCIiY0NjIWFEcqHR0qHR0qHR0qHQI6HSodHSr+6R0q\
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\
NmJ3MBsDVh4iOSQlezNGJiYAAAAAAgAA/mMCQgGaAGMAZwAAATI2NTQnJiMiBw4BByYnJicRIxEz\
ETY3NjceAxcWMzI2NTQnJiMiBxYXFBYVFAYrASY1NDc2NzYzMhcWFxUUBgcGIyInBxc2MzIWFxYd\
AQYHBiMiJjU0NzMyFhUUBhUGBxYBMxEjAX4yOwoVOjgwAgwEHRMYJRYWJRgTHQQRChMMIB0nMQ4c\
QyUnKAoCKhoENgQVRCMYSUYtBkg6GCUrMRsbNCg1UhggBi1GST1bNgQaKgIMJiv+o2Ji/oBgOyQk\
VzsFHQtSHCIZ/moDM/50GSIcUggiEhcIFmI1KyhOFQ0gAgsDGCIUKBAJNRULQCtBDj5aFgoSPDsT\
MiMuNQ9BK0A/MCgUIxgDCwMfDRYDGPzNAAAAAAP/yP4eAjYAzAAmAC8AOwAANzQ2MzIXFhUUBw4B\
BzY3Njc2NTQnLgEjIgYHPgEzMhYVFAcGIyImBSImNDYyFhQGJyImNTQ2MzIWFRQGD3BSgjwjeEPG\
acBeRx4JLRgtIDBSChIWFiU5IBklLDkCAhIXFCIYFRUSFhUSERYVIU1eVzNaxmw7VwYzZEqMLylm\
MxoUQjYXDTwmKBoYU3UXJBYXIhjCGBQRFBUQExkAAAAAAwAAAAAAyADwAAkAFQArAAA3BhUUFjMy\
NjU0JyIGFRQeARc2NTQmByImNTQ2Ny4BNTQ2MzIWFRQHFhUUBlYsHhARFAIOEwoJECUUNCU1IyIR\
DCgeKTE3IzR0EB4UHhsRF4URDgoQCAwLHQ4X3CgeFxoLDxMQGiIfHSUOHB8gJgACAAD//wFnAQMA\
MABiAAAXIjU0MzIVFAYVFDMyNjU0IyIHBiMiNTQ3NjM2MzIWFRQHBgcOAQcGFjc2MzIWFRQGJyI0\
OwEyNzI0MzY3PgE1NiMiBwYnJjc+ATc2OwIyFxYzMjc2BwYHBhUUMzIVFCsC1D4YGxIdFyweChQW\
BwIBAgQJDA4hIkX4BQUEBgkVBA8aCA4KBwwNCg8HGw8TDAQHGgcEBgwIA0QNAhUMDAEBAgEBAQEC\
AQEBAQECAQEBAQEBAQEBAgEBAQEBAQEBAQEBAQEBAQECAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEJ\
EwE3IRsIFAcOQiMcGQ8WVAsBBxAHCg8BBgQICAgDAyUfKTgBCQkMI0UVCQ4GBRMJIxQXCg0CBAYI\
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\
EhITHgUpPkhAFglETVYVASk+SEEWCURNVhUBKT5IQRYJRE1WFQEpPkhB/qgCrBs5Mzc6PUglLCsn\
LSwrJy0sKykrNjkZITdkRTQYqyRUQ10pBAwEN2VFMxmrJFRDXSkDDgM3ZUUzGaskVENdKQQMBDdl\
RTMZAAQAAP6OATwCoAAfACwAOQBGAAAZATMyPgI1NCcWFRQHFhUUBxYVFAcWFRQOBQc1Mj4CNTQm\
NQ4DJzI+AjU0JjUOAycyPgI1NCY1DgMeHFVXPQUeExISEhISHC44OzMnBh1VVz0BFVZNRAkdVVc9\
ARVWTUQJHVVXPQEVVk1E/o4CrClId0QhGTk2KykrLC0nKywtJyssJUg9OjczORuqKUl4RAMNBCld\
Q1SGKUl4RAMNBCldQ1SGKUl4RAMNBCldQ1QAAAAFAAD9VQE8AhIAJAAyAEAATgBcAAAZATMeBhUU\
BxYVFAcWFRQHFhUUBxYVFAc2NTQuAyM1HgMXNDY1NC4DJx4DFzQ2NTQuAyceAxc0NjU0LgMnHgMX\
NDY1NC4DHgYnMzs4LhwSEhISEhISEx4FKT5IQBYJRE1WFQEpPkhBFglETVYVASk+SEEWCURNVhUB\
KT5IQRYJRE1WFQEpPkhB/rsDVxs5Mzc6PUglLCsnLSwrJy0sKyctLCspKzY5GSE3ZEU0GKskVENd\
KQMNBDdlRTMZqyRUQ10pBAwEN2VFMxmrJFRDXSkDDgM3ZUUzGaskVENdKQQMBDdlRTMZAAAFAAD9\
vAE8AnkAIwAwAD0ASgBXAAAZATMyPgI1NCcWFRQHFhUUBxYVFAcWFRQHFhUUDgUHNTI+AjU0JjUO\
AycyPgI1NCY1DgMnMj4CNTQmNQ4DJzI+AjU0JjUOAx4cVVc9BR4TEhISEhISEhwuODszJwYdVVc9\
ARVWTUQJHVVXPQEVVk1ECR1VVz0BFVZNRAkdVVc9ARVWTUT9vANXKUh3RCEZOTYrKSssLScrLC0n\
KywtJyssJUg9OjczORuqKUl4RAMNBCldQ1SGKUl4RAMNBCldQ1SGKUl4RAMNBCldQ1SGKUl4RAMN\
BCldQ1QAAAACAAD/ZADhAbAACgAWAAA3IgYdATY3NjU0JjcyFhUUBwYjETMRNmcUKyImKx0HIzlL\
UkQoI3omE7kPODsvGyYmMiNJTFICTP68NAAAAgAA/oYAxQF6AAMADAAAFzc1BxEVNxEjNQcRNxyQ\
kKkZrAFlLZYtAUnoNP3A4jMCQwEAAAIAAP6YAP8BaAADAB8AADcVNzUDIzUHNTc1BzU3NTMVNzUz\
FTcVBxU3FQcVIzUHU1paHjU1NTUeWh01NTU1HVpGpxun/jejD1wPpw9aD6ifHKujD1wPpw9aD6if\
HAAAAAEAFP+EAQsAegAeAAAXNSYnBzAVIzUzNycwIzUzFRYXNzA1MxUjBgcXMDMVwygMM0g5MzM5\
SCESNEg5IRM0OXw7Jg0zO0oyMkg5IhEzOUciETRIAAQAAP9qAWwBsAAOABwAKwA6AAA3DgEdATI3\
Njc2NTQnJiM3MhYVFAcGBwYjETMRNhcOAR0BMjc2NzY1NCcmIzcyFhUUBwYHDgEjETMRNk4RHg4e\
HwwEChARGR0rCRgrNS8fGdERHRAeHQsGCxAPFh8qCxkoFjcWHht9AR4QxikrNA0ZHhQVJjkhEiA5\
NEACRv7BMiYBHRHGKS8wExMcFhUmNiQWHD4vGyUCRv7BMgAAAQAA/wYAjAD6AA4AADcVBhUUFxUu\
AzQ+AoxQUBolMhsbMiX6FEOjpkAUDx86WnBaOh8AAAEAAP8GAIwA+gAOAAA1HgMUDgIHNTY1NCca\
JTIbGzIlGlBQ+g8fOlpwWjofDxRApqNDAAACADL/ZAENAbAACgAWAAA3IgYVFBcWFzU0JicyFxEz\
ESInJjU0NqsXIC4uGiozOiMjOlJPOXomGzBFQgPLEh4mNAFE/bRSUEUjMgAABP/1/2oBbAGwAA4A\
HQAsADsAADcjIgcGFRQXFhcWMzU0JicyFxEzESImJyYnJjU0NhcOAR0BMjc2NzY1NCcmIzcyFhUU\
BwYHDgEjETMRNlcBERAKBAwfHg4eKzAZHxY3FysYCSvpER0QHh0LBgsQDxYfKgsZKBY3Fh4bfRUU\
HhkNNCspxhAeJzIBP/26JRs0OSASITkmAR0RxikvMBMTHBYVJjYkFhw+LxslAkb+wTIAAAAAAQAA\
/sAAqQFAABMAABMzFTcVBxU3FQcVIzUHNTc1BzU3RB5HR0dHHkREREQBQKIOXA5/DloPqKIOXA5/\
DloPAAMAAP6YAToBaAAjACcAKwAANzUzFTcVBxU3FQcVIzUHFSM1DwEjNQc1NzUHNTc1MxU3NTMV\
AzUHFTcVNzXpHjMzMzMePR48AR4zMzMzHj0eHj1bPcCong9cD58PWg+1qhKspBCong9cD58PWg+1\
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\
VENdKQMNBDdlRTMZqyRUQ10pBAwEN2VFMxmrJFRDXSkDDgM3ZUUzGaskVENdKQQMBDdlRTMZAAAF\
AAD9vAE8AnkAIwAwAD0ASgBXAAAZATMyPgI1NCcWFRQHFhUUBxYVFAcWFRQHFhUUDgUHNTI+AjU0\
JjUOAycyPgI1NCY1DgMnMj4CNTQmNQ4DJzI+AjU0JjUOAx4cVVc9BR4TEhISEhISEhwuODszJwYd\
VVc9ARVWTUQJHVVXPQEVVk1ECR1VVz0BFVZNRAkdVVc9ARVWTUT9vANXKUh3RCEZOTYrKSssLScr\
LC0nKywtJyssJUg9OjczORuqKUl4RAMNBCldQ1SGKUl4RAMNBCldQ1SGKUl4RAMNBCldQ1SGKUl4\
RAMNBCldQ1QAAAACAAD/ZADhAbAACgAWAAA3IgYdATY3NjU0JjcyFhUUBwYjETMRNmcUKyImKx0H\
IzlLUkQoI3omE7kPODsvGyYmMiNJTFICTP68NAAAAgAA/oYAxQF6AAMADAAAFzc1BxEVNxEjNQcR\
NxyQkKkZrAFlLZYtAUnoNP3A4jMCQwEAAAIAAP6YAP8BaAADAB8AADcVNzUDIzUHNTc1BzU3NTMV\
NzUzFTcVBxU3FQcVIzUHU1paHjU1NTUeWh01NTU1HVpGpxun/jejD1wPpw9aD6ifHKujD1wPpw9a\
D6ifHAAAAAEAFP+EAQsAegAeAAAXNSYnBzAVIzUzNycwIzUzFRYXNzA1MxUjBgcXMDMVwygMM0g5\
MzM5SCESNEg5IRM0OXw7Jg0zO0oyMkg5IhEzOUciETRIAAQAAP9qAWwBsAAOABwAKwA6AAA3DgEd\
ATI3Njc2NTQnJiM3MhYVFAcGBwYjETMRNhcOAR0BMjc2NzY1NCcmIzcyFhUUBwYHDgEjETMRNk4R\
Hg4eHwwEChARGR0rCRgrNS8fGdERHRAeHQsGCxAPFh8qCxkoFjcWHht9AR4QxikrNA0ZHhQVJjkh\
EiA5NEACRv7BMiYBHRHGKS8wExMcFhUmNiQWHD4vGyUCRv7BMgAAAQAA/wYAjAD6AA4AADcVBhUU\
FxUuAzQ+AoxQUBolMhsbMiX6FEOjpkAUDx86WnBaOh8AAAEAAP8GAIwA+gAOAAA1HgMUDgIHNTY1\
NCcaJTIbGzIlGlBQ+g8fOlpwWjofDxRApqNDAAACADL/ZAENAbAACgAWAAA3IgYVFBcWFzU0Jicy\
FxEzESInJjU0NqsXIC4uGiozOiMjOlJPOXomGzBFQgPLEh4mNAFE/bRSUEUjMgAABP/1/2oBbAGw\
AA4AHQAsADsAADcjIgcGFRQXFhcWMzU0JicyFxEzESImJyYnJjU0NhcOAR0BMjc2NzY1NCcmIzcy\
FhUUBwYHDgEjETMRNlcBERAKBAwfHg4eKzAZHxY3FysYCSvpER0QHh0LBgsQDxYfKgsZKBY3Fh4b\
fRUUHhkNNCspxhAeJzIBP/26JRs0OSASITkmAR0RxikvMBMTHBYVJjYkFhw+LxslAkb+wTIAAAAA\
AQAA/sAAqQFAABMAABMzFTcVBxU3FQcVIzUHNTc1BzU3RB5HR0dHHkREREQBQKIOXA5/DloPqKIO\
XA5/DloPAAMAAP6YAToBaAAjACcAKwAANzUzFTcVBxU3FQcVIzUHFSM1DwEjNQc1NzUHNTc1MxU3\
NTMVAzUHFTcVNzXpHjMzMzMePR48AR4zMzMzHj0eHj1bPcCong9cD58PWg+1qhKspBCong9cD58P\
Wg+1qhKspP79nhGfuJ4RnwAB//0AAAE/APQAGAAANwYjIiY1ND8BNi8BJjU0NjMyMRcFFhUUBxIC\
AwcJBs8ODs0ICwcBAgEfDg4BARAICgNJBwZPAwsKEgFrBg4NBQAAAAEAAAAAAFAAUAAJAAA1NDYy\
FhQGIyImFyIXFxEQGCgRFxciFxgAAAABAAAAAAFUADIAAwAAMTUhFQFUMjIAAAABAAAAAABkARgA\
AwAAMwMzAygoZCgBGP7oAAAAAQAAAAABGAE1AAUAADEbASMnB4yMQVhaATX+y8bGAAACAAAAAAJY\
AUoADgAZAAAxNDYzMh4CFSMuASIGByEiJjQ2MzIWFRQGs3k5a1UzDwui4KILARwXJSUXGSMjmLIs\
UYBNboaGbiQwJCQYGSMAAAEAAAAAALYBLQAYAAATMhYXFhUUBw4BIzAnJjU0NjU0Iy4BNTQ2Vhsb\
EBoyGUQQBgFHFBsoLQEtDBEdMD08HS0DAQIIaxMPASYcHjEAAAAAAgAFAAABjgH1ABEAIwAANxM2\
MzIXFhUUBwMGIyInJjU0JxM2MzIXFhUUBwMGIyInJjU0mM0LCgYDCwXMCQsEBguLzQoLBgMLBcwI\
DAQGCyMBwBICBQoGDP4/EQMGDAcHAcASAgUKBgz+PxEDBgwHAAEAAP8GAIIA+gADAAA1MxEjgoL6\
/gwAAAEAAAAAAIIA+gADAAA1MxUjgoL6+gAAAAEAAP+DASwAAAADAAAxIRUhASz+1H0AAAEAAAAA\
ASwAfQADAAA1IRUhASz+1H19AAEAAP5+AOsBhwATAAATFwcXJiMiBhUUFyY1NDYzMhcnNym9Z2wy\
IiKHZAGH5dnPLiQdNTRLTSMtFby0AAABAAD/DQEAAMAAFgAANw4CIyImNTQ2MhYVFAcyNjc2MhcD\
J6sDGRoTKzcmOCkXIjMhAhUDljA8AQcEKSgfIB4ZHRshLAIC/m8QAAAAAQAA/gwBSADAACQAABcG\
IyImNTQ2MzIWFRQHMj8BBiMiJjU0NjMyFhUUBzI3NjIXAyerKCErNycbHCkXQQs8NhgrNycbHCkX\
NB8mOHg0JSIih2QBh+XZzy4kHTU0S00jLRW8tAAAAQAA/w0BAADAABYAADcOAiMiJjU0NjIWFRQH\
MjY3NjIXAyerAxkaEys3JjgpFyIzIQIVA5YwPAEHBCkoHyAeGR0bISwCAv5vEAAAAAEAAP4MAUgA\
SC4CFQPFLcQMKCggIB8ZHRsiygwpKB8gHhkdG00CAv1uDAAAAQAA/gwBjwHAADYAADcGIyImNTQ2\
MzIWFRQHMj8BIg4BIyImNTQ2MzIWFRQHMjc2MhcBJxMGIyImNTQ2MzIWFRQHMjf2KB8rNycbHCkX\
Pws6ASAcEys3JxscKRdILgEWA/70LVUoISs3JxscKRdBCzwMKCggIB8ZHRsiywkEKSgfIB4ZHRtN\
AgL8bgwBJAwoKCAgHxkdGyIAAAAAAQAA/QwB2gHAAEUAABMGIyImNTQ2MzIWFRQHMj8BBiMiJjU0\
NjMyFhUUBzI/AQYjIiY1NDYzMhYVFAcyPwEiDgEjIiY1NDYyFhUUBzI3NjIXASerKCErNycbHCkX\
QQs6KCErNycbHCkXQQs6KB8rNycbHCkXPws6ASAcEys3JjgpF0guAhUD/qkt/jwMKCggIB8ZHRsi\
ygwoKCAgHxkdGyLKDCgoICAfGR0bIssJBCkoHyAeGR0bTQIC+24MAAAAAQAA/QwCGQKuAFYAACUG\
IyImNTQ2MzIWFRQHMj8BBiMiJjU0NjMyFhUUBzI/ASIOASMiJjU0NjMyFhUUBzI3NjIXAScTBiMi\
JjU0NjMyFhUUBzI/AQYjIiY1NDYzMhYVFAcyNwE/KCErNycbHCkXQQs2KB8rNycbHCkXPws0ASAc\
Eys3JxscKRdILgEWA/5qLVUoISs3JxscKRdBCzooISs3JxscKRdBCzQMKCggIB8ZHRsixAwoKCAg\
wAAkAAAXBiMiJjU0NjMyFhUUBzI/AQYjIiY1NDYzMhYVFAcyNzYyFwMnqyghKzcnGxwpF0ELPDYY\
KzcnGxwpF0guAhUDxS3EDCgoICAfGR0bIsoMKSgfIB4ZHRtNAgL9bgwAAAEAAP4MAY8BwAA2AAA3\
BiMiJjU0NjMyFhUUBzI/ASIOASMiJjU0NjMyFhUUBzI3NjIXAScTBiMiJjU0NjMyFhUUBzI39igf\
KzcnGxwpFz8LOgEgHBMrNycbHCkXSC4BFgP+9C1VKCErNycbHCkXQQs8DCgoICAfGR0bIssJBCko\
HyAeGR0bTQIC/G4MASQMKCggIB8ZHRsiAAAAAAEAAP0MAdoBwABFAAATBiMiJjU0NjMyFhUUBzI/\
AQYjIiY1NDYzMhYVFAcyPwEGIyImNTQ2MzIWFRQHMj8BIg4BIyImNTQ2MhYVFAcyNzYyFwEnqygh\
KzcnGxwpF0ELOighKzcnGxwpF0ELOigfKzcnGxwpFz8LOgEgHBMrNyY4KRdILgIVA/6pLf48DCgo\
ICAfGR0bIsoMKCggIB8ZHRsiygwoKCAgHxkdGyLLCQQpKB8gHhkdG00CAvtuDAAAAAEAAP0MAhkC\
rgBWAAAlBiMiJjU0NjMyFhUUBzI/AQYjIiY1NDYzMhYVFAcyPwEiDgEjIiY1NDYzMhYVFAcyNzYy\
FwEnEwYjIiY1NDYzMhYVFAcyPwEGIyImNTQ2MzIWFRQHMjcBPyghKzcnGxwpF0ELNigfKzcnGxwp\
Fz8LNAEgHBMrNycbHCkXSC4BFgP+ai1VKCErNycbHCkXQQs6KCErNycbHCkXQQs0DCgoICAfGR0b\
IsQMKCggIB8ZHRsixwkEKSgfIB4ZHRtNAgL6gAwBJAwoKCAgHxkdGyLIDCgoICAfGR0bIgAD//D/\
HxkdGyLHCQQpKB8gHhkdG00CAvqADAEkDCgoICAfGR0bIsgMKCggIB8ZHRsiAAP/8P8GAiYA+gAH\
AA8AEwAANiImNDYyFhQAIiY0NjIWFAUBMwFQMiMjMiMBiDIjIzIj/dIBuH7+R0sjMiMjMv7PIzIj\
IzJaAfT+DAAE/+H/BgMHAPoABwAPABMAFwAANiImNDYyFhQAIiY0NjIWFAUBMwEzATMBQTIjIzIj\
AncyIyMyI/zjAbh7/kd5Abh7/kdLIzIjIzL+zyMyIyMyWgH0/gwB9P4MAAL/tP+IAXwBGAARADsA\
ADcWMzI2NzY1NCcmIyIGBwYVFBciJwczMhQrASI0OwETNjU0IyIOAwcGJjc2NzYzMhYXPgEzMhYV\
BgImAPoABwAPABMAADYiJjQ2MhYUACImNDYyFhQFATMBUDIjIzIjAYgyIyMyI/3SAbh+/kdLIzIj\
IzL+zyMyIyMyWgH0/gwABP/h/wYDBwD6AAcADwATABcAADYiJjQ2MhYUACImNDYyFhQFATMBMwEz\
AUEyIyMyIwJ3MiMjMiP84wG4e/5HeQG4e/5HSyMyIyMy/s8jMiMjMloB9P4MAfT+DAAC/7T/iAF8\
ARgAEQA7AAA3FjMyNjc2NTQnJiMiBgcGFRQXIicHMzIUKwEiNDsBEzY1NCMiDgMHBiY3Njc2MzIW\
Fz4BMzIWFRQGxQIFEjIODQ8CBBI1Cw8nKhktNAsL4QsLS2gGCwgMDwsZCgUbBTEPFyUjJAcdJiMe\
LVkoATUkICYlBQEzHCckKS4geh4eAR0SDA8HFBIsEAgPCVgQGRMaHg80MElrAAAB/9v/9gG+ARgA\
UwAANwYHBisBIj8BNiYjIgYHBiY3PgMzMhc2MzIXPgEzMhYVFA8BBhUUMzI3PgU3NhYHDgIjIiY1\
FAbFAgUSMg4NDwIEEjULDycqGS00CwvhCwtLaAYLCAwPCxkKBRsFMQ8XJSMkBx0mIx4tWSgBNSQg\
JiUFATMcJyQpLiB6Hh4BHRIMDwcUEiwQCA8JWBAZExoeDzQwSWsAAAH/2//2Ab4BGABTAAA3BgcG\
KwEiPwE2JiMiBgcGJjc+AzMyFzYzMhc+ATMyFhUUDwEGFRQzMjc+BTc2FgcOAiMiJjU0PwE2NTQj\
Ig8BBgcnBiY/ATY1NCMiB1AHCAQENQ0NQgQGCA0WJAUVBBQQIh8SNwskJC0JCykTGSQFLwQIAQQF\
ND8BNjU0IyIPAQYHJwYmPwE2NTQjIgdQBwgEBDUNDUIEBggNFiQFFQQUECIfEjcLJCQtCQspExkk\
BS8ECAEEBQsHDAMNAQYVBhIXLR8VGQU0ARUbCEEIDyYNCARDARUbCBURAwEapw0PGjkIDAklGjAS\
KCgoEBgjGgsPfQsJDgIDCQYPBRIBCQ0LHx8aFhMNDYgCBA4UqxYBAQEPCKsCBA4UAAAAAf9+/2AB\
XgG4AEEAAAciJjU0NjMyFhUUBwYVFDMyPgc3IyI1NDsBPgEzMhYVFAYjIiY1NDc2NCMiDgcHMzIU\
KwEOATIgMBcTEhcSChkLEA8LDQoODRQKNRMRQRRpNCAwFxMSFxIKGQcMCgcIBQYDBgE2ExM/IXag\
JiAaIhQPDgsHDQ4GERMlJDw3VScVE0tfJiAaIhQPDgsGHAULChQNGg0eBijFwQAAAf/bAAABEwET\
ACoAADc+ASYjIgYPAQYHBisBIj8BNiYjIgYHBiY3PgEzMhYXNjMyFhUUIyImNTTQBQMDBRQkCT8H\
CAQENQ0NQgQGCA4XIgUVBCE4IhsdBB8kGiArDxvnAwcELBicEQMBGqMNDxo1CAwJPEAaDSceGTcW\
CwcMAw0BBhUGEhctHxUZBTQBFRsIQQgPJg0IBEMBFRsIFREDARqnDQ8aOQgMCSUaMBIoKCgQGCMa\
Cw99CwkOAgMJBg8FEgEJDQsfHxoWEw0NiAIEDhSrFgEBAQ8IqwIEDhQAAAAB/37/YAFeAbgAQQAA\
ByImNTQ2MzIWFRQHBhUUMzI+BzcjIjU0OwE+ATMyFhUUBiMiJjU0NzY0IyIOBwczMhQrAQ4BMiAw\
FxMSFxIKGQsQDwsNCg4NFAo1ExFBFGk0IDAXExIXEgoZBwwKBwgFBgMGATYTEz8hdqAmIBoiFA8O\
CwcNDgYREyUkPDdVJxUTS18mIBoiFA8OCwYcBQsKFA0aDR4GKMXBAAAB/9sAAAETARMAKgAANz4B\
DRQAAAABAAAAAADcARgAMQAAMyImNTQ2MhYVFAcWMzI2NTQuAicmNTQ2MzIWFRQGIyImNTQ3JiMi\
BhUUHgIXFhUUUB4yFRoXEAwTFiEJCxgGOjctIjYWEA0WBw8RDxkREh4FMCsbEBYQDBIQEBYSCw8H\
DQQlMCMoJBgQGBQOAw4TEQ0JEwwRAyArVQAAAf/k//wA5wEPADwAACcGLgE/ASIGIyImDgEHBicm\
JiMiBg8BBgcGKwEiPwE2JiMiBgcGJjc+ATMyFhc2MzIWFRQjIiY1NNAFAwMFFCQJPwcIBAQ1DQ1C\
BAYIDhciBRUEITgiGx0EHyQaICsPG+cDBwQsGJwRAwEaow0PGjUIDAk8QBoNJx4ZNxYNFAAAAAEA\
AAAAANwBGAAxAAAzIiY1NDYyFhUUBxYzMjY1NC4CJyY1NDYzMhYVFAYjIiY1NDcmIyIGFRQeAhcW\
FRRQHjIVGhcQDBMWIQkLGAY6Ny0iNhYQDRYHDxEPGRESHgUwKxsQFhAMEhAQFhILDwcNBCUwIygk\
GBAYFA4DDhMRDQkTDBEDICtVAAAB/+T//ADnAQ8APAAAJwYuAT8BIgYjIiYOAQcGJyY3PgE3HgEz\
MjYzMhcWFA8BBhUUMzI2MzIXFjc2JyI1NDYzMhUUBisBLgEjIgoGCwEFsAUfDAMUDB8FDwQDCAwL\
Nz4BNx4BMzI2MzIXFhQPAQYVFDMyNjMyFxY3NiciNTQ2MzIVFAYrAS4BIyIKBgsBBbAFHwwDFAwf\
AQ4vFSIrBAgFCweeAgIBDQYaIw0IBQckEg0mKB4dGCUIDgMECA0GwQYGAjIFDQsJEh4wAgEGCwEB\
EQenBgIDAxoKDg0DHQ4VNx4vAxgABf+0/4gFSwEYABEAIwC2AMgA2gAAJRYzMjY3NjU0JyYjIgYH\
BhUUBRYzMjY3NjU0JyYjIgYHBhUUFyInBzMyFCsBIjQ7ARM2NTQjIg4DBwYmNzY3NjMyFhc+ATMy\
Fz4BMzIWFz4BMzIXPgEzMhYXPgEzMhc+ATMyFhc+ATMyFhUUBiMiJwczMhQrASI0OwETNjU0IyIG\
BxUUBiMiJwczMhQrASI0OwETNjU0IyIGBxUUBiMiJwczMhQrASI0OwETNjU0IyIGBxUUBiUWMzI2\
NzY1NCcmIyIGBwYVFAUWMzI2NzY1NCcmIyIGBwYVFAIKAwQSMg4NDwMDEzQLD/7LAwQSMg4NDwMD\
EzQLDxMWGS00CwvhCwtLaAYLCAwPCxkKBRsFMQ8XJSMkBx0mIy8TEiIbIyQHHSYjLxMSIhsjJAcd\
BQ8EAwgMCwEOLxUiKwQIBQsHngICAQ0GGiMNCAUHJBINJigeHRglCA4DBAgNBsEGBgIyBQ0LCRIe\
MAIBBgsBAREHpwYCAwMaCg4NAx0OFTceLwMYAAX/tP+IBUsBGAAQACIAtQDGANcAACUWMzI2NzY0\
JyYjIgYHBhUUBRYzMjY3NjU0JyYjIgYHBhUUFyInBzMyFCsBIjQ7ARM2NTQjIg4DBwYmNzY3NjMy\
Fhc+ATMyFz4BMzIWFz4BMzIXPgEzMhYXPgEzMhc+ATMyFhc+ATMyFhUUBiMiJwczMhQrASI0OwET\
NjU0IyIGBxUUBiMiJwczMhQrASI0OwETNjU0IyIGBxUUBiMiJwczMhQrASI0OwETNjU0IyIGBxUU\
BiUWMzI2NzY0JyYjIgYHBhUUBRYzMjY3NjQnJiMiBgcGFRQCCgIFEjIODQ8CBBI1Cw/+ywIFEjIO\
DQ8CBBI1Cw8TFhktNAsL4QsLS2gGCwgMDwsZCgUbBTEPFyUjJAcdJiMvExIiGyMkBx0mIy8TEiIb\
IyQHHSYjLxMSIhsjJAcdJiMeLWtJFhktNAsL4QsLS2gGCw4UFGtJFhktNAsL4QsLS2gGCw4UFGtJ\
JiMvExIiGyMkBx0mIx4ta0kWGS00CwvhCwtLaAYLDhQUa0kWGS00CwvhCwtLaAYLDhQUa0kWGS00\
CwvhCwtLaAYLDhQUawODAwQSMg4NDwMDEzQLD/7LAwQSMg4NDwMDEzQLDygBNSQhJSQGATMcJiUo\
BwE1JCElJAYBMxwmJSgvIHoeHgEdEA4PBxQSLBAIDwlYEBkTGh4PMhwWExoeDzIcFhMaHg8yHBYT\
Gh4PNDBHbSB6Hh4BHRAODxgjAUdtIHoeHgEdEA4PGCMBR20geh4eAR0QDg8YIwFHbSgBNSQhJSQG\
ATMcJiUoBwE1JCElJAYBMxwmJSgAAAAE/7T/iAQGARgAbwCBAJMApQAAISInBzMyFCsBIjQ7ARM2\
NTQjIgYHFRQGIyInBzMyFCsBIjQ7ARM2NTQjIgYHFRQGIyInBzMyFCsBIjQ7ARM2NTQjIg4DBwYm\
FhktNAsL4QsLS2gGCw4UFGsDgwIFEjIODQ8CBBI1Cw/+ywIFEjIODQ8CBBI1Cw8oATUkIUoFATMc\
JyQpBgE1JCAmJQUBMxwnJCkuIHoeHgEdEgwPBxQSLBAIDwlYEBkTGh4PMhwWExoeDzIcFhMaHg8y\
HBYTGh4PNDBHbSB6Hh4BHRIMDxgjAUdtIHoeHgEdEgwPGCMBR20geh4eAR0SDA8YIwFHbSgBNSQh\
SgUBMxwnJCkGATUkIUoFATMcJyQpAAT/tP+IBAYBGABvAIAAkQCjAAAhIicHMzIUKwEiNDsBEzY1\
NCMiBgcVFAYjIicHMzIUKwEiNDsBEzY1NCMiBgcVFAYjIicHMzIUKwEiNDsBEzY1NCMiDgMHBiY3\
Njc2MzIWFz4BMzIXPgEzMhYXPgEzMhc+ATMyFhc+ATMyFhUUBicWMzI2NzY0JyYjIgYHBhUUBRYz\
MjY3NjQnJiMiBgcGFRQFFjMyNjc2NTQnJiMiBgcGFRQDUhYZLTQLC+ELC0toBgsOFBRrSRYZLTQL\
C+ELC0toBgsOFBRrSRYZLTQLC+ELC0toBgsIDA8LGQoFGwUxDxclIyQHHSYjLxMSIhsjJAcdJiMv\
ExIiGyMkBx0mIx4ta0wCBRIyDg0PAgQSNQsP/ssCBRIyDg0PAgQSNQsP/ssCBRIyDg0PAgQSNQsP\
IHoeHgEdEgwPGCMBR20geh4eAR0SDA8YIwFHbSB6Hh4BHRIMDwcUEiwQCA8JWBAZExoeDzIcFhMa\
Hg8yHBYTGh4PNDBHbSgBNSQhSgUBMxwnJCkGATUkIUoFATMcJyQpBgE1JCAmJQUBMxwnJCkAAAP/\
tP+IAsEBGABMAF4AbwAAMyInBzMyFCsBIjQ7ARM2NTQjIg4DBwYmNzY3NjMyFhc+ATMyFz4BMzIW\
Fz4BMzIWFRQGIyInBzMyFCsBIjQ7ARM2NTQjIgYHFRQGJxYzMjY3NjU0JyYjIgYHBhUUBRYzMjY3\
NzY3NjMyFhc+ATMyFz4BMzIWFz4BMzIXPgEzMhYXPgEzMhYVFAYnFjMyNjc2NTQnJiMiBgcGFRQF\
FjMyNjc2NTQnJiMiBgcGFRQFFjMyNjc2NTQnJiMiBgcGFRQDUhYZLTQLC+ELC0toBgsOFBRrSRYZ\
LTQLC+ELC0toBgsOFBRrSRYZLTQLC+ELC0toBgsIDA8LGQoFGwUxDxclIyQHHSYjLxMSIhsjJAcd\
JiMvExIiGyMkBx0mIx4ta0wDBBIyDg0PAwMTNAsP/ssDBBIyDg0PAwMTNAsP/ssDBBIyDg0PAwMT\
NAsPIHoeHgEdEA4PGCMBR20geh4eAR0QDg8YIwFHbSB6Hh4BHRAODwcUEiwQCA8JWBAZExoeDzIc\
FhMaHg8yHBYTGh4PNDBHbSgBNSQhJSQGATMcJiUoBwE1JCElJAYBMxwmJSgHATUkISUkBgEzHCYl\
KAAAA/+0/4gCwQEYAEwAXgBwAAAzIicHMzIUKwEiNDsBEzY1NCMiDgMHBiY3Njc2MzIWFz4BMzIX\
PgEzMhYXPgEzMhYVFAYjIicHMzIUKwEiNDsBEzY1NCMiBgcVFAYnFjMyNjc2NTQnJiMiBgcGFRQF\
FjMyNjc2NTQnJiMiBgcGFRTIFhktNAsL4QsLS2gGCwgMDwsZCgUbBTEPFyUjJAcdJiMvExIiGyMk\
Bx0mIx4ta0kWGS00CwvhCwtLaAYLDhQUa0wDBBIyDg0PAwMTNAsPAVUDBBIyDg0PAwMTNAsPIHoe\
HgEdEA4PBxQSLBAIDwlYEBkTGh4PMhwWExoeDzQwR20geh4eAR0QDg8YIwFHbSgBNSQhJSQGATMc\
NjQnJiMiBgcGFRTIFhktNAsL4QsLS2gGCwgMDwsZCgUbBTEPFyUjJAcdJiMvExIiGyMkBx0mIx4t\
a0kWGS00CwvhCwtLaAYLDhQUa0wCBRIyDg0PAgQSNQsPAVUCBRIyDg0PAgQSNQsPIHoeHgEdEgwP\
BxQSLBAIDwlYEBkTGh4PMhwWExoeDzQwR20geh4eAR0SDA8YIwFHbSgBNSQgJiUFATMcJyQpBgE1\
JiUoBwE1JCElJAYBMxwmJSgAAv/b/4gDKwEYAHIAhAAAJTY3NjMyFhc+ATMyFhUUBiMiJwczMhQr\
ASI0OwETNjU0IyIOAwcOASMiJjU0PwE2NTQjIg8BBgcnBiY/ATY1NCMiDwEGBwYrASI/ATYmIyIG\
BwYmNz4DMzIXNjMyFz4BMzIWFRQPAQYVFDMyNz4BFxYzMjY3NjU0JyYjIgYHBhUUAa0xFBgiIyQH\
HSYjHi1rSRYZLTQLC+ELC0toBgsHDxIOGAgaPC0VGQU0ARUbCEEIDyYNCARDARUbCEQHCAQENQ0N\
QgQGCA0WJAUVBBQQIh8SNwskJC0JCykTGSQFLwQIAgMPJdEDBBIyDg0PAwMTNAsPd2wYHRMaHg80\
MEdtIHoeHgEdEA4PDR8bNRA2OBUUDA6IAwMOFKsWAQEBDwirAwMOFKwRAwEapw0PGjkIDAklGjAS\
KCgoEBgjGg0NfQsJDgIINTkBNSQhJSQGATMcJiUoAAAC/9v/YAMZAbgAUwCZAAA3BgcGKwEiPwE2\
JCFKBQEzHCckKQAAAAL/2/+IAysBGAByAIMAACU2NzYzMhYXPgEzMhYVFAYjIicHMzIUKwEiNDsB\
EzY1NCMiDgMHDgEjIiY1ND8BNjU0IyIPAQYHJwYmPwE2NTQjIg8BBgcGKwEiPwE2JiMiBgcGJjc+\
AzMyFzYzMhc+ATMyFhUUDwEGFRQzMjc+ARcWMzI2NzY0JyYjIgYHBhUUAa0xFBgiIyQHHSYjHi1r\
SRYZLTQLC+ELC0toBgsHDxIOGAgaPC0VGQU0ARUbCEEIDyYNCARDARUbCEQHCAQENQ0NQgQGCA0W\
JAUVBBQQIh8SNwskJC0JCykTGSQFLwQIAQQPJdECBRIyDg0PAgQSNQsPd2wYHRMaHg80MEdtIHoe\
HgEdEgwPDR8bNRA2OBYTDQ2IAgQOFKsWAQEBDwirAgQOFKwRAwEapw0PGjkIDAklGjASKCgoEBgj\
GgsPfQsJDgIINTkBNSQhSgUBMxwnJCkAAAAAAv/b/2ADGQG4AFMAlQAANwYHBisBIj8BNiYjIgYH\
JiMiBgcGJjc+AzMyFzYzMhc+ATMyFhUUDwEGFRQzMjc+BTc2FgcOAiMiJjU0PwE2NTQjIg8BBgcn\
BiY/ATY1NCMiBxMiJjU0NjMyFhUUBwYVFDMyPgc3IyImNTQ2OwE+ATMyFhUUBiMiJjU0NzY0IyIO\
BwczMhYUBisBDgFQBwgEBDUNDUIEBggNFiQFFQQUECIfEjcLJCQtCQspExkkBS8ECAIDBQsHDAMN\
AQYVBhIXLR8VGQU0ARUbCEEIDyYNCARDARUbCPUgMBcTEhcSChkLEA8LDQoODRQKNQkKCQhBFGk0\
IDAXExIXEgoZBwwKBwgFBgMGATYJCwsJPyF2FREDARqnDQ8aOQgMCSUaMBIoKCgQGCMaDQ19CwkO\
AgMJBg8FEgEJDQsfHxoVFAwOiAMDDhSrFgEBAQ8IqwMDDhT+nyYgGiIUDw4LBw0OBhETJSQ8N1Un\
DAkIC0tfJiAaIhQPDgsGHAULChQNGg0eBgwQDMXBAAAAAf9+/2ACaQG4AHgAACUjDgEjIiY1NDYz\
MhYVFAcGFRQzMj4HNyMiJjU0NjsBPgEzMhYVFAYjIiY1NDc2NCMiBwYHFz4BMzIWFRQGIyImNTQ3\
NjQjIg4HBzMyFhQGKwEOASMiJjU0NjMyFhUUBwYVFDMyPgcBX5shdl8gMBcTEhcSChkLEA8LDQoO\
DRQKNQkKCQhBFGk0IDAXExIXEgoZJhcDAZsUaTQgMBcTEhcSChkHDAoHCAUGAwYBNgkLCwk/IXZf\
BiY3PgMzMhc2MzIXPgEzMhYVFA8BBhUUMzI3PgU3NhYHDgIjIiY1ND8BNjU0IyIPAQYHJwYmPwE2\
NTQjIgcTIiY1NDYzMhYVFAcGFRQzMj4HNyMiNTQ7AT4BMzIWFRQGIyImNTQ3NjQjIg4HBzMyFCsB\
DgFQBwgEBDUNDUIEBggNFiQFFQQUECIfEjcLJCQtCQspExkkBS8ECAEEBQsHDAMNAQYVBhIXLR8V\
GQU0ARUbCEEIDyYNCARDARUbCPUgMBcTEhcSChkLEA8LDQoODRQKNRMRQRRpNCAwFxMSFxIKGQcM\
CgcIBQYDBgE2FBQ/IXYVEQMBGqcNDxo5CAwJJRowEigoKBAYIxoLD30LCQ4CAwkGDwUSAQkNCx8f\
GhYTDQ2IAgQOFKsWAQEBDwirAgQOFP6fJiAaIhQPDgsHDQ4GERMlJDw3VScVE0tfJiAaIhQPDgsG\
HAULChQNGg0eBijFwQAAAAH/fv9gAmkBuAB0AAAlIw4BIyImNTQ2MzIWFRQHBhUUMzI+BzcjIjU0\
OwE+ATMyFhUUBiMiJjU0NzY0IyIHBgcXPgEzMhYVFAYjIiY1NDc2NCMiDgcHMzIUKwEOASMiJjU0\
NjMyFhUUBwYVFDMyPgcBX5shdl8gMBcTEhcSChkLEA8LDQoODRQKNRMRQRRpNCAwFxMSFxIKGSYX\
AwGbFGk0IDAXExIXEgoZBwwKBwgFBgMGATYUFD8hdl8gMBcTEhcSChkLEA8LDQoPDRTmxcEmIBoi\
FA8OCwcNDgYREyUkPDdVJxUTS18mIBoiFA8OCwYccwwGAUtfJiAaIhQPDgsGHAULChQNGg0eBijF\
wSYgGiIUDw4LBw0OBhETJSQ8N1UAAAAB/37/YAN0AbgAqgAAEzM+ATMyFhUUBiMiJjU0NzY0IyIH\
BgcXPgEzMhYVFAYjIiY1NDc2NCMiDgcHMzIUKwEOASMiJjU0NjMyFhUUBwYVFDMyPgc3Iw4BIyIm\
NTQ2MzIWFRQHBhUUMzI+BzcjDgEjIiY1NDYzMhYVFAcGFRQzMj4HNyMiNTQ7AT4BMzIWFRQGIyIm\
NTQ3NjQjIg4CBwbMnBRpNCAwFxMSFxIKGSYXAwGbFGk0IDAXExIXEgoZBwwKBwgFBgMGATYTEz8h\
dl8gMBcTEhcSChkLEA8LDQoPDRQKmyF2XyAwFxMSFxIKGQsQDwsNCg4NFQqbIXZfIDAXExIXEgoZ\
CxAPCw0KDg0UCjUTEUEUaTQgMBcTEhcSChkOFQ4IBgIBDktfJiAaIhQPDgsGHHMMBgFLXyYgGiIU\
Dw4LBhwFCwoUDRoNHgYoxcEmIBoiFA8OCwcNDgYREyUkPDdVJ8XBJiAaIhQPDgsHDQ4GERMlJDs4\
VSfFwSYgGiIUDw4LBw0OBhETJSQ8N1UnFRNLXyYgGiIUDw4LBhwTJyIbCgAB/37/YASAAbgA4AAA\
ARc+ATMyFhUUBiMiJjU0NzY0IyIHBgcXPgEzMhYVFAYjIiY1NDc2NCMiDgcHMzIUKwEOASMiJjU0\
NjMyFhUUBwYVFDMyPgc3Iw4BIyImNTQ2MzIWFRQHBhUUMzI+BzcjDgEjIiY1NDYzMhYVFAcGFRQz\
Mj4HNyMOASMiJjU0NjMyFhUUBwYVFDMyPgc3IyI1NDsBPgEzMhYVFAYjIiY1NDc2NCMiBwYHFz4B\
MzIWFRQGIyImNTQ3NjQjIg4HAdicFGk0IDAXExIXEgoZJhcDAZsUaTQgMBcTEhcSChkHDAoHCAUG\
IDAXExIXEgoZCxAPCw0KDw0U5sXBJiAaIhQPDgsHDQ4GERMlJDw3VScMCQgLS18mIBoiFA8OCwYc\
cwwGAUtfJiAaIhQPDgsGHAULChQNGg0eBgwQDMXBJiAaIhQPDgsHDQ4GERMlJDw3VQAAAAH/fv9g\
A3QBuACuAAATMz4BMzIWFRQGIyImNTQ3NjQjIgcGBxc+ATMyFhUUBiMiJjU0NzY0IyIOBwczMhYU\
BisBDgEjIiY1NDYzMhYVFAcGFRQzMj4HNyMOASMiJjU0NjMyFhUUBwYVFDMyPgc3Iw4BIyImNTQ2\
MzIWFRQHBhUUMzI+BzcjIiY1NDY7AT4BMzIWFRQGIyImNTQ3NjQjIg4CBwbMnBRpNCAwFxMSFxIK\
GSYXAwGbFGk0IDAXExIXEgoZBwwKBwgFBgMGATYJCgoJPyF2XyAwFxMSFxIKGQsQDwsNCg8NFAqb\
IXZfIDAXExIXEgoZCxAPCw0KDg0VCpshdl8gMBcTEhcSChkLEA8LDQoODRQKNQkKCQhBFGk0IDAX\
ExIXEgoZDhUOCAYCAQ5LXyYgGiIUDw4LBhxzDAYBS18mIBoiFA8OCwYcBQsKFA0aDR4GDBAMxcEm\
AwYBNhMTPyF2XyAwFxMSFxIKGQsQDwsNCg8NFAqbIXZfIDAXExIXEgoZCxAPCw0KDg0UCpshdl8g\
MBcTEhcSChkLEA8LDQoPDRQKmyF2XyAwFxMSFxIKGQsQDwsNCg4NFAo1ExFBFGk0IDAXExIXEgoZ\
JhcDAZsUaTQgMBcTEhcSChkHDAoHCAUGAwYBDwFLXyYgGiIUDw4LBhxzDAYBS18mIBoiFA8OCwYc\
IBoiFA8OCwcNDgYREyUkPDdVJ8XBJiAaIhQPDgsHDQ4GERMlJDs4VSfFwSYgGiIUDw4LBw0OBhET\
JSQ8N1UnDAkIC0tfJiAaIhQPDgsGHBMnIhsKAAH/fv9gBIABuADkAAABFz4BMzIWFRQGIyImNTQ3\
NjQjIgcGBxc+ATMyFhUUBiMiJjU0NzY0IyIOBwczMhYUBisBDgEjIiY1NDYzMhYVFAcGFRQzMj4H\
NyMOASMiJjU0NjMyFhUUBwYVFDMyPgc3Iw4BIyImNTQ2MzIWFRQHBhUUMzI+BzcjDgEjIiY1NDYz\
MhYVFAcGFRQzMj4HNyMiJjU0NjsBPgEzMhYVFAYjIiY1NDc2NCMiBwYHFz4BMzIWFRQGIyImNTQ3\
NjQjIg4HAdicFGk0IDAXExIXEgoZJhcDAZsUaTQgMBcTEhcSChkHDAoHCAUGAwYBNgkKCgk/IXZf\
IDAXExIXEgoZCxAPCw0KDw0UCpshdl8gMBcTEhcSChkLEA8LDQoODRQKmyF2XyAwFxMSFxIKGQsQ\
DwsNCg8NFAqbIXZfIDAXExIXEgoZCxAPCw0KDg0UCjUJCgkIQRRpNCAwFxMSFxIKGSYXAwGbFGk0\
IDAXExIXEgoZBwwKBwgFBgMGAQ8BS18mIBoiFA8OCwYccwwGAUtfJiAaIhQPDgsGHAULChQNGg0e\
BgwQDMXBJiAaIhQPDgsHDQ4GERMlJDw3VSfFwSYgGiIUDw4LBw0OBhETJSM8N1YnxcEmIBoiFA8O\
CwcNDgYREyUkPDdVJ8XBJiAaIhQPDgsHDQ4GERMlJDw3VScMCQgLS18mIBoiFA8OCwYccwwGAUtf\
JiAaIhQPDgsGHAUKCxMOGQ4dAAAAAAMAAP9gAt8BuAA2AHIAuwAAMyImNTQ2MzIWFRQHFjMyNjU0\
BQsKFA0aDR4GKMXBJiAaIhQPDgsHDQ4GERMlJDw3VSfFwSYgGiIUDw4LBw0OBhETJSM8N1YnxcEm\
IBoiFA8OCwcNDgYREyUkPDdVJ8XBJiAaIhQPDgsHDQ4GERMlJDw3VScVE0tfJiAaIhQPDgsGHHMM\
BgFLXyYgGiIUDw4LBhwFCgsTDhkOHQAAAAADAAD/YALfAbgANgBxALYAADMiJjU0NjMyFhUUBxYz\
MjY1NC4DJy4CNTQ2MzIWFRQGIyImNTQ3JiMiBhUUHgIXHgEVFCUGLgE/ASYjIgYjIg4BBwYnJjc+\
LgMnLgI1NDYzMhYVFAYjIiY1NDcmIyIGFRQeAhceARUUJQYuAT8BJiMiBiMiDgEHBicmNz4BNxYz\
MjYzMhcWFA8BBhUUHgEXFj4BJy4BNTQ2MzIVFAYjIiMuASMiBSImNTQ2MzIWFRQHDgEeARUUFjI+\
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\
AGkAbgBlAC4AIABUAGgAaQBzACAAZgBvAG4AdAAgAGkAcwAgAGwAaQBjAGUAbgBzAGUAZAAgAHUA\
bgBkAGUAcgAgAHQAaABlACAAUwBJAEwAIABPAHAAZQBuACAARgBvAG4AdAAgAEwAaQBjAGUAbgBz\
AGUAIABcACgAaAB0AHQAcAA6AC8ALwBzAGMAcgBpAHAAdABzAC4AcwBpAGwALgBvAHIAZwAvAE8A\
RgBMAFwAKQAuAABDb3B5cmlnaHQgXDI1MSAyMDE4LTIwMTkgSmVhbi1GcmFuY29pcyBNb2luZS4g\
VGhpcyBmb250IGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBTSUwgT3BlbiBGb250IExpY2Vuc2UgXCho\
dHRwOi8vc2NyaXB0cy5zaWwub3JnL09GTFwpLgAAYQBiAGMAMgBzAHYAZwAAYWJjMnN2ZwAAUgBl\
AGcAdQBsAGEAcgAAUmVndWxhcgAARgBvAG4AdABGAG8AcgBnAGUAIAAyAC4AMAAgADoAIABhAGIA\
YwAyAHMAdgBnACAAOgAgADEAMgAtADIALQAyADAAMgAyAABGb250Rm9yZ2UgMi4wIDogYWJjMnN2\
Kh0dKh0yHSodHSoAAAAAAA4ArgABAAAAAAAAAIMBCAABAAAAAAABAAcBnAABAAAAAAACAAcBtAAB\
AAAAAAADAB8B/AABAAAAAAAEAAcCLAABAAAAAAAFAAgCRgABAAAAAAAGAAcCXwADAAEECQAAAQYA\
AAADAAEECQABAA4BjAADAAEECQACAA4BpAADAAEECQADAD4BvAADAAEECQAEAA4CHAADAAEECQAF\
ABACNAADAAEECQAGAA4CTwBDAG8AcAB5AHIAaQBnAGgAdAAgAFwAMgA1ADEAIAAyADAAMQA4AC0A\
MgAwADEAOQAgAEoAZQBhAG4ALQBGAHIAYQBuAGMAbwBpAHMAIABNAG8AaQBuAGUALgAgAFQAaABp\
AHMAIABmAG8AbgB0ACAAaQBzACAAbABpAGMAZQBuAHMAZQBkACAAdQBuAGQAZQByACAAdABoAGUA\
IABTAEkATAAgAE8AcABlAG4AIABGAG8AbgB0ACAATABpAGMAZQBuAHMAZQAgAFwAKABoAHQAdABw\
ADoALwAvAHMAYwByAGkAcAB0AHMALgBzAGkAbAAuAG8AcgBnAC8ATwBGAEwAXAApAC4AAENvcHly\
aWdodCBcMjUxIDIwMTgtMjAxOSBKZWFuLUZyYW5jb2lzIE1vaW5lLiBUaGlzIGZvbnQgaXMgbGlj\
ZW5zZWQgdW5kZXIgdGhlIFNJTCBPcGVuIEZvbnQgTGljZW5zZSBcKGh0dHA6Ly9zY3JpcHRzLnNp\
bC5vcmcvT0ZMXCkuAABhAGIAYwAyAHMAdgBnAABhYmMyc3ZnAABSAGUAZwB1AGwAYQByAABSZWd1\
bGFyAABGAG8AbgB0AEYAbwByAGcAZQAgADoAIABhAGIAYwAyAHMAdgBnACAAOgAgADEANAAtADQA\
LQAyADAAMgAzAABGb250Rm9yZ2UgOiBhYmMyc3ZnIDogMTQtNC0yMDIzAABhAGIAYwAyAHMAdgBn\
ZyA6IDEyLTItMjAyMgAAYQBiAGMAMgBzAHYAZwAAYWJjMnN2ZwAAVgBlAHIAcwBpAG8AbgAgACAA\
AFZlcnNpb24gIAAAYQBiAGMAMgBzAHYAZwAAYWJjMnN2ZwAAAgAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAACSAAAAAQACAQIAAwEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMB\
FAEVARYBFwEYARkBGgEbARwBHQEeAR8BIAEhASIBIwEkASUBJgEnASgBKQEqASsBLAEtAS4BLwEw\
ATEBMgEzATQBNQE2ATcBOAE5AToBOwE8AT0BPgE/AUABQQFCAUMBRAFFAUYBRwFIAUkBSgFLAUwB\
TQFOAU8BUAFRAVIBUwFUAVUBVgFXAVgBWQFaAVsBXAFdAV4BXwFgAWEBYgFjAWQBZQFmAWcBaAFp\
AWoBawFsAW0BbgFvAXABcQFyAXMBdAF1AXYBdwF4AXkBegF7AXwBfQF+AX8BgAGBAYIBgwGEAYUB\
hgGHAYgBiQGKAYsBjAGNAY4BjwYubm9kZWYHdW5pRTAwMAd1bmlFMDMwB3VuaUUwMzgHdW5pRTAz\
OQd1bmlFMDQzB3VuaUUwNDUHdW5pRTA0Ngd1bmlFMDQ3B3VuaUUwNDgHdW5pRTA1MAd1bmlFMDVD\
B3VuaUUwNjIHdW5pRTA2OQd1bmlFMDdBB3VuaUUwN0IHdW5pRTA3Qwd1bmlFMDdEB3VuaUUwN0UH\
dW5pRTA4MAd1bmlFMDgxB3VuaUUwODIHdW5pRTA4Mwd1bmlFMDg0B3VuaUUwODUHdW5pRTA4Ngd1\
bmlFMDg3B3VuaUUwODgHdW5pRTA4OQd1bmlFMDhBB3VuaUUwOEIHdW5pRTA4Qwd1bmlFMDk0B3Vu\
aUUwOTUHdW5pRTBBMAd1bmlFMEExB3VuaUUwQTIHdW5pRTBBMwd1bmlFMEE0B3VuaUUwQTkHdW5p\
RTBCMwd1bmlFMTAxB3VuaUUxQjkHdW5pRTFCQgd1bmlFMUU3B3VuaUUxRjIHdW5pRTFGNAd1bmlF\
MUY3B3VuaUUxRjkHdW5pRTFGQwd1bmlFMUZFB3VuaUUxRkYHdW5pRTIwMAd1bmlFMjQwB3VuaUUy\
NDEHdW5pRTI0Mgd1bmlFMjQzB3VuaUUyNDQHdW5pRTI0NQd1bmlFMjQ2B3VuaUUyNDcHdW5pRTI0\
OAd1bmlFMjQ5B3VuaUUyNjAHdW5pRTI2MQd1bmlFMjYyB3VuaUUyNjMHdW5pRTI2NAd1bmlFMjZh\
B3VuaUUyNmIHdW5pRTI4MAd1bmlFMjgxB3VuaUUyODIHdW5pRTI4Mwd1bmlFNEEwB3VuaUU0QTIH\
dW5pRTRBNAd1bmlFNEE4B3VuaUU0QUMHdW5pRTRDMAd1bmlFNENFB3VuaUU0RDEHdW5pRTRFMQd1\
bmlFNEUyB3VuaUU0RTMHdW5pRTRFNAd1bmlFNEU1B3VuaUU0RTYHdW5pRTRFNwd1bmlFNEU4B3Vu\
aUU0RTkHdW5pRTRFQQd1bmlFNTAwB3VuaUU1MDEHdW5pRTUyMAd1bmlFNTIxB3VuaUU1MjIHdW5p\
RTUyMwd1bmlFNTI0B3VuaUU1MjUHdW5pRTUyOQd1bmlFNTJBB3VuaUU1MkIHdW5pRTUyQwd1bmlF\
NTJEB3VuaUU1MkYHdW5pRTUzMAd1bmlFNTMxB3VuaUU1MzkHdW5pRTU2Ngd1bmlFNTY3B3VuaUU1\
NjkHdW5pRTU2Qwd1bmlFNTZEB3VuaUU1ODIHdW5pRTVEMAd1bmlFNUUyB3VuaUU2MTAHdW5pRTYx\
Mgd1bmlFNjE0B3VuaUU2MTgHdW5pRTYyNAd1bmlFNjMwB3VuaUU2NTAHdW5pRTY1NQd1bmlFOTEw\
B3VuaUU5MTEHdW5pRTkxMgd1bmlFOTE0B3VuaUU5MTUHdW5pRTkxOAd1bmlFOTIwB3VuaUU5MjUH\
dW5pRTk1RAd1bmlFQTAyB3VuaUVBQTQHdW5pRUNBMgd1bmlFQ0EzB3VuaUVDQTUHdW5pRUNBNwd1\
bmlFQ0E5B3VuaUVDQjcAAAAAAAAB//8AAgABAAAAAAAAAAwAFAAEAAAAAgAAAAEAAAABAAAAAAAB\
AABhYmMyc3ZnAABWAGUAcgBzAGkAbwBuACAAAFZlcnNpb24gAABhAGIAYwAyAHMAdgBnAABhYmMy\
c3ZnAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJIAAAABAAIBAgADAQMBBAEF\
AQYBBwEIAQkBCgELAQwBDQEOAQ8BEAERARIBEwEUARUBFgEXARgBGQEaARsBHAEdAR4BHwEgASEB\
IgEjASQBJQEmAScBKAEpASoBKwEsAS0BLgEvATABMQEyATMBNAE1ATYBNwE4ATkBOgE7ATwBPQE+\
AT8BQAFBAUIBQwFEAUUBRgFHAUgBSQFKAUsBTAFNAU4BTwFQAVEBUgFTAVQBVQFWAVcBWAFZAVoB\
WwFcAV0BXgFfAWABYQFiAWMBZAFlAWYBZwFoAWkBagFrAWwBbQFuAW8BcAFxAXIBcwF0AXUBdgF3\
AXgBeQF6AXsBfAF9AX4BfwGAAYEBggGDAYQBhQGGAYcBiAGJAYoBiwGMAY0BjgGPBi5ub2RlZgd1\
bmlFMDAwB3VuaUUwMzAHdW5pRTAzOAd1bmlFMDM5B3VuaUUwNDMHdW5pRTA0NQd1bmlFMDQ2B3Vu\
aUUwNDcHdW5pRTA0OAd1bmlFMDUwB3VuaUUwNUMHdW5pRTA2Mgd1bmlFMDY5B3VuaUUwN0EHdW5p\
RTA3Qgd1bmlFMDdDB3VuaUUwN0QHdW5pRTA3RQd1bmlFMDgwB3VuaUUwODEHdW5pRTA4Mgd1bmlF\
MDgzB3VuaUUwODQHdW5pRTA4NQd1bmlFMDg2B3VuaUUwODcHdW5pRTA4OAd1bmlFMDg5B3VuaUUw\
OEEHdW5pRTA4Qgd1bmlFMDhDB3VuaUUwOTQHdW5pRTA5NQd1bmlFMEEwB3VuaUUwQTEHdW5pRTBB\
Mgd1bmlFMEEzB3VuaUUwQTQHdW5pRTBBOQd1bmlFMEIzB3VuaUUxMDEHdW5pRTFCOQd1bmlFMUJC\
B3VuaUUxRTcHdW5pRTFGMgd1bmlFMUY0B3VuaUUxRjcHdW5pRTFGOQd1bmlFMUZDB3VuaUUxRkUH\
dW5pRTFGRgd1bmlFMjAwB3VuaUUyNDAHdW5pRTI0MQd1bmlFMjQyB3VuaUUyNDMHdW5pRTI0NAd1\
bmlFMjQ1B3VuaUUyNDYHdW5pRTI0Nwd1bmlFMjQ4B3VuaUUyNDkHdW5pRTI2MAd1bmlFMjYxB3Vu\
aUUyNjIHdW5pRTI2Mwd1bmlFMjY0B3VuaUUyNmEHdW5pRTI2Ygd1bmlFMjgwB3VuaUUyODEHdW5p\
RTI4Mgd1bmlFMjgzB3VuaUU0QTAHdW5pRTRBMgd1bmlFNEE0B3VuaUU0QTgHdW5pRTRBQwd1bmlF\
NEMwB3VuaUU0Q0UHdW5pRTREMQd1bmlFNEUxB3VuaUU0RTIHdW5pRTRFMwd1bmlFNEU0B3VuaUU0\
RTUHdW5pRTRFNgd1bmlFNEU3B3VuaUU0RTgHdW5pRTRFOQd1bmlFNEVBB3VuaUU1MDAHdW5pRTUw\
MQd1bmlFNTIwB3VuaUU1MjEHdW5pRTUyMgd1bmlFNTIzB3VuaUU1MjQHdW5pRTUyNQd1bmlFNTI5\
B3VuaUU1MkEHdW5pRTUyQgd1bmlFNTJDB3VuaUU1MkQHdW5pRTUyRgd1bmlFNTMwB3VuaUU1MzEH\
dW5pRTUzOQd1bmlFNTY2B3VuaUU1NjcHdW5pRTU2OQd1bmlFNTZDB3VuaUU1NkQHdW5pRTU4Mgd1\
bmlFNUQwB3VuaUU1RTIHdW5pRTYxMAd1bmlFNjEyB3VuaUU2MTQHdW5pRTYxOAd1bmlFNjI0B3Vu\
aUU2MzAHdW5pRTY1MAd1bmlFNjU1B3VuaUU5MTAHdW5pRTkxMQd1bmlFOTEyB3VuaUU5MTQHdW5p\
RTkxNQd1bmlFOTE4B3VuaUU5MjAHdW5pRTkyNQd1bmlFOTVEB3VuaUVBMDIHdW5pRUFBNAd1bmlF\
Q0EyB3VuaUVDQTMHdW5pRUNBNQd1bmlFQ0E3B3VuaUVDQTkHdW5pRUNCNwAAAAAAAAH//wACAAEA\
AAAAAAAADAAUAAQAAAACAAAAAQAAAAEAAAAAAAEAAAAA399K6gAAAADRlyIXAAAAAOBezeg=\
AAAAAN2HW+gAAAAA0ZciFwAAAADeLXWv\
") format("truetype")'
Changes to font/abc2svg.sfd.
1
2
3
4
5
6

7
8
9
10
11
12
13
14
15
16
17

18
19
20
21
22

23
24
25
26
27
28
29
1
2
3
4
5

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

23
24
25
26
27
28
29
30





-
+











+




-
+







SplineFontDB: 3.2
FontName: abc2svg
FullName: abc2svg
FamilyName: abc2svg
Weight: Regular
Copyright: Copyright \\251 2018-2019 Jean-Francois Moine. This font is licensed under the SIL Open Font License \\(http://scripts.sil.org/OFL\\).
Copyright: Copyright \\251 2018-2024 Jean-Francois Moine. This font is licensed under the SIL Open Font License \\(http://scripts.sil.org/OFL\\).
Version: 
ItalicAngle: 0
UnderlinePosition: 0
UnderlineWidth: 0
Ascent: 824
Descent: 200
InvalidEm: 0
LayerCount: 2
Layer: 0 1 "Back" 1
Layer: 1 0 "Fore" 0
XUID: [1021 296 1430826605 13506888]
FSType: 0
OS2Version: 0
OS2_WeightWidthSlopeOnly: 0
OS2_UseTypoMetrics: 0
CreationTime: 1433498007
ModificationTime: 1654926804
ModificationTime: 1705513399
PfmFamily: 17
TTFWeight: 400
TTFWidth: 5
LineGap: 92
VLineGap: 92
Panose: 2 0 5 3 0 0 0 0 0 0
OS2TypoAscent: 0
︙
40
41
42
43
44
45
46
47
48
49
50
51
52
53

54
55
56
57
58
59
60
41
42
43
44
45
46
47

48
49
50
51
52

53
54
55
56
57
58
59
60







-





-
+







HheadDescent: 0
HheadDOffset: 1
OS2Vendor: 'PfEd'
MarkAttachClasses: 1
DEI: 91125
LangName: 1033
Encoding: Custom
Compacted: 1
UnicodeInterp: none
NameList: Adobe Glyph List
DisplaySize: -96
AntiAlias: 1
FitToEm: 1
WinInfo: 0 8 2
WinInfo: 32 8 2
BeginPrivate: 0
EndPrivate
TeXData: 1 0 0 346030 173015 115343 0 1048576 115343 783286 444596 497025 792723 393216 433062 380633 303038 157286 324010 404750 52429 2506097 1059062 262144
BeginChars: 143 143

StartChar: .nodef
Encoding: 0 0 0
︙
1335
1336
1337
1338
1339
1340
1341
1342
1343


1344
1345
1346
1347
1348
1349
1350
1351





1352
1353
1354

1355
1356
1357
1358
1359




1360
1361
1362
1363
1364
1365
1366
1367
1335
1336
1337
1338
1339
1340
1341


1342
1343
1344
1345
1346





1347
1348
1349
1350
1351



1352





1353
1354
1355
1356

1357
1358
1359
1360
1361
1362
1363







-
-
+
+



-
-
-
-
-
+
+
+
+
+
-
-
-
+
-
-
-
-
-
+
+
+
+
-







 361 129 450 70 450 0 c 4
EndSplineSet
Validated: 1
EndChar

StartChar: uniE0A3
Encoding: 38 57507 38
Width: 329
Flags: MW
Width: 322
Flags: HMW
LayerCount: 2
Fore
SplineSet
292 68 m 4
 283 84 264 91 242 91 c 4
 164 91 31 10 31 -49 c 4
 31 -56 33 -62 37 -68 c 4
 45 -84 64 -91 86 -91 c 4
291 46 m 4
 291 61 278 85 237 85 c 4
 161 85 31 9 31 -46 c 4
 31 -47 33 -85 85 -85 c 4
 161 -85 291 -9 291 46 c 4
 164 -91 297 -10 297 49 c 4
 297 56 295 62 292 68 c 4
313 81 m 4
194 138 m 4
 323 61 328 41 328 22 c 4
 328 -70 223 -148 130 -148 c 4
 83 -148 40 -128 15 -81 c 4
 5 -61 0 -41 0 -22 c 4
 0 70 105 148 198 148 c 4
 289 138 322 64 322 21 c 4
 322 -65 219 -138 128 -138 c 4
 33 -138 0 -64 0 -21 c 4
 0 65 103 138 194 138 c 4
 245 148 288 128 313 81 c 4
EndSplineSet
Validated: 1
EndChar

StartChar: uniE0A4
Encoding: 39 57508 39
Width: 320
︙
Changes to modules/MIDI.js.
︙
35
36
37
38
39
40
41



42
43
44
45
46
47
48
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51







+
+
+







// This name must be used if some print map is required:
//	%%MIDI drummap g 42
//	%%map MIDIdrum g heads=x
// A same effect may be done by
//	%%percmap g 42 x
// but this is not abcMIDI compatible!

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.MIDI = {

    // parse %%MIDI commands
    do_midi: function(parm) {

    // build the equal temperament as a b40 float array
    function tb40(qs) {
︙
291
292
293
294
295
296
297



298
299
300
301
302
303
304
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310







+
+
+








    // set the MIDI parameters in the current voice
    set_vp: function(of, a) {
    var	i, item, s,
	abc = this,
	curvoice = abc.get_curvoice()

	// set the voice parameters before inserting any block
	of(a.slice(0))			// (copy because the parameters are removed)

	for (i = 0; i < a.length; i++) {
		switch (a[i]) {
		case "channel=":		// %%MIDI channel
			s = abc.new_block("midiprog")
			s.play = s.invis = 1 //true
			s.chn = curvoice.chn = a[++i]
			break
︙
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346


347
348

328
329
330
331
332
333
334

335
336
337
338
339
340
341
342
343
344
345
346
347
348
349


350
351


352







-















-
-
+
+
-
-
+
		case "mididrum=":		// %%MIDI drummap note midipitch
			if (!curvoice.map)
				curvoice.map = {}
			curvoice.map = a[++i]
			break
		}
	}
	of(a)
    }, // set_vp()

    do_pscom: function(of, text) {
	if (text.slice(0, 5) == "MIDI ")
		abc2svg.MIDI.do_midi.call(this, text)
	else
		of(text)
    },

    set_hooks: function(abc) {
	abc.do_pscom = abc2svg.MIDI.do_pscom.bind(abc, abc.do_pscom);
	abc.set_vp = abc2svg.MIDI.set_vp.bind(abc, abc.set_vp)
    }
} // MIDI

abc2svg.modules.hooks.push(abc2svg.MIDI.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.MIDI.loaded = true
abc2svg.mhooks.MIDI = abc2svg.MIDI.set_hooks
Changes to modules/ambitus.js.
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23



24
25
26
27
28
29
30
1
2

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33


-
+




















+
+
+







// ambitus.js - module to insert an ambitus at start of a voice
//
// Copyright (C) 2018-2021 Jean-Francois Moine
// Copyright (C) 2018-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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 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.  If not, see <http://www.gnu.org/licenses/>.
//
// This module is loaded when "%%ambitus" appears in a ABC source.
//
// Parameters
//	%%ambitus 1

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.ambitus = {
    do_ambitus: function() {
    var	C = abc2svg.C,
	s, v, p_v, min, max,
	voice_tb = this.get_voice_tb()

︙
94
95
96
97
98
99
100





















101
102
103
104
105
106
107
108
109
110
111
112
113
114

115
116
117
118
119
120


121
122

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143


144
145


146







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+














+




-
-
+
+
-
-
+
    set_fmt: function(of, cmd, param) {
	if (cmd == "ambitus") {
		this.cfmt().ambitus = param
		return
	}
	of(cmd, param)
    },

    set_glue: function(of, w) {
    var	v, s,
	voice_tb = this.get_voice_tb()

	of(w)
	if (this.cfmt().ambitus) {
		for (v = 0; v < voice_tb.length; v++) {
			s = voice_tb[v].sym
			while (!s.time && !s.clef_type)
				s = s.next
			if (s && s.nhd) {	// draw the helper lines if any
				s.x -= 26
				this.draw_hl(s)
				s.ymn = 3 * (s.notes[0].pit - 18) - 2
				s.ymx = 3 * (s.notes[1].pit - 18) + 2
				s.x += 26
			}
		}
	}
    }, // set_glue()

    set_width: function(of, s) {
	if (s.clef_type != undefined && s.nhd > 0) {
		s.wl = 40;
		s.wr = 12
	} else {
		of(s)
	}
    },

    set_hooks: function(abc) {
	abc.draw_symbols = abc2svg.ambitus.draw_symbols.bind(abc, abc.draw_symbols);
	abc.set_pitch = abc2svg.ambitus.set_pitch.bind(abc, abc.set_pitch);
	abc.set_format = abc2svg.ambitus.set_fmt.bind(abc, abc.set_format);
	abc.set_sym_glue = abc2svg.ambitus.set_glue.bind(abc, abc.set_sym_glue)
	abc.set_width = abc2svg.ambitus.set_width.bind(abc, abc.set_width)
    }
} // ambitus

abc2svg.modules.hooks.push(abc2svg.ambitus.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.ambitus.loaded = true
abc2svg.mhooks.ambitus = abc2svg.ambitus.set_hooks
Changes to modules/break.js.
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23



24
25
26
27
28
29
30
1
2

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33


-
+




















+
+
+







// break.js - module to handle the %%break command
//
// Copyright (C) 2018-2021 Jean-Francois Moine
// Copyright (C) 2018-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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 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.  If not, see <http://www.gnu.org/licenses/>.
//
// This module is loaded when "%%break" appears in a ABC source.
//
// Parameters
//	%%break measure_nb [":" num "/" den] [" " measure ...]*

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.break = {

	// get the %%break parameters
	get_break: function(parm) {
	    var	C = abc2svg.C,
		b, c, d, sq,
︙
121
122
123
124
125
126
127
128
129


130
131

124
125
126
127
128
129
130


131
132


133







-
-
+
+
-
-
+

    set_hooks: function(abc) {
	abc.do_pscom = abc2svg.break.do_pscom.bind(abc, abc.do_pscom);
	abc.set_bar_num = abc2svg.break.set_bar_num.bind(abc, abc.set_bar_num)
    }
} // break

abc2svg.modules.hooks.push(abc2svg.break.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.break.loaded = true
abc2svg.mhooks.break = abc2svg.break.set_hooks
Changes to modules/capo.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// capo.js - module to add a capo chord line
//
// Copyright (C) 2018-2021 Jean-Francois Moine
// Copyright (C) 2018-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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.
︙
18
19
20
21
22
23
24



25



26
27
28
29
30
31
32
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38







+
+
+

+
+
+







// along with abc2svg.  If not, see <http://www.gnu.org/licenses/>.
//
// This module is loaded when "%%capo" appears in a ABC source.
//
// Parameters
//	%%capo n	'n' is the capo fret number

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.capo = {
    // b40 intervals of capo
    icb40: [0, 5, 6,11,16,17,22,23,28,33,34,39],
//	    e  f ^f  g _a  a _b  b  c _d  d _e

    gch_build: function(of, s) {
    var	t, i, gch, gch2, i2,
	abc = this,
	p_v = abc.get_curvoice(),
	a_gch = s.a_gch

︙
41
42
43
44
45
46
47
48

49
50
51
52
53
54
55
47
48
49
50
51
52
53

54
55
56
57
58
59
60
61







-
+







				return
			}
			if (gch.type == 'g')
				break
		}
		gch2 = Object.create(gch)
		gch2.capo = false	// (would be erased when setting gch)
		gch2.text = abc.gch_tr1(gch2.text, -abc2svg.ifb40[t % 12])
		gch2.text = abc.gch_tr1(gch2.text, -abc2svg.capo.icb40[t % 12])
		if (!p_v.capo_first) {		// if new voice
			p_v.capo_first = true
			gch2.text += "  (capo: " + t.toString() + ")"
		}

		gch2.font = abc.get_font(abc.cfmt().capofont ?
						"capo" : "annotation")
︙
90
91
92
93
94
95
96
97
98


99
100

96
97
98
99
100
101
102


103
104


105







-
-
+
+
-
-
+
    set_hooks: function(abc) {
	abc.gch_build = abc2svg.capo.gch_build.bind(abc, abc.gch_build);
	abc.set_format = abc2svg.capo.set_fmt.bind(abc, abc.set_format)
	abc.set_vp = abc2svg.capo.set_vp.bind(abc, abc.set_vp)
    }
} // capo

abc2svg.modules.hooks.push(abc2svg.capo.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.capo.loaded = true
abc2svg.mhooks.capo = abc2svg.capo.set_hooks
Changes to modules/chordnames.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - chordnames.js - change the names of the chord symbols
//
// Copyright (C) 2020-2021 Jean-Francois Moine
// Copyright (C) 2020-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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.
︙
25
26
27
28
29
30
31



32
33
34
35
36
37
38
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41







+
+
+







//	Each name replace one chord. The order is:
//		CDEFGAB<N.C.>
// 2nd syntax:
//		%%chordnames <comma separated list of key ':' value>
//	The key may be a chord letter ('A') with/or an accidental
//	Example:
//		%%chordnames Bb:B,B:H,b:s	% German chords

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.chordnames = {

    gch_build: function(of, s) {
    var	gch, ix, t,
	cfmt = this.cfmt()

︙
83
84
85
86
87
88
89
90
91



86
87
88
89
90
91
92


93
94
95







-
-
+
+
+

    set_hooks: function(abc) {
	abc.gch_build = abc2svg.chordnames.gch_build.bind(abc, abc.gch_build)
	abc.set_format = abc2svg.chordnames.set_fmt.bind(abc, abc.set_format)
    } // set_hooks()
} // chordnames

abc2svg.modules.hooks.push(abc2svg.chordnames.set_hooks)
abc2svg.modules.chordnames.loaded = true
if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
abc2svg.mhooks.chordnames = abc2svg.chordnames.set_hooks
Changes to modules/clair.js.
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23



24
25
26
27
28
29
30
1
2

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33


-
+




















+
+
+







// clair.js - module to output Clairnote sheets (https:clairnote.org)
//
// Copyright (C) 2019-2021 Jean-Francois Moine
// Copyright (C) 2019-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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 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.  If not, see <http://www.gnu.org/licenses/>.
//
// This module is loaded when "%%clairnote" appears in a ABC source.
//
// Parameters (none)
//	%%clairnote 1

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.clair = {

// table for helper lines (from C, to c'')
// index = (note pitch + 16)
// value = array of line numbers / null
    hl_tb: [
︙
377
378
379
380
381
382
383
384
385


386
387

380
381
382
383
384
385
386


387
388


389







-
-
+
+
-
-
+
	abc.set_format = abc2svg.clair.set_fmt.bind(abc, abc.set_format);
	abc.set_pitch = abc2svg.clair.set_pitch.bind(abc, abc.set_pitch);
	abc.set_vp = abc2svg.clair.set_vp.bind(abc, abc.set_vp);
	abc.set_width = abc2svg.clair.set_width.bind(abc, abc.set_width)
    }
} // clair

abc2svg.modules.hooks.push(abc2svg.clair.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.clairnote.loaded = true
abc2svg.mhooks.clair = abc2svg.clair.set_hooks
Changes to modules/clip.js.
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23



24
25
26
27
28
29
30
1
2

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33


-
+




















+
+
+







// clip.js - module to handle the %%clip command
//
// Copyright (C) 2018-2021 Jean-Francois Moine
// Copyright (C) 2018-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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 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.  If not, see <http://www.gnu.org/licenses/>.
//
// This module is loaded when "%%clip" appears in a ABC source.
//
// Parameters
//	%%clip start_measure_nb [":" num "/" den] "-" end_measure_nb [":" num "/" den]

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.clip = {

    get_clip: function(parm) {
    var	C = abc2svg.C

	// get the start/stop points
︙
208
209
210
211
212
213
214
215
216


217
218

211
212
213
214
215
216
217


218
219


220







-
-
+
+
-
-
+

    set_hooks: function(abc) {
	abc.do_pscom = abc2svg.clip.do_pscom.bind(abc, abc.do_pscom);
	abc.set_bar_num = abc2svg.clip.set_bar_num.bind(abc, abc.set_bar_num)
    }
} // clip

abc2svg.modules.hooks.push(abc2svg.clip.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.clip.loaded = true
abc2svg.mhooks.clip = abc2svg.clip.set_hooks
Changes to modules/combine.js.
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23



24
25
26
27
28
29
30
1
2

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33


-
+




















+
+
+







// combine.js - module to add a combine chord line
//
// Copyright (C) 2018-2022 Jean-Francois Moine
// Copyright (C) 2018-2024 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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 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.  If not, see <http://www.gnu.org/licenses/>.
//
// This module is loaded when "%%voicecombine" appears in a ABC source.
//
// Parameters
//	%%voicecombine n	'n' is the combine level

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.combine = {

    // function called at start of the generation when multi-voices
    comb_v: function() {
    var	C = abc2svg.C,
	abc = this
︙
62
63
64
65
66
67
68
69
70






71
72
73
74
75
76
77
65
66
67
68
69
70
71


72
73
74
75
76
77
78
79
80
81
82
83
84







-
-
+
+
+
+
+
+







		return false
//	if (s2.a_dd) { //fixme: should check the double decorations
//		return false
//	}
	if (s.a_gch && s2.a_gch)
		return false
	if (s.type == C.REST) {
		if (s.type == s2.type && s.invis && !s2.invis)
			return false
		if (s.type == s2.type) {
			if (s.invis && !s2.invis)
				return //false
		} else if (s.combine <= 2) {
			return //false
		}
		return true
	}
	if (s2.a_ly)
		return false
	if (s2.beam_st != s.beam_st
	 || s2.beam_end != s.beam_end)
		return false;
︙
135
136
137
138
139
140
141

142
143
144
145
146
147
148
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156







+







				s2 = s;
				s = s2.ts_next
			}
		} else if (s.type == C.REST) {
			if (s.invis
			 && !s2.invis)
				delete s.invis
			s.multi = 0
		} else {
			combine_notes(s, s2)
			if (s2.ti1)
				s.ti1 = true
			if (s2.ti2)
				s.ti2 = true
		}
︙
276
277
278
279
280
281
282
283
284


285
286

284
285
286
287
288
289
290


291
292


293







-
-
+
+
-
-
+
	abc.do_pscom = abc2svg.combine.do_pscom.bind(abc, abc.do_pscom);
	abc.new_note = abc2svg.combine.new_note.bind(abc, abc.new_note);
	abc.set_stem_dir = abc2svg.combine.set_stem_dir.bind(abc, abc.set_stem_dir);
	abc.set_vp = abc2svg.combine.set_vp.bind(abc, abc.set_vp)
    }
} // combine

abc2svg.modules.hooks.push(abc2svg.combine.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.voicecombine.loaded = true
abc2svg.mhooks.combine = abc2svg.combine.set_hooks
Changes to modules/diag.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// diag.js - module to insert guitar chord diagrams
//
// Copyright (C) 2018-2021 Jean-Francois Moine
// Copyright (C) 2018-2024 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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.
︙
36
37
38
39
40
41
42



43
44
45
46
47
48
49
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52







+
+
+







//	<chord> = chord symbol
//	<dots>  = list of diagram offset of dots on the strings - '0 or 'x': no dot
//	<label> = text to write on the left of the <pos>th fret
//				(<pos> default = 1, fret #0 is no text)
//	<fingers> = finger numbers ou 'x' (mute) or '0'/'y' (no finger)
//	barre=<num>-<num> draw a bar between the two string numbers in the first fret
//				(numbering order 654321 for E,A,D,GBe)

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.diag = {

    cd4: {},
// common diagrams by Guido Gonzato from http://www.guitar-chord.org/ (2021-08-27)
    cd6: {
	C: "x32010 ,0 x32010",
︙
87
88
89
90
91
92
93



94

95
96

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

113
114
115
116

117
118
119
120
121

122
123
124
125

126
127
128
129

130
131
132
133
134
135

136
137
138
139
140
141
142
143
144
145
146
147


148
149
150

151
152
153



154
155
156
157
158
159
160
161
162
163
164
165
166
167

168
169
170
171
172
173

174
175
176
177
178
179
180
181

182
183
184
185
186
187
188
189
190

191
192
193
194
195
196


197
198
199
200



201
202
203
204
205
206
207








208
209







210
211

212
213
214
215
216
217
218
219
220
221
222
223
224
225
90
91
92
93
94
95
96
97
98
99

100


101


102
103
104
105
106
107
108
109
110
111
112
113
114

115
116
117
118

119
120
121
122
123

124
125
126
127

128
129
130
131

132
133
134
135
136
137

138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

155
156


157
158
159
160
161
162

163
164
165
166
167
168
169
170
171

172
173

174
175
176

177
178
179
180
181
182
183
184

185
186
187
188
189
190
191
192
193

194
195
196
197
198
199

200
201
202



203
204
205







206
207
208
209
210
211
212
213


214
215
216
217
218
219
220
221

222







223
224
225
226
227
228
229







+
+
+
-
+
-
-
+
-
-













-
+



-
+




-
+



-
+



-
+





-
+












+
+


-
+

-
-
+
+
+



-









-
+

-



-
+







-
+








-
+





-
+
+

-
-
-
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+

-
+
-
-
-
-
-
-
-







	B7: "021202 ,0 x21304",
	Bm7: "003020 fr2 x03020 barre=5-1",
	BM7: "003230 fr2 x03240 barre=5-1",
	Bsus4: "x03340 fr2 x02340 barre=5-1",
    }, // cd6{}

// function called before tune generation
    draw_gchord: function(of, i, s, x, y) {
    var	gch, nm,
	cfmt = this.cfmt(),
// n = number of strings
	n = cfmt.diag,				// number of strings
    do_diag: function(n) {
    var	glyphs = this.get_glyphs(),
	glyphs = this.get_glyphs()
	voice_tb = this.get_voice_tb(),
	decos = this.get_decos()

	// create the base decorations if not done yet
	if (!glyphs.ddot) {
		this.add_style("\
\n.fng {font:6px sans-serif}\
\n.frn {font:italic 7px sans-serif}")
		glyphs.ddot = '<circle id="ddot" class="fill" r="1.5"/>'
	}

	if (!glyphs["fb" + n]) {
		if (n == 4) {
			glyphs.fb4 = '<g id="fb4">\n\
<path class="stroke" stroke-width="0.4" d="\
M-6 -34h12m0 6h-12\
M-6 -24h12m0 6h-12\
m0 6h12m0 6h-12\
m0 6h12"/>\n\
<path class="stroke" stroke-width="0.5" d="\
M-6 -34v24m4 0v-24\
M-6 -24v24m4 0v-24\
m4 0v24m4 0v-24"/>\n\
</g>'
			glyphs.nut4 =
				'<path id="nut4" class="stroke" stroke-width="1.6" d="\
M-6.2 -34.5h12.4"/>'
M-6.2 -24.5h12.4"/>'
		} else {
			glyphs.fb6 = '<g id="fb6">\n\
<path class="stroke" stroke-width="0.4" d="\
M-10 -34h20m0 6h-20\
M-10 -24h20m0 6h-20\
m0 6h20m0 6h-20\
m0 6h20"/>\n\
<path class="stroke" stroke-width="0.5" d="\
M-10 -34v24m4 0v-24\
M-10 -24v24m4 0v-24\
m4 0v24m4 0v-24\
m4 0v24m4 0v-24"/>\n\
</g>'
			glyphs.nut6 =
				'<path id="nut6" class="stroke" stroke-width="1.6" d="\
M-10.2 -34.5h20.4"/>'
M-10.2 -24.5h20.4"/>'
		}
	}

	// convert the chord symbol to a "better known" one
	function ch_cnv(t) {
	    var	a = t.match(/[A-G][#♯b♭]?([^/]*)\/?/)	// a[1] = chord type
		if (a && a[1]) {
			a[2] = abc2svg.ch_alias[a[1]]
			if (a[2] != undefined)
				t = t.replace(a[1], a[2])
		}
		return t.replace('/', '.')
			.replace(/\u266f/g,'#')
			.replace(/\u266d/g,'b')
	} // ch_cnv()

	// add a decoration and display the diagram
	// create a glyph of the diagram
	function diag_add(nm) {			// chord name
	    var	dc, i, l, x,
		d = abc2svg.diag["cd" + n][nm]	// definition of the diagram
	    var	dc, i, l, x, y,
		d = abc2svg.diag["cd" + n][nm.slice(1)]
						// definition of the diagram

		if (!d)
			return		// no diagram of this chord
		nm = n + nm
		d = d.split(' ')
		x = 2 - 2 * n
		dc = '<g id="' + nm + '">\n\
<use xlink:href="#fb' + n + '"/>\n'
		l = d[1].split(',')	// label,position
		if (!l[0] || l[0].slice(-1) == l[1])
			dc += '<use xlink:href="#nut' + n + '"/>\n'
		if (l[0])
			dc += '<text x="' + (x - 10).toString()
				+ '" y="' + ((l[1] || 1) * 6 - 35)
				+ '" y="' + ((l[1] || 1) * 6 - 25)
				+ '" class="frn">' + l[0] + '</text>\n'
		decos[nm] = "3 " + nm + " 40 " + (l[0] ? "30" : "10") + " 0"
		// fingers
		dc += '<text x="' + (n == 6 ? '-12,-8,-4,0,4,8'
					: '-8,-4,0,4')
				+ '" y="-36" class="fng">'
				+ '" y="-26" class="fng">'
				+ d[2].replace(/[y0]/g, ' ')
				+ '</text>\n'
		// dots
		for (i = 0; i < n; i++) {
			l = d[0][i]
			if (l && l != 'x' && l != '0')
				dc += '<use x="' + (i * 4 + x)
					+ '" y="' + (l * 6 - 37)
					+ '" y="' + (l * 6 - 27)
					+ '" xlink:href="#ddot"/>\n'
		}
		// barre
		if (d[3]) {
			l = d[3].match(/barre=(\d)-(\d)/)
			if (l)
				dc += '<path id="barre" class="stroke"\
 stroke-width="1.4" d="M' + ((n - l[1]) * 4 + x - 2)
					+ ' -31h' + ((l[1] - l[2]) * 4 + 4) + '"/>'
					+ ' -21h' + ((l[1] - l[2]) * 4 + 4) + '"/>'
		}
		dc += '</g>'
		glyphs[nm] = dc
	} // diag_add()

    var	s, i, gch, nm
	// --- draw_gchord ---
	of(i, s, x, y)		// draw the chord symbols and the annotations

	for (s = voice_tb[0].sym; s; s = s.next) {
		if (!s.a_gch)
			continue
	if ((s.invis && s.play)	// play sequence: no chord nor annotation
	 || !n)			// no %%diagram
		return
		for (i = 0; i < s.a_gch.length; i++) {
			gch = s.a_gch[i]
			if (!gch || gch.type != 'g' || gch.capo)
				continue
			nm = ch_cnv(gch.text)
			if (!decos[n + nm])	// if no decoration yet
				diag_add(nm)
	gch = s.a_gch[i]
	if (!gch || gch.type != 'g' || gch.capo)
		return
	nm = n + ch_cnv(gch.text)	// glyph name

	// build a glyph if not done yet
	if (!glyphs[nm])
		diag_add(nm)
			this.deco_put(n + nm, s) // insert diag as decoration
		}

	// output the diagram above the chord symbol
	if (glyphs[nm]) {
		x = s.x
		y = this.y_get(s.st, 1, x - 10, 20)
		this.xygl(x, y + 2, nm)
		this.y_set(s.st, 1, x - 10, 20, y + 34)
	}
    }, // do_diag()
    }, // draw_gchord()

    output_music: function(of) {
    var	n = this.cfmt().diag
	if (n)
		abc2svg.diag.do_diag.call(this, n)
	of()
    },

    set_fmt: function(of, cmd, param) {
    var	a, d, n,
	cfmt = this.cfmt()

	switch (cmd) {
	case "diagram":
︙
246
247
248
249
250
251
252
253

254
255
256
257
258
259


260
261

250
251
252
253
254
255
256

257
258
259
260
261


262
263


264







-
+




-
-
+
+
-
-
+
		this.syntax(1, this.errs.bad_val, "%%setdiag")
		return
	}
	of(cmd, param)
    },

    set_hooks: function(abc) {
	abc.output_music = abc2svg.diag.output_music.bind(abc, abc.output_music);
	abc.draw_gchord = abc2svg.diag.draw_gchord.bind(abc,abc.draw_gchord)
	abc.set_format = abc2svg.diag.set_fmt.bind(abc, abc.set_format)
    }
} // diag

abc2svg.modules.hooks.push(abc2svg.diag.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.diagram.loaded = true
abc2svg.mhooks.diag = abc2svg.diag.set_hooks
Changes to modules/equalbars.js.
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23



24
25
26
27
28
29
30
1
2

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33


-
+




















+
+
+







// equalbars.js - module to set equal spaced measure bars
//
// Copyright (C) 2018-2022 Jean-Francois Moine
// Copyright (C) 2018-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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 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.  If not, see <http://www.gnu.org/licenses/>.
//
// This module is loaded when "%%equalbars" appears in a ABC source.
//
// Parameters
//	%%equalbars bool

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.equalbars = {

    // new tune - clear the width of the start of the staff
    output_music: function(of) {
	this.equalbars_d = 0;
	of()
︙
41
42
43
44
45
46
47
48

49
50
51
52
53
54
55
44
45
46
47
48
49
50

51
52
53
54
55
56
57
58







-
+







	fmt.stretchlast = 1
    },

    // adjust the symbol offsets of a music line
    // only the bars of the first voice are treated
    set_sym_glue: function(of, width) {
    var	C = abc2svg.C,
	s, s2, w, i, n, x, g, t, t0,
	s, s2, d, w, i, n, x, g, t, t0,
	bars = [],
	tsfirst = this.get_tsfirst();

	of(width)			// compute the x offset of the symbols
	if (!this.cfmt().equalbars)
		return

︙
69
70
71
72
73
74
75
76

77
78
79
80
81
82
83


84
85
86
87
88
89
90
72
73
74
75
76
77
78

79
80
81
82
83
84


85
86
87
88
89
90
91
92
93







-
+





-
-
+
+







	}
	if (!s2)
		return

	// build an array of the bars
	t0 = t = s2.time
	for (s = s2; s.next; s = s.next) {
		if (s.type == C.BAR && s.seqst) {
		if (s.type == C.BAR && s.seqst && s.time != t) {
			bars.push([s, s.time - t]);
			t = s.time
		}
	}

	// push the last bar if it is not the invisible bar after a key change
	if (!s.invis || (s.prev && s.prev.type != C.KEY))
	// push the last bar or replace it in the array
	if (s.time != t)
		bars.push([s, s.time - t])
	else
		bars[bars.length - 1][0] = s	// replace the last bar

	t = s.time
	if (s.dur)
		t += s.dur;
︙
105
106
107
108
109
110
111
112

113
114
115
116
117
118
119
120
121
122







123
124
125
126
127
128
129
130
131
132
133
134


135
136
137
138
139
140
141
108
109
110
111
112
113
114

115
116
117
118
119
120
121
122
123


124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141

142
143
144
145
146
147
148
149
150







-
+








-
-
+
+
+
+
+
+
+











-
+
+







		}
		if (w * n < width)
			width = w * n
		this.set_realwidth(width)
	}

	// set the measure parameters
	x = s2.type == C.GRACE ? s2.extra.x : s2.x;
	x = s2.type == C.GRACE ? s2.extra.x : (s2.x - s2.wl)
	if (this.equalbars_d < x)
		this.equalbars_d = x		// new offset of the first note/rest

	d = this.equalbars_d
	w = (width - d) / (t - t0)		// width per time unit

	// loop on the bars
	for (i = 0; i < n; i++) {
		do {				// don't shift the 1st note
			s2.x = d + s2.x - x	// from the bar
		do {			// don't shift the 1st note from the bar
			if (s2.type == C.GRACE) {
				for (g = s2.extra; g; g = g.next)
					g.x = d + g.x - x
			} else {
				s2.x = d + s2.x - x
			}
			s2 = s2.ts_next
		} while (!s2.seqst)

		s = bars[i][0];			// next bar
		f = w * bars[i][1] / (s.x - x)

		// and update the x offsets
		for ( ; s2 != s; s2 = s2.ts_next) {
			if (s2.type == C.GRACE) {
				for (g = s2.extra; g; g = g.next)
					g.x = d + (g.x - x) * f
			} else if (s2.x) {
//			} else if (s2.x) {
			} else {
				s2.x = d + (s2.x - x) * f
			}
		}
		d += w * bars[i][1];
		x = s2.x
		while (1) {
			s2.x = d;
︙
151
152
153
154
155
156
157
158
159


160
161

160
161
162
163
164
165
166


167
168


169







-
-
+
+
-
-
+
    set_hooks: function(abc) {
	abc.output_music = abc2svg.equalbars.output_music.bind(abc, abc.output_music);
	abc.set_format = abc2svg.equalbars.set_fmt.bind(abc, abc.set_format);
	abc.set_sym_glue = abc2svg.equalbars.set_sym_glue.bind(abc, abc.set_sym_glue)
    }
} // equalbars

abc2svg.modules.hooks.push(abc2svg.equalbars.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.equalbars.loaded = true
abc2svg.mhooks.equalbars = abc2svg.equalbars.set_hooks
Changes to modules/gamelan.js.
︙
37
38
39
40
41
42
43



44
45
46
47
48
49
50
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53







+
+
+







//	bem	D_E ^G A _B	12456
//	barang	_E F A _B c	23567
// numbers
//	??	E F G B c
//	??	C ^C _E G _A (or ^C D E ^G A)
// dot = continuation (not rest)

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.gamelan = {

  cde2fcg: new Int8Array([0, 2, 4, -1, 1, 3, 5]),
  cgd2cde: new Int8Array([0, -4, -1, -5, -2, -6, -3,
			  0, -4, -1, -5, -2, -6, -3, 0]),
  acc2: new Int8Array([-2, -1, 3, 1, 2]),

︙
460
461
462
463
464
465
466
467
468


469
470

463
464
465
466
467
468
469


470
471


472







-
-
+
+
-
-
+
	abc.get_glyphs().gstc = '<circle id="gstc" cx="0" cy="-3" r="2"/>'
	abc.get_decos().gstc = "0 gstc 5 1 1"

	abc.add_style("\n.bn {font-family:sans-serif; font-size:16px}")
    } // set_hooks()
} // gamelan

abc2svg.modules.hooks.push(abc2svg.gamelan.set_hooks)

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.gamelan.loaded = true
abc2svg.mhooks.gamelan = abc2svg.gamelan.set_hooks
Changes to modules/grid.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - grid.js - module to insert a chord grid before or after a tune
//
// Copyright (C) 2018-2022 Jean-Francois Moine
// Copyright (C) 2018-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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.
︙
25
26
27
28
29
30
31



32
33
34
35
36
37
38
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41







+
+
+







//			> 0: above the tune, < 0: under the tune
//		<list> = comma separated list of (continuous) measure numbers
//		'nomusic' displays only the grid
//		'norepeat' omits the ':' indications
//		'repbrk' starts a new grid line on start/stop repeat
//		'parts' displays the parts on the left side of the grid
//	%%gridfont font_name size (default: 'serif 16')

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.grid = {
    pl: '<path class="stroke" stroke-width="1" d="M',

// generate the grid
    block_gen: function(of, s) {
	if (s.subtype != "grid") {
︙
298
299
300
301
302
303
304

305
306
307
308
309
310
311
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315







+







	}
	abc.vskip(hr * (nr + 1) + 6)
} // build_grid()

	// ----- block_gen() -----
    var	p_voice, n, font, f2

	abc.set_page()
	img = abc.get_img()

	// set the text style
	font = abc.get_font('grid')
	if (font.class)
		font.class += ' mid'
	else
︙
397
398
399
400
401
402
403

404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421


422
423
424
425
426
427
428
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425

426
427
428
429
430
431
432
433
434







+

















-
+
+







				cur_beat += beat
			}
			if (s.part)
				parts[chords.length] = s.part.text
			switch (s.type) {
			case C.NOTE:
			case C.REST:
			case C.SPACE:
				if (!s.a_gch || chord[beat_i])
					break
				bt = cs_filter(s.a_gch)
				if (!bt)
					break
					w = abc.strwh(bt.replace(
						/<[^>]+>/gm,''))
					if (w[0] > wmx)
						wmx = w[0]
					bt = new String(bt)
					bt.wh = w
				chord[beat_i] = bt
				break
			case C.BAR:
				i = s.bar_num		// check if normal measure bar
				bt = s.bar_type
				while (s.ts_next && s.ts_next.time == s.time) {
					if (s.ts_next.dur)
					if (s.ts_next.dur
					 || s.ts_next.type == C.SPACE)
						break
					s = s.ts_next
					if (s.type == C.METER) {
						beat = get_beat(s)
						wm = s.wmeasure
						continue
					}
︙
579
580
581
582
583
584
585
586
587


588
589

585
586
587
588
589
590
591


592
593


594







-
-
+
+
-
-
+
    set_hooks: function(abc) {
	abc.block_gen = abc2svg.grid.block_gen.bind(abc, abc.block_gen)
	abc.set_stems = abc2svg.grid.set_stems.bind(abc, abc.set_stems)
	abc.set_format = abc2svg.grid.set_fmt.bind(abc, abc.set_format)
    }
} // grid

abc2svg.modules.hooks.push(abc2svg.grid.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.grid.loaded = true
abc2svg.mhooks.grid = abc2svg.grid.set_hooks
Changes to modules/grid2.js.
︙
19
20
21
22
23
24
25



26
27
28
29
30
31
32
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35







+
+
+







//
// This module is loaded when "%%grid2" appears in a ABC source.
//
// Parameters
//	%%grid2 y
// This command may appear globally or in a voice.

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.grid2 = {

// function called before tune generation
    do_grid: function() {
    var s, v, p_v, ix, cs, c_a_cs, bt, gch,
	voice_tb = this.get_voice_tb()

︙
117
118
119
120
121
122
123
124
125


126
127

120
121
122
123
124
125
126


127
128


129







-
-
+
+
-
-
+
    set_hooks: function(abc) {
	abc.draw_gchord = abc2svg.grid2.draw_gchord.bind(abc, abc.draw_gchord);
	abc.output_music = abc2svg.grid2.output_music.bind(abc, abc.output_music);
	abc.set_format = abc2svg.grid2.set_fmt.bind(abc, abc.set_format)
    }
} // grid2

abc2svg.modules.hooks.push(abc2svg.grid2.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.grid2.loaded = true
abc2svg.mhooks.grid2 = abc2svg.grid2.set_hooks
Changes to modules/grid3.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// grid3.js - module to insert a manual chords
//
// Copyright (C) 2020-2022 Jean-Francois Moine
// Copyright (C) 2020-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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.
︙
27
28
29
30
31
32
33



34
35
36
37
38
39
40
41
42

43
44
45
46
47
48
49
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53







+
+
+









+







//	%%gridfont font_name size (default: 'serif 16')
//
// When this command appears inside a tune and when 'chord-define' is present,
// the chords are used to define the chord symbols that are displayed
// above the staff system.
// When 'noprint' is also present, the grid itself is not displayed.

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.grid3 = {

// generate the grid
    block_gen: function(of, s) {
	if (s.subtype != "grid3") {
		of(s)
		return
	}

	this.set_page()
	this.blk_flush()

    var	abc = this,
	cfmt = abc.cfmt(),
	img = abc.get_img(),
	posy = abc.get_posy(),
	txt = s.text,
︙
464
465
466
467
468
469
470
471
472


473
474

468
469
470
471
472
473
474


475
476


477







-
-
+
+
-
-
+
    set_hooks: function(abc) {
	abc.block_gen = abc2svg.grid3.block_gen.bind(abc, abc.block_gen)
	abc.do_begin_end = abc2svg.grid3.do_begin_end.bind(abc, abc.do_begin_end)
	abc.output_music = abc2svg.grid3.output_music.bind(abc, abc.output_music)
    }
} // grid3

abc2svg.modules.hooks.push(abc2svg.grid3.set_hooks)

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.begingrid.loaded = true
abc2svg.mhooks.grid3 = abc2svg.grid3.set_hooks
Changes to modules/jazzchord.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - jazzchord.js - Adds jazz chord styling to chord symbols
//
// Copyright (C) 2020-2022 Jean-Francois Moine
// Copyright (C) 2020-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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.
︙
20
21
22
23
24
25
26



27
28
29
30
31
32
33
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36







+
+
+







// Code adapted from Chris Fargen.
//	https://gist.github.com/chrisfargen/4324c6cf6fed2c8f9a6eae1680e53169
//
// This module is loaded by %%jazzchord.
//
// Parameters
//	%%jazzchord [ string '=' replacement-string ]*

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.jazzchord = {

    // default replacements
    defrep: {
	"-": "–",
	"°": "o",
︙
57
58
59
60
61
62
63












64
65

66
67

68
69
70
71
72
73
74
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

80
81

82
83
84
85
86
87
88
89







+
+
+
+
+
+
+
+
+
+
+
+

-
+

-
+







		a = t.match(/(\[?[A-G])([#♯b♭]?)([^/]*)\/?(.*)\)?/)
		// a[1]=note, a[2]=acc, a[3]=quality, a[4]=bass

		if (!a)
			return t
		if (a[2])
			r = "$7" + a[2]
		if (a[3][0] == 'm'		// if minor
		 && a[3].slice(0, 3) != "maj") {
			if (!r)
				r += "$7"
			if (a[3].slice(0, 3) == "min") {
				r += a[3].slice(0, 3)
				a[3] = a[3].slice(3)
			} else {		// assume 'm'
				r += 'm'
				a[3] = a[3].slice(1)
			}
		}
		if (a[3])
			r += (a[2] ? "$0" : '') + "$8" + a[3]
			r += (r ? "$0" : '') + "$8" + a[3]
		if (a[4])
			r += ((a[2] || a[3]) ? "$0" : '') + "$9/" + a[4]
			r += (r ? "$0" : '') + "$9/" + a[4]
		if (!r)
			return t
		return a[1] + r + "$0"
	} // jzch()

	for (ix = 0; ix < s.a_gch.length; ix++) {
		gch = s.a_gch[ix]
︙
155
156
157
158
159
160
161
162

163
164
165
166
167
168
169
170
171
172
173



170
171
172
173
174
175
176

177
178
179
180
181
182
183
184
185
186


187
188
189







-
+









-
-
+
+
+
    }, // set_fmt()

    set_hooks: function(abc) {
	abc.gch_build = abc2svg.jazzchord.gch_build.bind(abc, abc.gch_build)
	abc.set_format = abc2svg.jazzchord.set_fmt.bind(abc, abc.set_format)

	abc.add_style("\
\n.jc7{baseline-shift:10%;font-size:90%;letter-spacing:-0.05em}\
\n.jc7{font-size:90%}\
\n.jc8{baseline-shift:25%;font-size:75%;letter-spacing:-0.05em}\
\n.jc9{font-size:75%;letter-spacing:-0.05em}\
")
	abc.param_set_font("setfont-7", "* * class=jc7")
	abc.param_set_font("setfont-8", "* * class=jc8")
	abc.param_set_font("setfont-9", "* * class=jc9")
    } // set_hooks()
} // jazzchord

abc2svg.modules.hooks.push(abc2svg.jazzchord.set_hooks)
abc2svg.modules.jazzchord.loaded = true
if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
abc2svg.mhooks.jazzchord = abc2svg.jazzchord.set_hooks
Changes to modules/jianpu.js.
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23



24
25
26
27
28
29
30
1
2

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33


-
+




















+
+
+







// jianpu.js - module to output jiănpŭ (简谱) music sheets
//
// Copyright (C) 2020-2023 Jean-Francois Moine
// Copyright (C) 2020-2024 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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 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.  If not, see <http://www.gnu.org/licenses/>.
//
// This module is loaded when "%%jianpu" appears in a ABC source.
//
// Parameters (none)
//	%%jianpu 1

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.jianpu = {

  k_tb: [ "Cb", "Gb", "Db", "Ab", "Eb", "Bb", "F",
	  "C",
	  "G", "D", "A", "E", "B", "F#", "C#" ],
  cde2fcg: new Int8Array([0, 2, 4, -1, 1, 3, 5]),
︙
66
67
68
69
70
71
72


73
74
75
76
77
78
79
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84







+
+







						break
					s1 = s1.prev
				}
				//add deco '{' on s1
				while (!s1.bar_type) {
					s1.dy = 14
					s1.notes[0].pit = 30
					if (s1.type == C.REST)
						s1.combine = -1
					s1 = s1.next
				}
				// add deco '}' on s1

				while (1) {
					s.dy = -14
					s.notes[0].pit = 20
︙
144
145
146
147
148
149
150

















151

152
153
154
155
156
157
158
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172

173
174
175
176
177
178
179
180







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+








		if (s.dur >= C.BLEN)
			n = 3 
		else if (s.dur == C.BLEN / 2)
			n = 1
		else
			n = 2

		// duplicate the note/rest for display
		s2 = abc.clone(s)
		s2.invis =
			s2.play = 1 //true
		s2.next = s
		if (s2.prev)
			s2.prev.next = s2
		s.prev = s2
		s2.ts_next = s
		if (s2.ts_prev)
			s2.ts_prev.ts_next = s2
		s.ts_prev = s2
		delete s.seqst
		s.noplay = 1 // true

		// create the continuation symbols
		s.notes[0].dur =
//		s.notes[0].dur =
		s.dur = s.dur_orig = C.BLEN / 4
		delete s.fmr
		while (--n >= 0) {
			s2 = {
				type: C.REST,
				v: s.v,
				p_v: s.p_v,
︙
323
324
325
326
327
328
329
330

331
332
333
334
335
336
337
338
339
340
341
342

343
344
345
346
347
348
349
345
346
347
348
349
350
351

352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372







-
+












+








	set_head()

	for (v = 0; v < voice_tb.length; v++) {
		p_v = voice_tb[v]
		if (p_v.jianpu) {
			set_sym(p_v)
			if (v > 0 && voice_tb[v - 1].st == p_v.st)
			if (p_v.second)
				ov_def(v)
		}
	}

	of()
  }, // output_music()

  draw_symbols: function(of, p_voice) {
    var	s, s2, nl, y,
	C = abc2svg.C,
	abc = this,
	dot = "\ue1e7",
	anno_a = abc.anno_a,
	staff_tb = abc.get_staff_tb(),
	out_svg = abc.out_svg,
	out_sxsy = abc.out_sxsy,
	xypath = abc.xypath

	if (!p_voice.jianpu) {
		of(p_voice)
︙
443
444
445
446
447
448
449

450
451
452
453
454
455
456
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480







+








		if (s.nflags >= 0 && s.dots)
			out_mus(x + 8 * sc, y + 13 * sc, dot)
		if (s.grace) {
			out_svg('</g>\n')
			abc.stv_g().g--
		}
		anno_a.push(s)
	} // draw_note()

	// -- draw_symbols --
	for (s = p_voice.sym; s; s = s.next) {
		if (s.invis)
			continue
		switch (s.type) {
︙
599
600
601
602
603
604
605
606
607


608
609

623
624
625
626
627
628
629


630
631


632







-
-
+
+
-
-
+
	abc.get_glyphs().gstc = '<circle id="gstc" cx="0" cy="-3" r="2"/>'
	abc.get_decos().gstc = "0 gstc 5 1 1"

	abc.add_style("\n.fj{font:15px sans-serif}")
    } // set_hooks()
} // jianpu

abc2svg.modules.hooks.push(abc2svg.jianpu.set_hooks)

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.jianpu.loaded = true
abc2svg.mhooks.jianpu = abc2svg.jianpu.set_hooks
Changes to modules/mdnn.js.
︙
53
54
55
56
57
58
59



60
61
62
63
64
65
66
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69







+
+
+







      return to;
    },
    writable: true,
    configurable: true
  });
}

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.mdnn = {

  cde2fcg: new Int8Array([0, 2, 4, -1, 1, 3, 5]),
  cgd2cde: new Int8Array([0, -4, -1, -5, -2, -6, -3,
			  0, -4, -1, -5, -2, -6, -3, 0]),
  acc_tb: ["aff", "af", "n", "s", "ss"],

︙
280
281
282
283
284
285
286
287
288


289
290

283
284
285
286
287
288
289


290
291


292







-
-
+
+
-
-
+

	Object.assign(abc.get_glyphs(), abc2svg.mdnn.glyphs)
	Object.assign(abc.get_decos(), abc2svg.mdnn.decos)
	abc.add_style("\n.bn {font-family:sans-serif; font-size:15px}")
    }
} // mdnn

abc2svg.modules.hooks.push(abc2svg.mdnn.set_hooks)

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.mdnn.loaded = true
abc2svg.mhooks.mdnn = abc2svg.mdnn.set_hooks
Changes to modules/nns.js.
1
2
3
4

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

25
26
27
28
29
30



31



32
33
34
35
36
37
38
39
40
41
42
43
44
45







46
47
48
49
50
51
52
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

24
25
26
27
28
29

30
31
32
33
34
35
36
37
38
39
40
41
42
43


44
45
46


47
48
49
50
51
52
53
54
55
56
57
58
59
60



-
+



















-
+





-
+
+
+

+
+
+







-
-



-
-
+
+
+
+
+
+
+







// abc2svg - nns.js - module to output chords in the NNS
//			(Nashville Notation System)
//
// Copyright (C) 2021 Jean-Francois Moine
// Copyright (C) 2021-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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 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.  If not, see <http://www.gnu.org/licenses/>.
//
// This module is loaded when "%%nns" appears in a ABC source.
//
// Parameters
//	%%nns [n] [include=<list>] [nomusic] [repbrk] [roman]
//	%%nns [n] [include=<list>] [nomusic] [repbrk] [roman= 1 | 2]
//		<n> = number of chords per line (1: auto)
//			> 0: above the tune, < 0: under the tune
//		<list> = comma separated list of (continuous) measure numbers
//		'nomusic' displays only the chord
//		'repbrk' starts a new grid line on start/stop repeat
//		'roman' Roman Numeral Notation
//		'roman' display the chord in the Roman Numeral Notation
//			=1: uppercase letters with 'm' for minor chords (default)
//			=2: lowercase letters for minor chords
//	%%nnsfont font_name size (default: 'monospace 16')

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.nns = {
    note_nm: "CDEFGAB",

	// Nashville
    nns_nm: ["1", "♯1", "2", "♭3", "3", "4", "♯4",
		"5", "♯5", "6", "♭7", "7"],
    nns_nm_m: ["1", "♭2", "2", "3", "♯3", "4", "♭5",
		"5", "6", "♯6", "7", "♯7"],
	// Roman
    rnn_nm: ["I", "♯I", "II", "♭III", "III", "IV", "♯IV",
		"V", "♯V", "VI", "♭VII", "VII"],
    rnn_nm_m: ["I", "♭II", "II", "III", "♯III", "IV", "♭V",
		"V", "VI", "♯VI", "VII", "♯VII"],
    rnn_nm_m: ["III", "♯III", "IV", "♭V", "V", "VI", "♯VI",
		"VII", "♯VII", "I", "♭II", "II", "III"],
	// Roman 2
    rnn2_nm: ["I", "♯I", "ii", "♭III", "iii", "IV", "♯IV",
		"V", "♯V", "vi", "♭VII", "vii"],
    rnn2_nm_m: ["III", "♯III", "iv", "♭V", "v", "VI", "♯VI",
		"VII", "♯VII", "i", "♭II", "ii", "III"],
// inversions: 1st: (upper)6, 2nd: (upper)6 (lower) 4 

// generate the grid
    block_gen: function(of, s) {
	if (s.subtype != "nns") {
		of(s)
		return
︙
243
244
245
246
247
248
249

250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265

266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283

284
285
286
287
288
289
290
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273

274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291

292
293
294
295
296
297
298
299







+















-
+

















-
+








	abc.vskip(hr * nr + 6)
} // build_nns()

	// ----- block_gen() -----
    var	p_voice, n, font, f2

	abc.set_page()
	img = abc.get_img()

	// set the text style
	if (!cfmt.nnsfont)
		abc.param_set_font("nnsfont", "monospace 16")
	font = abc.get_font('nns')

	// create the chord list
	abc.blk_flush()
	build_nns(s, font)
	abc.blk_flush()
    }, // block_gen()

    // hook before the generation
    set_stems: function(of) {
    var	C, tsfirst, voice_tb, fmt, p_v, s, s2, mode,
    var	C, tsfirst, voice_tb, fmt, p_v, s, s2,
	abc = this,
	nns = abc.cfmt().nns

	function get_beat(s) {
	    var	beat = C.BLEN / 4

		if (!s.a_meter[0] || s.a_meter[0].top[0] == 'C'
		 || !s.a_meter[0].bot)
			return beat
		beat = C.BLEN / s.a_meter[0].bot[0] |0
		if (s.a_meter[0].bot[0] == 8
		 && s.a_meter[0].top[0] % 3 == 0)
			beat = C.BLEN / 8 * 3
		return beat
	} // get_beat()

	// transpose the chord back to "C"
	function set_nm(p, tr) {
	function set_nm(p, tr, mode) {
	    var	i, o, o2, a, n,
		csa = []

		i = p.indexOf('/')		// get the bass if any
		if (i > 0) {
			while (1) {
				if (p[i -1] != '<')
︙
317
318
319
320
321
322
323
324
325
326
327
328

329
330
331

332
333
334
335







336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356


357
358
359
360
361
362
363
364
365
366
367
368




369
370
371
372
373
374
375
376
377
378
379
380

381
382
383
384
385
386
387
326
327
328
329
330
331
332


333


334



335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365


366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394

395
396
397
398
399
400
401
402







-
-

-
-
+
-
-
-
+




+
+
+
+
+
+
+



















-
-
+
+












+
+
+
+











-
+







				a--
				o2++
			}
			n = ([0, 2, 4, 5, 7, 9, 11]
					[abc2svg.nns.note_nm.indexOf(p[o])]
				+ a
				+ tr) % 12
			if (mode)
				n = (n + 3) % 12
			if (!nns.roman) {
			   if (!mode)
				n = abc2svg.nns.nns_nm[n]	// major
				n = abc2svg.nns.nns_nm[n]	// major and minor
			   else
				n = abc2svg.nns.nns_nm_m[n]	// minor
			} else {
			} else if (nns.roman == 1) {
			   if (!mode)
				n = abc2svg.nns.rnn_nm[n]
			   else
				n = abc2svg.nns.rnn_nm_m[n]
			} else {
			   if (!mode)
				n = abc2svg.nns.rnn2_nm[n]
			   else
				n = abc2svg.nns.rnn2_nm_m[n]
				if (p[o2] == 'm')
					o2++
			}
			csa[i] = p.slice(0, o)
				+ n
				+ p.slice(o2)
		}
		return csa.join('/')
	} // set_nm()

	// build the arrays of chords and bars
	function build_chords(sb) {		// block 'nns'
	    var	s, i, w, bt, rep,
		bars = [],
		chords = [],
		parts = [],
		chord = [],
		beat = get_beat(voice_tb[0].meter),
		wm = voice_tb[0].meter.wmeasure,
		cur_beat = 0,
		beat_i = 0,
		tr = (tsfirst.p_v.key.k_sf + 12) * 5
					// transposition to "C"
		tr = (tsfirst.p_v.key.k_sf + 12) * 5,	// transposition to "C"
		mode = tsfirst.p_v.key.k_mode

		// scan all the symbols
		bars.push('|')
		for (s = tsfirst; s; s = s.ts_next) {
			while (s.time > cur_beat) {
				if (beat_i < 3)	// only 2, 3 or 4 beats / measure...
					beat_i++
				cur_beat += beat
			}
			if (s.part)
				parts[chords.length] = s.part.text
			switch (s.type) {
			case C.KEY:
				tr = (s.k_sf + 12) * 5
				mode = s.k_mode
				break
			case C.NOTE:
			case C.REST:
				if (!s.a_gch)
					break

				// search a chord symbol
				for (i = 0; i < s.a_gch.length; i++) {
					if (s.a_gch[i].type == 'g') {
						if (!chord[beat_i]) {
							chord[beat_i] =
							    set_nm(s.a_gch[i].text,
									tr)
									tr, mode)
						}
						break
					}
				}
				break
			case C.BAR:
				bt = s.bar_type
︙
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449

450
451
452
453
454
455
456







-








	// -------- set_stems --------

	// create a specific block
	if (nns) {
		C = abc2svg.C
		tsfirst = this.get_tsfirst()
		mode = tsfirst.p_v.key.k_mode
		fmt = tsfirst.fmt
		voice_tb = this.get_voice_tb()
		p_v = voice_tb[this.get_top_v()]
		s = {
			type: C.BLOCK,
			subtype: 'nns',
			dur: 0,
︙
499
500
501
502
503
504
505
506

507
508
509
510


511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526


527
528

513
514
515
516
517
518
519

520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540


541
542


543







-
+




+
+














-
-
+
+
-
-
+
			nns.n = 1
		}
		while (parm.length) {
			var item = parm.shift()
			if (item == "nomusic")
				nns.nomusic = true
			else if (item == "roman")
				nns.roman = true
				nns.roman = 1
			else if (item == "repbrk")
				nns.repbrk = true
			else if (item.slice(0, 8) == "include=")
				nns.ls = item.slice(8).split(',')
			else if (item.slice(0, -1) == "roman=")
				nns.roman = item.slice(-1) == "1" ? 1 : 2
		}
		this.cfmt().nns = nns
		return
	}
	of(cmd, parm)
    },

    set_hooks: function(abc) {
	abc.block_gen = abc2svg.nns.block_gen.bind(abc, abc.block_gen)
	abc.set_stems = abc2svg.nns.set_stems.bind(abc, abc.set_stems)
	abc.set_format = abc2svg.nns.set_fmt.bind(abc, abc.set_format)
    }
} // nns

abc2svg.modules.hooks.push(abc2svg.nns.set_hooks)

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.nns.loaded = true
abc2svg.mhooks.nns = abc2svg.nns.set_hooks
Changes to modules/page.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// page.js - module to generate pages
//
// Copyright (C) 2018-2022 Jean-Francois Moine
// Copyright (C) 2018-2024 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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.
︙
18
19
20
21
22
23
24



25
26
27
28

29
30
31
32
33
34
35

36
37

















38
39
40
41
42

43
44
45
46
47
48
49
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

64
65
66
67
68
69
70
71







+
+
+




+







+


+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+




-
+







// along with abc2svg.  If not, see <http://www.gnu.org/licenses/>.
//
// This module is loaded when "%%pageheight" appears in a ABC source.
//
// Parameters
//	%%pageheight <unit>

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.page = {

    // function called at end of generation
    abc_end: function(of) {
      if (this.cfmt().pageheight) {
    var page = this.page
	if (page && page.in_page)
		abc2svg.page.close_page(page)
	if (abc2svg.page.user_out) {
		user.img_out = abc2svg.page.user_out
		abc2svg.page.user_out = null
	}
      }
	of()
    }, // abc_end()

    // output the SVG tag
    svg_tag: function(w, h, ty) {
	w = Math.ceil(w)
	h = Math.ceil(h)
	abc2svg.page.user_out(
		'<svg xmlns="http://www.w3.org/2000/svg" version="1.1"\n\
 xmlns:xlink="http://www.w3.org/1999/xlink"\n\
 class="'
		+ ty + '" '
		+ (user.imagesize != undefined
			? (user.imagesize)
			: ('width="' + w + 'px" height="' + h + 'px"')
		)
		+ ' viewBox="0 0 ' + w + ' ' + h + '">'
	)
    }, // svg_tag()

    // generate a header or a footer in page.hf and return its height
    gen_hf: function(page, ty) {
    var	a, i, j, k, x, y, y0, s, str,
	font = page.abc.get_font(ty),
	font = page.abc.get_font(ty.substr(0, 6)),
	cfmt = page.abc.cfmt(),
	fh = font.size * 1.1,
	pos = [ '">',
		'" text-anchor="middle">',
		'" text-anchor="end">' ]

	// replace <>& by XML character references
︙
89
90
91
92
93
94
95


96

97
98
99
100
101
102
103
111
112
113
114
115
116
117
118
119

120
121
122
123
124
125
126
127







+
+
-
+







				if (c == 'D')
					d = new Date()
				if (cfmt.dateformat[0] == '"')
					cfmt.dateformat = cfmt.dateformat.slice(1, -1)
				d = strftime(cfmt.dateformat, d)
				break
			case 'F':
				d = typeof document != "undefined"
					? window.location.href
				d = page.abc.parse.fname
					: page.abc.parse.fname
				break
			case 'I':
				c = str[++i]
				s += c
				// fall thru
			case 'T':
				t = page.abc.info()[c]
︙
250
251
252
253
254
255
256


257
258
259
260
261
262
263

264

265
266
267
268
269
270
271

272
273
274
275
276

277
278
279
280
281

282
283
284
285
286
287
288
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290

291





292

293
294
295
296
297

298





299
300
301
302
303
304
305
306







+
+







+
-
+
-
-
-
-
-

-
+




-
+
-
-
-
-
-
+







	page.hmax = cfmt.pageheight - page.botmargin - ht

	// define the header/footer
	page.hf = ''
	if (page.header) {
		l = abc.get_font_style().length
		h = abc2svg.page.gen_hf(page, "header")
		if (!h && page.pn == 1 && page.header1)
			h = abc2svg.page.gen_hf(page, "header1")
		sty = abc.get_font_style().slice(l)		// new style(s)
		if (cfmt.fullsvg || sty != page.hsty) {
			page.hsty = sty
			sty = '<style>' + sty + '\n</style>\n'
		} else {
			sty = ''
		}
		abc2svg.page.svg_tag(cfmt.pagewidth, ht + h, "header")
		abc2svg.page.user_out(
		abc2svg.page.user_out(sty +
			'<svg xmlns="http://www.w3.org/2000/svg" version="1.1"\n\
	xmlns:xlink="http://www.w3.org/1999/xlink"\n\
	width="' + cfmt.pagewidth.toFixed(0) +
			'px" height="' + (ht + h).toFixed(0) +
			'px">\n' + sty +
			'<g transform="translate(0,' +
				page.topmargin.toFixed(1) + ')">' +
				page.topmargin.toFixed(1) + ')">\n' +
				page.hf + '</g>\n</svg>')
		page.hmax -= h;
		page.hf = ''
	} else {
		abc2svg.page.user_out(
		abc2svg.page.svg_tag(cfmt.pagewidth, ht, "header")
			'<svg xmlns="http://www.w3.org/2000/svg" version="1.1"\n\
	xmlns:xlink="http://www.w3.org/1999/xlink"\n\
	width="' + cfmt.pagewidth.toFixed(0) +
			'px" height="' + ht.toFixed(0) +
			'px">\n</svg>')
		abc2svg.page.user_out('\n</svg>')
	}
	if (page.footer) {
		l = abc.get_font_style().length
		page.fh = abc2svg.page.gen_hf(page, "footer")
		sty = abc.get_font_style().slice(l)		// new style(s)
		if (cfmt.fullsvg || sty != page.fsty) {
			page.fsty = sty
︙
299
300
301
302
303
304
305
306

307
308
309
310
311

312
313

314
315
316
317
318
319
320
317
318
319
320
321
322
323

324





325
326

327
328
329
330
331
332
333
334







-
+
-
-
-
-
-
+

-
+







    close_page: function(page) {
    var	h,
	cfmt = page.abc.cfmt()

	page.in_page = false
	if (page.footer) {
		h = page.hmax + page.fh - page.h
		abc2svg.page.user_out(
		abc2svg.page.svg_tag(cfmt.pagewidth, h, "footer")
			'<svg xmlns="http://www.w3.org/2000/svg" version="1.1"\n\
	xmlns:xlink="http://www.w3.org/1999/xlink"\n\
	width="' + cfmt.pagewidth.toFixed(0) +
			'px" height="' + h.toFixed(0) +
			'px">\n' + page.ffsty +
		abc2svg.page.user_out(page.ffsty +
			'<g transform="translate(0,' +
				(h - page.fh).toFixed(1) + ')">' +
				(h - page.fh).toFixed(1) + ')">\n' +
			page.hf + '</g>\n</svg>')
	}
	abc2svg.page.user_out('</div>')
	page.h = 0
    }, // close_page()

    // handle the output flow of the abc2svg generator
︙
396
397
398
399
400
401
402
403






404

405
406
407
408
409
410
411
410
411
412
413
414
415
416

417
418
419
420
421
422
423
424
425
426
427
428
429
430
431







-
+
+
+
+
+
+

+







		if (isNaN(v)) {
			this.syntax(1, this.errs.bad_val, '%%' + cmd)
			return
		}
		if (!user.img_out || !abc2svg.abc_end)
			v = 0
		cfmt.pageheight = v
		if (!v)
		if (!v) {
			if (abc2svg.page.user_out) {
				user.img_out = abc2svg.page.user_out
				abc2svg.page.user_out = null
			}
			delete this.page
			return
		}

		// if first definition, install the hook
		if (!page || !abc2svg.page.user_out) {
			this.page = page = {
				abc: this,
				topmargin: 38,	// 1cm
				botmargin: 38,	// 1cm
︙
421
422
423
424
425
426
427




428
429
430
431
432
433
434
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458







+
+
+
+







				page.header = cfmt.header;
				cfmt.header = null
			}
			if (cfmt.footer) {
				page.footer = cfmt.footer;
				cfmt.footer = null
			}
			if (cfmt.header1) {
				page.header1 = cfmt.header1
				cfmt.header1 = null
			}
			if (cfmt.header2) {
				page.header2 = cfmt.header2
				cfmt.header2 = null
			}
			if (cfmt.footer2) {
				page.footer2 = cfmt.footer2
				cfmt.footer2 = null
︙
464
465
466
467
468
469
470

471
472
473
474
475
476
477
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502







+







		}
		return
	}
	if (page) {
		switch (cmd) {
		case "header":
		case "footer":
		case "header1":
		case "header2":
		case "footer2":
			page[cmd] = parm
			return
		case "newpage":
			if (!parm)
				break
︙
503
504
505
506
507
508
509
510
511


512
513

528
529
530
531
532
533
534


535
536


537







-
-
+
+
-
-
+
    set_hooks: function(abc) {
	abc.set_format = abc2svg.page.set_fmt.bind(abc, abc.set_format)
	user.page_format = true			// do page formatting
	abc.set_pagef()
    }
} // page

abc2svg.modules.hooks.push(abc2svg.page.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.pageheight.loaded = true
abc2svg.mhooks.page = abc2svg.page.set_hooks
Changes to modules/pedline.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// pedline.js - module to draw pedal lines instead of 'Ped .. *'
//
// Copyright (C) 2020-2022 Jean-Francois Moine
// Copyright (C) 2020-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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.
︙
18
19
20
21
22
23
24



25
26
27

28
29
30
31
32
33
34
35
36

37

38
39
40

41
42
43


44
45
46
47
48









49
50
51



52
53
54
55
56
57
58
59
60
61
62
63

64

65
66





67
68
69
70

71
72
73
74
75









76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93


94
95

18
19
20
21
22
23
24
25
26
27
28
29

30
31
32
33
34
35
36
37
38
39
40

41

42
43
44
45
46
47
48
49





50
51
52
53
54
55
56
57
58
59


60
61
62
63
64
65
66
67
68
69
70
71
72
73

74
75
76


77
78
79
80
81
82
83
84
85
86





87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111


112
113


114







+
+
+


-
+









+
-
+
-


+



+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+

-
-
+
+
+











-
+

+
-
-
+
+
+
+
+




+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
















-
-
+
+
-
-
+
// along with abc2svg.  If not, see <http://www.gnu.org/licenses/>.
//
// This module is loaded when "%%pedline" appears in a ABC source.
//
// Parameters
//	%%pedline 1

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.pedline = {
    draw_all_deco: function(of) {
    var	de, i,
    var	de, i, x, dp, ds,
	a_de = this.a_de()

	if (!a_de.length)
		return			// no decoration in this music line
	if (this.cfmt().pedline) {
		for (i = 0; i < a_de.length; i++) {
			de = a_de[i]
			if (de.dd.name != "ped)")
				continue
			ds = de.start
			if (de.prev
			dp = de.prev
			 && de.prev.dd.name == "ped)") {
// ( .. ) ( .. )
//		\ de
//	  \ de.start
//	\ de.prev
// \ de.prev.start
// |_____/\____|
			if (dp && dp.dd.name == "ped)"
			 && dp.s.v == ds.s.v) {
				de.defl.nost = true
				de.prev.defl.noen = true
				de.x = de.prev.s.x - 5
				de.val = de.s.x - de.x - 5
				de.prev.val = de.x - de.prev.x
				de.defl.nost =		// /\
					dp.defl.noen = 2
				de.x = ds.s.x - 10
				de.val = de.s.x - ds.s.x - 3
				dp.val = de.x - dp.x

				if (de.y > dp.y)
					de.y = dp.y
				dp.y = de.y
			} else {
				de.x -= 3
				de.val += 10
				de.x = ds.s.x - 8
				if (!de.defl.noen)
					de.val = de.s.x - ds.s.x - de.s.wl
			}
		}
	}
	of()
    }, // draw_all_deco()

    out_lped: function(of, x, y, val, defl) {
	if (!this.cfmt().pedline) {
		of(x, y, val, defl)
		return
	}
	this.xypath(x, y + 16)
	this.xypath(x, y + 8)
	if (defl.nost) {
		if (defl.nost == 2) {		// \
		this.out_svg("l2.5 6")
		val -= 2.5
			this.out_svg("l2.5 6")
			val -= 2.5
		} else {
			this.out_svg("m0 6")
		}
	} else {
		this.out_svg("v6")
	}
	if (defl.noen) {
		if (defl.noen == 2) {		// /
		val -= 2.5
		this.out_svg("h" + val.toFixed(1) + 'l2.5 -6"/>\n')
	} else {
		this.out_svg("h" + val.toFixed(1) + 'v-6"/>\n')
	}
			val -= 2.5
			this.out_svg("h" + val.toFixed(1) + 'l2.5 -6')
		} else {
			this.out_svg("h" + val.toFixed(1))
		}
	} else {
		this.out_svg("h" + val.toFixed(1) + 'v-6')
	}
	this.out_svg('"/>\n')
    }, // out_lped()

    set_fmt: function(of, cmd, param) {
	if (cmd == "pedline")
		this.cfmt().pedline = this.get_bool(param)
	else
		of(cmd, param)
    }, // set_fmt()

    set_hooks: function(abc) {
	abc.draw_all_deco = abc2svg.pedline.draw_all_deco.bind(abc, abc.draw_all_deco)
	abc.out_lped = abc2svg.pedline.out_lped.bind(abc, abc.out_lped)
	abc.set_format = abc2svg.pedline.set_fmt.bind(abc, abc.set_format)
    } // set_hooks()
} // pedline

abc2svg.modules.hooks.push(abc2svg.pedline.set_hooks)

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.pedline.loaded = true
abc2svg.mhooks.pedline = abc2svg.pedline.set_hooks
Changes to modules/perc.js.
︙
23
24
25
26
27
28
29



30
31
32
33
34
35
36
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39







+
+
+







//	%%percmap ABC_note percussion [note_head]
// The percussion may be a number (MIDI percussion number range 35..81),
// a ABC note or a possibly abbreviated percussion name.
// See https://wim.vree.org/js2/tabDrumDoc.html for more information.

// Using this command creates a voicemap named "MIDIdrum".

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.perc = {

    // parse %%percmap
    do_perc: function(parm) {
    var	pits = new Int8Array([0, 0, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6]),
	accs = new Int8Array([3, 1, 3, -1, 3, 3, 1, 3, -1, 3, -1, 3])

︙
240
241
242
243
244
245
246
247
248


249
250

243
244
245
246
247
248
249


250
251


252







-
-
+
+
-
-
+

    set_hooks: function(abc) {
	abc.do_pscom = abc2svg.perc.do_pscom.bind(abc, abc.do_pscom);
	abc.set_vp = abc2svg.perc.set_vp.bind(abc, abc.set_vp)
    }
} // perc

abc2svg.modules.hooks.push(abc2svg.perc.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.percmap.loaded = true
abc2svg.mhooks.perc = abc2svg.perc.set_hooks
Changes to modules/psvg.js.
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18



19
20
21
22
23
24
25
1
2

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28


-
+















+
+
+







// psvg.js - small PS to SVG convertor for abc2svg

// Copyright (C) 2014-2021 Jean-Francois Moine
// Copyright (C) 2014-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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 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.  If not, see <http://www.gnu.org/licenses/>.

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

function Psvg(abcobj_r) {
    var	svgbuf = '',

// SVG functions - adapted from abcm2ps svg.c
	abcobj = abcobj_r,
	wps = new Wps(this),
︙
561
562
563
564
565
566
567
568

569

570
571
572
573
574
575
576
564
565
566
567
568
569
570

571
572
573
574
575
576
577
578
579
580







-
+

+







	wps.parse(script +
		(x / abcobj.stv_g().scale).toFixed(1) + ' ' + y.toFixed(1) + ' ' + f);
	ps_flush(true)			// + setg(0)
	return true
}

// try to generate a decoration by PS
Psvg.prototype.psdeco = function(f, x, y, de) {
Psvg.prototype.psdeco = function(x, y, de) {
	var	dd, de2, script, defl,
	f = de.dd.glyph,
		Os = wps.parse('/' + f + ' where'),
		A = Os.pop(),
	staff_tb = abcobj.get_staff_tb()

	if (!A)
		return false;
	defl = 0
︙
750
751
752
753
754
755
756
757

758
759
760

761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776


777
778

754
755
756
757
758
759
760

761
762
763

764
765
766
767
768
769
770
771
772
773
774
775
776
777
778


779
780


781







-
+


-
+














-
-
+
+
-
-
+
		}
		if (opt == 'nosvg')
			return
		if (!this.psvg)
			this.psvg = new Psvg(this);
		this.psvg.ps_eval.call(this.psvg, text)
	},
	psdeco: function(of, f, x, y, de) {
	psdeco: function(of, x, y, de) {
		if (!this.psvg)			// no %%beginps yet
			return false
		return this.psvg.psdeco.call(this.psvg, f, x, y, de)
		return this.psvg.psdeco.call(this.psvg, x, y, de)
	},
	psxygl: function(of, x, y, gl) {
		if (!this.psvg)
			return false
		return this.psvg.psxygl.call(this.psvg, x, y, gl)
	},

    set_hooks: function(abc) {
	abc.do_begin_end = abc2svg.psvg.do_begin_end.bind(abc, abc.do_begin_end);
	abc.psdeco = abc2svg.psvg.psdeco.bind(abc, abc.psdeco);
	abc.psxygl = abc2svg.psvg.psxygl.bind(abc, abc.psxygl)
    }
} // psvg

abc2svg.modules.hooks.push(abc2svg.psvg.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.beginps.loaded = true
abc2svg.mhooks.psvg = abc2svg.psvg.set_hooks
Changes to modules/roman.js.
1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







// abc2svg - roman.js - convert the chord symbols to the RNN
//			(Roman Numeral Notation)
//
// Copyright (C) 2021 Jean-Francois Moine
// Copyright (C) 2021-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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.
︙
21
22
23
24
25
26
27



28
29
30
31
32
33
34
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37







+
+
+







// This module is loaded by %%roman.
//
// Parameters
//	%%roman int
// <int>
//	 = '1': use uppercase letters with 'm' for minor chords
//	 = '2': user lowercase letters for minor chords

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.roman = {
    note_nm: "CDEFGAB",

    // chord names
    nm_M: ["I", "♯I", "II", "♭III", "III", "IV", "♯IV",
		"V", "♯V", "VI", "♭VII", "VII"],
︙
141
142
143
144
145
146
147
148
149



144
145
146
147
148
149
150


151
152
153







-
-
+
+
+
    set_hooks: function(abc) {
	abc.gch_build = abc2svg.roman.gch_build.bind(abc, abc.gch_build)
	abc.output_music = abc2svg.roman.o_mus.bind(abc, abc.output_music)
	abc.set_format = abc2svg.roman.set_fmt.bind(abc, abc.set_format)
    } // set_hooks()
} // roman

abc2svg.modules.hooks.push(abc2svg.roman.set_hooks)
abc2svg.modules.roman.loaded = true
if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
abc2svg.mhooks.roman = abc2svg.roman.set_hooks
Changes to modules/soloffs.js.
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23



24
25
26
27
28
29
30
1
2

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33


-
+




















+
+
+







// soloffs.js - module to set the X offset of some elements at start of music line
//
// Copyright (C) 2018-2021 Jean-Francois Moine
// Copyright (C) 2018-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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 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.  If not, see <http://www.gnu.org/licenses/>.
//
// Parameters
//	%%soloffs <type>=<offset> [<type>=<offset>]*
//		<type> is one of 'part', 'tempo' or 'space'
//		<offset> is the X offset from the start of staff

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.soloffs = {

    set_fmt: function(of, cmd, parm) {
	if (cmd == "soloffs") {
	    var	i, v,
		C = abc2svg.C,
︙
79
80
81
82
83
84
85
86
87


88
89

82
83
84
85
86
87
88


89
90


91







-
-
+
+
-
-
+

    set_hooks: function(abc) {
	abc.set_sym_glue = abc2svg.soloffs.set_sym_glue.bind(abc, abc.set_sym_glue);
	abc.set_format = abc2svg.soloffs.set_fmt.bind(abc, abc.set_format)
    }
} // soloffs

abc2svg.modules.hooks.push(abc2svg.soloffs.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.soloffs.loaded = true
abc2svg.mhooks.soloffs = abc2svg.soloffs.set_hooks
Changes to modules/sth.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// sth.js - module to set the stem heights
//
// Copyright (C) 2018-2021 Jean-Francois Moine
// Copyright (C) 2018-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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.
︙
20
21
22
23
24
25
26



27
28
29
30
31
32
33
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36







+
+
+







// This module is loaded when "%%sth" appears in a ABC source.
//
// Parameters
//	%%sth h1 h2 h3 ...
// The values h1, h2, .. are applied to the following notes which
// have a stem and which are not inside a beam.
// The value may be '*' for keeping the original stem length.

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.sth = {

// function called after beam calculation
    recal_beam: function(bm, s) {
    var staff_tb = this.get_staff_tb(),
	y = staff_tb[s.st].y,
︙
134
135
136
137
138
139
140
141
142


143
144

137
138
139
140
141
142
143


144
145


146







-
-
+
+
-
-
+
	abc.calculate_beam = abc2svg.sth.calculate_beam.bind(abc, abc.calculate_beam);
	abc.new_note = abc2svg.sth.new_note.bind(abc, abc.new_note);
	abc.set_format = abc2svg.sth.set_fmt.bind(abc, abc.set_format);
	abc.set_stems = abc2svg.sth.set_stems.bind(abc, abc.set_stems)
    }
} // sth

abc2svg.modules.hooks.push(abc2svg.sth.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.sth.loaded = true
abc2svg.mhooks.sth = abc2svg.sth.set_hooks
Changes to modules/strtab.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - strtab.js - tablature for string instruments
//
// Copyright (C) 2020-2022 Jean-Francois Moine
// Copyright (C) 2020-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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.
︙
30
31
32
33
34
35
36



37
38
39
40
41
42
43
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46







+
+
+







// The command %%minfret permits to force upper frets.
// Syntax:
//	%%minfret [ <string number> : <fret number> ]*
// Each command replaces the previous value.
//
// This module accepts Willem Vree's tablature syntax:
//	https://wim.vree.org/svgParse/abc2xml.html#tab

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.strtab = {

    // draw the tablature
    draw_symbols: function(of, p_v) {
    var	s, m, not, stb, x, y, g,
	C = abc2svg.C,
︙
204
205
206
207
208
209
210
211
























212
213




214

215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230

231
232
233
234
235
236
237
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244

245
246
247
248
249
250
251
252
253
254
255
256
257
258
259


260
261
262
263
264
265
266
267








+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


+
+
+
+
-
+














-
-
+







		case C.NOTE:
			draw_heads(stb, s)
			break
		}
	}
	abc.out_svg('</g>\n')
    }, // draw_symbols()

    // change the font size of the chord symbols
    csan_bld: function(of, s) {
	if (s.p_v.tab) {
	    var	i, gch,
		fmt = this.cfmt()

		for (i = 0; i < s.a_gch.length; i++) {
			gch = s.a_gch[i]
			if (gch.type != 'g')
				continue

			// create the smaller font if not done yet
			if (!fmt.cstabfont) {
			    var	f = gch.font

				this.param_set_font("cstabfont",
						f.name + ' ' + (f.size / 1.6).toFixed(1))
			}
			gch.font = this.get_font("cstab")
		}
	}
	of(s)
    }, // set_csan()

    // set a format parameter
    set_fmt: function(of, cmd, parm) {
	switch (cmd) {
	case "cstabfont":
		this.param_set_font("cstabfont", parm)
		return
	if (cmd == "strtab") {
	case "strtab":
		if (!parm)
			return
	    var	p_v = this.get_curvoice()
		if (!p_v) {
			this.parse.tab = parm
			return
		}
		this.set_v_param("clef", "tab")
		if (parm.indexOf("diafret") >= 0) {
			this.set_v_param("diafret", true)
			parm = parm.replace(/\s*diafret\s*/, "")
		}
		this.set_v_param("strings", parm)
		return
	}
	if (cmd == "minfret") {
	case "minfret":
		this.set_v_param("minfret", parm)
		return
	}
	of(cmd, parm)
    }, // set_fmt()

    // change the notes when the global generation settings are done
︙
388
389
390
391
392
393
394
395

396
397
398
399
400
401
402
418
419
420
421
422
423
424

425
426
427
428
429
430
431
432







-
+







		switch (s.type) {
		case C.KEY:
		case C.REST:
		case C.TIME:
			s.invis = true
		default:
			delete s.a_dd
			continue
			break
		case C.GRACE:
			if (p_v.pos.gst == C.SL_HIDDEN)
				s.sappo = 0
			for (g = s.extra; g; g = g.next) {
				if (p_v.pos.gst == C.SL_HIDDEN)
					g.stemless = true
				set_notes(p_v, g)
︙
642
643
644
645
646
647
648

649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669



672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698


699
700
701







+



















-
-
+
+
+
//		p_v.straightflags = true
	}
	of(a)
    }, // set_vp()

    set_hooks: function(abc) {
	abc.draw_symbols = abc2svg.strtab.draw_symbols.bind(abc, abc.draw_symbols)
	abc.gch_build = abc2svg.strtab.csan_bld.bind(abc, abc.gch_build)
	abc.set_format = abc2svg.strtab.set_fmt.bind(abc, abc.set_format);
	abc.set_stems = abc2svg.strtab.set_stems.bind(abc, abc.set_stems)
	abc.set_vp = abc2svg.strtab.set_vp.bind(abc, abc.set_vp)

	// define specific decorations used to force the string number
    var	decos = abc.get_decos()
	decos["1s"] = "0 nul 0 0 0"
	decos["2s"] = "0 nul 0 0 0"
	decos["3s"] = "0 nul 0 0 0"
	decos["4s"] = "0 nul 0 0 0"
	decos["5s"] = "0 nul 0 0 0"
	decos["6s"] = "0 nul 0 0 0"
	if (!user.nul)
		user.nul = function() {}

	abc.add_style("\n.bn{font:bold 7px sans-serif}")
    } // set_hooks()
} // strtab

abc2svg.modules.hooks.push(abc2svg.strtab.set_hooks)
abc2svg.modules.strtab.loaded = true
if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
abc2svg.mhooks.strtab = abc2svg.strtab.set_hooks
Changes to modules/temper.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// temper.js - module to define the temperament
//
// Copyright (C) 2018-2021 Jean-Francois Moine
// Copyright (C) 2018-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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.
︙
35
36
37
38
39
40
41



42
43
44
45
46
47
48
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51







+
+
+







// %%temperament +00 -24 -07 +10 -14 +03 -21 -03 -27 +10 +07 -17
//
// % Andreas Werckmeister III (1681)
// %%temperament +00 -04 +04 +00 -04 +04 +00 +02 -08 +00 +02 -02
//
// % well temperament (F.A. Vallotti 1754)
// %%temperament +00 -06 -04 -02 -08 +02 -08 -02 -04 -06 +00 -10

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.temper = {

    // get the temperament
    set_fmt: function(of, cmd, param) {
	if (cmd == "temperament") {
	    var	i, tb,
︙
77
78
79
80
81
82
83
84
85
86



87
88
80
81
82
83
84
85
86



87
88
89









-
-
-
+
+
+
-
-
    },

    set_hooks: function(abc) {
	abc.set_format = abc2svg.temper.set_fmt.bind(abc, abc.set_format)
    }
} // temper


abc2svg.modules.hooks.push(abc2svg.temper.set_hooks);

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
abc2svg.mhooks.temper = abc2svg.temper.set_hooks
// the module is loaded
abc2svg.modules.temperament.loaded = true
Changes to modules/tropt.js.
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21



22
23
24
25

26
27
28
29
30
31
32
1
2

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

28
29
30
31
32
33
34
35


-
+


















+
+
+



-
+







// tropt.js - module to optimize the notes after transposition
//
// Copyright (C) 2022 Jean-Francois Moine
// Copyright (C) 2022-2024 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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 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.  If not, see <http://www.gnu.org/licenses/>.
//
// This module is loaded when "%%tropt" appears in a ABC source.

if (typeof abc2svg == "undefined")
    var	abc2svg = {}

abc2svg.tropt = {

    // function called before start of the generation
    set_pitch: function(of, last_s) {
    voice_adj: function(of, last_s) {
	if (last_s) {			// if not first time
		of(last_s)
		return
	}
    var	v, p_v, s, m, nt, p, a, np, na,
	C = abc2svg.C,
	vo_tb = this.get_voice_tb(),
︙
49
50
51
52
53
54
55
56

57
58
59
60
61
62
63
52
53
54
55
56
57
58

59
60
61
62
63
64
65
66







-
+







			s = s.next
		}
		return 1 //true
	} // ok()

	for (v = 0; v < nv; v++) {
		p_v = vo_tb[v]
		if (!p_v.tropt || !p_v.key.k_none)
		if (!p_v.tropt || !p_v.ckey.k_none || !p_v.tr_sco)
			continue
		for (s = p_v.sym; s; s = s.next) {
			if (s.type != C.NOTE)
				continue
			for (m = 0; m <= s.nhd; m++) {
				nt = s.notes[m]
				if (nt.tie_s) {		// if end of tie
︙
113
114
115
116
117
118
119
120

121
122
123
124
125
126
127
116
117
118
119
120
121
122

123
124
125
126
127
128
129
130







-
+







					nt.pit = np
					nt.acc = na
				}
			}
		}
	}
	of(last_s)
    }, // set_pitch()
    }, // voice_adj()

    // set the tropt parameter
    do_pscom: function(of, text) {
	if (text.indexOf("tropt ") == 0)
		this.set_v_param("tropt", text.split(/[ \t]/)[1])
	else
		of(text)
︙
139
140
141
142
143
144
145
146

147
148
149
150
151
152


153
154

142
143
144
145
146
147
148

149
150
151
152
153


154
155


156







-
+




-
-
+
+
-
-
+
		}
	}
	of(a)
    }, // set_vp()

    set_hooks: function(abc) {
	abc.do_pscom = abc2svg.tropt.do_pscom.bind(abc, abc.do_pscom)
	abc.set_pitch = abc2svg.tropt.set_pitch.bind(abc, abc.set_pitch)
	abc.voice_adj = abc2svg.tropt.voice_adj.bind(abc, abc.voice_adj)
	abc.set_vp = abc2svg.tropt.set_vp.bind(abc, abc.set_vp)
    }
} // tropt

abc2svg.modules.hooks.push(abc2svg.tropt.set_hooks)

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
// the module is loaded
abc2svg.modules.tropt.loaded = 1 //true
abc2svg.mhooks.tropt = abc2svg.tropt.set_hooks
Changes to toabc.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - toabc.js - convert ABC to ABC
//
// Copyright (C) 2016-2022 Jean-Francois Moine
// Copyright (C) 2016-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
︙
491
492
493
494
495
496
497
498

499
500
501

502
503
504
505
506
507
508
509
510
511
512
513
514
515
491
492
493
494
495
496
497

498



499







500
501
502
503
504
505
506







-
+
-
-
-
+
-
-
-
-
-
-
-







		return ln
	} // meter_dump()

	function note_dump(s, note, tie_ch) {
	    var	p, j, sl, s2, a, d,
		ln = ""

		if (note.sls) {
		if (note.sl1)
			for (j = 0; j < note.sls.length; j++) {
				sl = note.sls[j];
				ln += slti_dump(sl.ty, '(')
			ln += slti_dump(note.sl1, '(')
				s2 = sl.note.s
				if (s2.sl2)
					s2.sl2++
				else
					s2.sl2 = 1
			}
		}
		if (note.a_dd)
			ln += deco_dump(note.a_dd)
		if (note.color)
			ln += "!" + note.color + "!"
		a = note.acc
		if (typeof a == "object") {
			d = a[1]
︙
736
737
738
739
740
741
742





743
744
745
746





747
748
749
750
751




752
753

754
755
756
757
758
759
760
727
728
729
730
731
732
733
734
735
736
737
738




739
740
741
742
743
744




745
746
747
748
749

750
751
752
753
754
755
756
757







+
+
+
+
+
-
-
-
-
+
+
+
+
+

-
-
-
-
+
+
+
+

-
+







					' ' + s.repeat_k + ']'
		}
		if (s.tp)
			tuplet_dump(s)
		if (s.sls) {
			for (i = 0; i < s.sls.length; i++) {
				sl = s.sls[i];
				if (sl.loc != 'i'
				 && !s.bar_type) {
					if (sl.nts)
						sl.nts.sl1 = sl.ty
					else
				line += slti_dump(sl.ty, '(')
				if (sl.is_note) {
					if (sl.note.sl2)
						sl.note.sl2++
						line += slti_dump(sl.ty, '(')
				}
				if (sl.nte) {
					if (sl.nte.sl2)
						sl.nte.sl2++
					else
						sl.note.sl2 = 1
				} else {
					if (sl.note.s.sl2)
						sl.note.s.sl2++
						sl.nte.sl2 = 1
				} else if (sl.se) {
					if (sl.se.sl2)
						sl.se.sl2++
					else
						sl.note.s.sl2 = 1
						sl.se.sl2 = 1
				}
			}
		}
		if (s.a_gch)
			gch_dump(s.a_gch)
		if (s.a_dd)
			line += deco_dump(s.a_dd)
︙
879
880
881
882
883
884
885



886
887
888



889
890
891
892
893
894
895
876
877
878
879
880
881
882
883
884
885



886
887
888
889
890
891
892
893
894
895







+
+
+
-
-
-
+
+
+







			break
		case C.STAVES:
			if (nv == 1)
				break
			staves_dump(s)
			break
		case C.STBRK:
			if (vo[v].length && vo[v].slice(-1) != '\n')
				line += '[I:staffbreak ' + s.xmx.toString() +
					(s.stbrk_forced ? ' f' : '') + ']'
			voice_out();
			abc2svg.print('%%staffbreak ' + s.xmx.toString() +
				(s.stbrk_forced ? 'f' : ''))
			else
				line += '%%staffbreak ' + s.xmx.toString() +
					(s.stbrk_forced ? ' f' : '') + '\n'
			break
		case C.BLOCK:
			voice_out();
			block_dump(s)
			break
		case C.REMARK:
			info_out('r:' + s.text)
︙
Changes to tohtml.js.
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20


21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

37
38
39
40
41
42
43
1
2

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45


-
+
















-
+
+
















+







// abc2svg - tohtml.js - HTML+SVG generation
//
// Copyright (C) 2014-2022 Jean-Francois Moine
// Copyright (C) 2014-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// abc2svg 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with abc2svg.  If not, see <http://www.gnu.org/licenses/>.

    var	init_done, pw, ml, mr, pkf, lkf, fn
    var	init_done, pw, ml, mr, pkf, lkf, fn,
	h_sty = ""

// replace <>& by XML character references
function clean_txt(txt) {
	return txt.replace(/<|>|&.*?;|&/g, function(c) {
		switch (c) {
		case '<': return "&lt;"
		case '>': return "&gt;"
		case '&': return "&amp;"
		}
		return c
	})
}

abc2svg.abort = function(e) {
	if (!init_done)				// if empty document
		user.img_out('')
	abc.parse.state = 0			// force block flush
	abc.blk_flush()
	if (typeof abc2svg.printErr == 'function')
		abc2svg.printErr(e.message + "\n*** Abort ***\n" + e.stack)
	else
		abc2svg.print("<pre>" + e.message + "\n*** Abort ***\n" + e.stack + "</pre>")
	abc2svg.abc_end()
	abc2svg.quit()
︙
178
179
180
181
182
183
184


185
186
187




188
189
190
191
192
193
194
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202







+
+



+
+
+
+







		abc2svg.print('</table>')
	}

	user.page_format = true

	// output the html header
	user.img_out = function(str) {
		if (!str)
			return
		if (init_done) {
			abc2svg.print(str)
			return
		}
		if (/^<style>[^<]+<\/style>$/.test(str)) {
			h_sty = str.replace(/^<style>\n|<\/style>$/g,'')
			return
		}

		var	header = cfmt.header,
			footer = cfmt.footer,
			topmargin = cfmt.topmargin || "1cm",
			botmargin = cfmt.botmargin || "1cm",
			media_s = '@media print {\n\
︙
251
252
253
254
255
256
257
258

259
260
261
262
263
264
265
266
267
268
269

270
271
272
273
274
275
276
259
260
261
262
263
264
265

266
267
268
269
270
271
272
273
274
275
276

277
278
279
280
281
282
283
284







-
+










-
+







			((header || footer) ? media_f : media_s))
// important for chrome and --headless (abctopdf)
		if (abc.page)
			abc2svg.print('@page{size:' +
				(cfmt.pagewidth / 96).toFixed(2) + 'in ' +
				(cfmt.pageheight / 96).toFixed(2) + 'in;margin:0}')

		abc2svg.print('</style>\n\
		abc2svg.print(h_sty + '</style>\n\
<title>' + fn.replace(/.*\//,'')
			+ '</title>\n\
<body>')
		if (header || footer) {
			if (header)
				gen_hf("header", header)
			if (footer)
				gen_hf("footer", footer)

			abc2svg.print('\
<table style="margin:0">\n\
<table style="margin:0" width="100%">\n\
  <thead><tr><td>\n\
    <div class="h-sp">&nbsp;</div>\n\
  </td></tr></thead>\n\
  <tbody><tr><td>')
			init_done = 2		// with header/footer
		} else {
			init_done = 1
︙
Changes to tonotes.js.
︙
57
58
59
60
61
62
63
64

65
66
67
68
69
70
71
57
58
59
60
61
62
63

64
65
66
67
68
69
70
71







-
+







		tgen: 3600, 	// generate by (for) 1 hour
		get_time: function() { return -.3},	// (move the time origin)
		midi_ctrl: function(po, s, t) {
			abc2svg.print(' v:' + s.v
					+ '  MIDI control ' + s.ctrl + ' ' + s.val)
		}, // midi_ctrl()
		midi_prog: function(po, s) {
			if (s.instr)
			if (s.instr != undefined)
				abc2svg.print(' v:' + s.v
					+ '  MIDI program '
					+ (s.chn + 1) + ' '
					+ s.instr)
			else
				abc2svg.print(' v:' + s.v
					+ '  MIDI channel ' + (s.chn + 1))
︙
Changes to toodt.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - toodt.js - ABC translation to ODT+SVG
//
// Copyright (C) 2017-2019 Jean-Francois Moine
// Copyright (C) 2017-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
︙
29
30
31
32
33
34
35

36
37
38
39
40
41
42
43
44
















45
46
47
48
49
50
51
29
30
31
32
33
34
35
36
37
38
39
40





41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63







+




-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







//
// Constraints:
// This module runs only with the nodeJS script 'abc2svg' and asks for
// the npm module 'jszip' to be installed.

    var	margins, page_size, page_type, page_left, page_mid, page_right,
	header, footer, headerfont, footerfont, in_p, t_info, title,
	init_done,
	style = '',
	content = '',
	imgs = '',
	seq = 0,
	outfn = 'abc.odt',
	fs = require('fs'),		// file system
	JSZip = require('jszip'),	// Zip
	zip = new JSZip(),
	sep = require('path').sep;	// '/' or '\'
	outfn = 'abc.odt'

	if (typeof std != "undefined") {	// quickjs
		zip = {
		    file: function(fn, p) {
		    var	f = std.open("/tmp/odt/" + fn, "w")
			f.puts(p)
			f.close()
		    }
		}
	} else  {				// nodejs ?
	    var	fs = require('fs'),		// file system
		JSZip = require('jszip'),	// Zip
		zip = new JSZip(),
		sep = require('path').sep	// '/' or '\'
	}

// get the command line arguments
function get_args(args) {
    var	a, i

	if (!args)			// compatibility
		return
︙
210
211
212
213
214
215
216



217
218
219
220
221
222
223
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238







+
+
+







		content + '\
 </office:text>\n\
</office:body>\n\
</office:document-content>\n',
		{ compression: "DEFLATE" });

	// Fonts/abc2svg.ttf
	if (typeof std != "undefined")		// quickjs
		os.exec(["cp", path + '/abc2svg.ttf', '/tmp/odt/Fonts/abc2svg.ttf'])
	else
	zip.file('Fonts/abc2svg.ttf',
		fs.readFileSync(__dirname + sep + 'abc2svg.ttf'),
		{ compression: "STORE" });

// manifest.rdf (?)

	// META-INF/manifest.xml
︙
339
340
341
342
343
344
345










346
347
348
349
350

351
352
353
354
355
356
357
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383







+
+
+
+
+
+
+
+
+
+





+







	(footer || '') + '\
  </style:master-page>\n\
 </office:master-styles>\n\
</office:document-styles>',
		{ compression: "DEFLATE" });

// - generate the ODT file
	if (typeof os != "undefined") {
		if (outfn[0] != '/')
			outfn = os.getcwd() + outfn
		os.exec(["zip", "-0", "-X", outfn,
			"mimetype", "Fonts/abc2svg.ttf"],
			{cwd: "/tmp/odt"})
		os.exec(["zip", "-r", outfn,
			".", "-x", "mimetype", "Fonts/abc2svg.ttf"],
			{cwd: "/tmp/odt"})
	} else {
	zip	.generateNodeStream({streamFiles:true})
		.pipe(fs.createWriteStream(outfn))
		.on('finish', function () {
			console.log(outfn + ' created')
		})
	}
}

abc2svg.abort = function(e) {
	abc.blk_flush();
	if (typeof abc2svg.printErr == 'function')
		abc2svg.printErr(e.message + "\n*** Abort ***\n" + e.stack)
	else
︙
524
525
526
527
528
529
530









531
532
533
534
535
536
537
538
539
540
541
542
543






544
545
546
547
548
549
550
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591







+
+
+
+
+
+
+
+
+













+
+
+
+
+
+







}

// entry point from cmdline
abc2svg.abc_init = function(args) {
	console.log('ODT generation started');

	get_args(args);

	// create the odt hierarchy and clear the odt out file
	if (typeof std != "undefined") {
		os.exec(["rm", "-r", "/tmp/odt", outfn])
		os.mkdir("/tmp/odt")
		os.mkdir("/tmp/odt/Fonts")
		os.mkdir("/tmp/odt/META-INF")
		os.mkdir("/tmp/odt/Pictures")
	}

	// generate mimetype which is the first item and without compression
	zip.file('mimetype',
		'application/vnd.oasis.opendocument.text',
		{ compression: "STORE" });

	// define some functions in the Abc object
	abc.tosvg("toodt", "\
%%fullsvg 1\n\
%%musicfont abc2svg")

	// get the page parameters
	user.img_out = function(str) {
		if (init_done) {
			svg_out(str)
			return
		}
		init_done = 1

	    var cfmt = abc.cfmt(),
		pw = cfmt.pagewidth;

		// page size
		if (pw > 800) {
			page_type = 'Letter';
			page_size = 'fo:page-width="8.5in" fo:page-height="11in"';
︙
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
607
608
609
610
611
612
613



614
615
616
617
618
619
620
621







-
-
-








		    margins = 'fo:margin-top="' +
			set_unit(cfmt.topmargin || 37.8) +
			'" fo:margin-bottom="' +
			set_unit(cfmt.botmargin || 37.8) + '"';

		// output the first generated string
		svg_out(str);

		// change the output function
		user.img_out = svg_out
	}

	user.page_format = true
}

abc2svg.abc_end = function() {
	odt_out()
}
Changes to util/abcweb.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abcweb-1.js file to include in html pages
//
// Copyright (C) 2014-2022 Jean-Francois Moine
// Copyright (C) 2014-2023 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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.
︙
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
171
172
173
174
175
176
177

178
179
180
181
182
183
184







-







					+ s.getPropertyValue(k)
					+ '\n'
		}
		return o
	} // get_p()

	// move the musique sequences to <script> text/vnd.abc
	//	<mei> .. </mei>
	//	<anytag .. class="abc" .. > ..ABC.. </anytag>
	//	%abc-n ..ABC.. '<' with skip %%beginxxx .. %%endxxx
	//	X:n ..ABC.. '<' with skip %%beginxxx .. %%endxxx
	function move_music(src) {
	    var	re, res, i, j, k, t,
		re_stop = /\n<|\n%.begin[^\s]+/g,
		ss = 0,
︙
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
242
243
244
245
246
247
248

















249
250
251
252
253
254
255







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







		document.body.innerHTML = out
	} // move_music()

	// save the music sequences and replace them by empty <div>'s
	function save_music() {
	    var i, k, div, c, s, sa

		// save MEI sequences
		function save_spe(ty) {
		    var	s, div
			while (1) {
				s = document.getElementsByTagName(ty)[0]
				if (!s)
					break
				div = document.createElement('div')
				abc2svg.music.push({
					n: 'mus' + abc2svg.music.length,
					t: s.outerHTML,
					d: div
				})
				s.parentNode.replaceChild(div, s)
			}
		} // save_spe()

		// get the global parameters
		abc2svg.music = [{
			t: "",			// global parameters
			n: "mus0"
		}]

		// get the parameters from the query string of the URL
︙
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
285
286
287
288
289
290
291



292
293
294
295
296
297
298







-
-
-







					n: "mus" + abc2svg.music.length,
					t: c + s.innerHTML,
					d: div
				})
			}
			s.parentNode.replaceChild(div, s)
		}

		// special treatment for MEI
		save_spe('mei')
	} // save_music()

	// generate a music sequence
	// @mu = object { t: music source, d: <div> }
	function musgen(mu) {
	    var	t = mu.t

︙
328
329
330
331
332
333
334




335
336
337
338
339
340
341
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324







+
+
+
+







		    var	i, j, e

			// start the generation
			outb = err = ""
			abc.tosvg(mu.n, t)	// music source

			abc2svg.abc_end()	// close the page if %%pageheight

			// mu.d can be null when parameters in query string
			// and no ABC script with global parameters
		    if (mu.d) {

			if (err)
				outb += '<pre class="nop" style="background:#ff8080">'
					+ err + "</pre>\n"

			if (abc.cfmt().with_source && outb)
				outb = '<pre class="source">'
︙
355
356
357
358
359
360
361

362
363
364
365
366
367
368
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352







+







					continue	// (page formatting)
				j = j.match(/tune(\d+)/)
				if (!j)
					continue
				j = j[1]		// tune number
				tune_lst[j] = null	// get new play references
			}
		    } // if (mu.d)

			// if some generation waiting, start it
			mu.w = busy = 0 //false
			for (i = 1; i < abc2svg.music.length; i++) {
				if (abc2svg.music[i].w) {
					musgen(abc2svg.music[i])
					break
︙
411
412
413
414
415
416
417
418
419


420
421
422
423
424
425
426
395
396
397
398
399
400
401


402
403
404
405
406
407
408
409
410







-
-
+
+







			r.send()
		} // include()

		// load the required modules and the include files before rendering
		if (abc2svg.modules.load(t, include))
			include()
	} // musgen()
//test
abc2svg.musgen = musgen

abc2svg.musgen = musgen			// used in set_music() below

// -- abc2svg init argument
    user = {
	read_file: function(fn) {
		return a_inc[fn]
	}, // read_file()
	errmsg: function(msg, l, c) {	// get the errors
︙
517
518
519
520
521
522
523
524
525
526

527
528
529
530
531
532
533
534
535
536
537
538
539
540

541
542

543
544
545
546
547
548
549
550
551
552
553
554
555
556
501
502
503
504
505
506
507



508

509
510
511
512
513
514
515
516
517
518
519
520

521


522







523
524
525
526
527
528
529







-
-
-
+
-












-
+
-
-
+
-
-
-
-
-
-
-







	} // playseq()

	// --- dom_loaded() main code ---

	// load the abc2svg core if not done by <script>
	src = document.body.innerHTML
	if (!abc2svg.Abc) {
		abc2svg.loadjs(src.indexOf("<mei ") >= 0 ?
					"mei2svg-1.js" :
					"abc2svg-1.js",
		abc2svg.loadjs("abc2svg-1.js", dom_loaded)
						dom_loaded)
		return
	}

	if (src.indexOf('type="text/vnd.abc"') < 0)
		move_music(src)

	save_music()	// save the music sequences and replace them by <div>

	// initialize the generation
	abc = new abc2svg.Abc(user)
	if (typeof follow == "function")	// if snd-1.js loaded
		follow(abc, user, playconf)	// initialize the play follow
	if (abc2svg.music[0].t) {
	if (abc2svg.music[0].t)
		abc.tosvg(abc2svg.music[0].n,	// global definitions
			  abc2svg.music[0].t)
		musgen(abc2svg.music[0])	// global definitions
		if (abc.cfmt().with_source
		 && abc.cfmt().with_source.indexOf('nohead') < 0) {
			abc2svg.music[0].d.innerHTML = '<pre class="source">'
					+ clean_txt(abc2svg.music[0].t)
					+ '</pre>\n'
		}
	}

	// create a list of all <div>'s
	abc2svg.alldiv = []
	for (var i = 1; i < abc2svg.music.length; i++)
		abc2svg.alldiv.push(abc2svg.music[i])
	visible()
} // dom_loaded()
︙
Changes to util/chord.js.
︙
32
33
34
35
36
37
38
39

40
41
42
43
44
45
46
32
33
34
35
36
37
38

39
40
41
42
43
44
45
46







-
+







	m7b5:	["C-b-e g ", "e-C g b ", "g-e b C+", "b-e g C+"],
	M7:	["C-B-E G ", "E-C G B ", "G-E B C+", "B-E G C+"],
	'6':	["C-A-E G ", "E-C A B ", "A-E B C+", "B-E A C+"],
	m6:	["C-A-e G ", "e-C A B ", "A-e B C+", "B-e A C+"],
	aug:	["C-E a C+", "E-C a C+", "a-C E a "],
//	plus:	["C-E a C+", "E-C a C+", "a-C E a "],
	aug7:	["C-b-E a ", "E-C a b ", "a-E b C+", "b-E a C+"],
	dim:	["C-E g C+", "E-C g C+", "g-C E g "],
	dim:	["C-e g C+", "e-C g C+", "g-C e g "],
	dim7:	["C-e g A ", "e-C g A ", "g-e A C+", "A-C e G "],
	'9':	["C-b-E G D+", "E-C G b D+", "G-E b C+D+", "b-E G C+D+", "D-G-C E b "],
	m9:	["C-b-e G D+", "e-C G b D+", "G-e b C+D+", "b-e G C+D+", "D-G-C e b "],
	maj9:	["C-B-E G D+", "E-C G B D+", "G-E B C+D+", "B-E G C+D+", "D-G-C E B "],
	M9:	["C-B-E G D+", "E-C G B D+", "G-C E B D+", "B-E G C+D+", "D-G-C E B "],
	'11':	["C-b-E G D+F+", "E-C G b D+F+", "G-E b C+D+F+", "b-E G C+D+F+",
						"D-G-C E b F+", "F-D-G-C E b D+"],
︙
238
239
240
241
242
243
244


245
246
247
248
249
250
251
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253







+
+







			instr: cfmt.chord.prog || 0,
			time: 0,
			ts_prev: first,
			ts_next: first.ts_next
		},
		vol: cfmt.chord.vol || .6	// (external default 76.2)
	}
	vch.sym.p_v = vch
	vch.sym.v = vch.v
	vch.last_sym = vch.sym
	voice_tb.push(vch)
	first.ts_next = vch.sym

	// loop on the symbols and add the accompaniment chords
	gchon = cfmt.chord.gchon
	s = first
︙
Changes to util/sndaud.js.
︙
299
300
301
302
303
304
305
306

307
308
309
310


311
312
313


314
315

316
317
318
319
320
321
322
299
300
301
302
303
304
305

306
307
308


309
310
311


312
313
314

315
316
317
318
319
320
321
322







-
+


-
-
+
+

-
-
+
+

-
+








		// scan from the beginning of the tune
		s = s.p_v.sym
		while (s.ts_prev)
			s = s.ts_prev

		for ( ; s; s = s.ts_next) {
			if (s.v < nv) {			// if new voice
			if (s.v > nv) {			// if new voice
				nv = s.v
				bk[nv] = 0		// bank 0
				if (p_v.midictl) {
					if (p_v.midictl[0])	// MSB
				if (s.p_v.midictl) {
					if (s.p_v.midictl[0])	// MSB
						bk[s.v] = (bk[s.v] & ~0x1fc000)
								+ (p_v.midictl[0] << 14)
					if (p_v.midictl[32])	// LSB
								+ (s.p_v.midictl[0] << 14)
					if (s.p_v.midictl[32])	// LSB
						bk[s.v] = (bk[s.v] & ~0x3f80)
								+ (p_v.midictl[32] << 7)
								+ (s.p_v.midictl[32] << 7)
				}
			}
			switch (s.subtype) {
			case "midiprog":
				break
			case "midictl":
				if (s.ctrl != 0 && s.ctrl != 32)
︙
344
345
346
347
348
349
350
351

352
353
354
355
356
357
358
344
345
346
347
348
349
350

351
352
353
354
355
356
357
358







-
+







				i += bk[s.v]		// bank number
			if (!params[i]) {
				params[i] = []		// instrument being loaded
				f(i, sf2par, sf2pre)	// sf2_create or load_instr
			}
		}
		nv = (2 << nv) - 1
		if (!(nv & vb)			// if some voice(s) without instrument
		if (nv != vb			// if some voice(s) without instrument
		 && !params[0]) {
			params[0] = []		// load the piano
			f(0, sf2par, sf2pre)
		}
	} // def_instr()

	// load the needed instruments
︙
367
368
369
370
371
372
373

374
375
376
377


378
379
380
381


382
383
384
385
386
387
388
389
390
391
392
393
394


395
396
397


398
399
400
401
402


403
404
405
406
407
408
409
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420







+




+
+




+
+













+
+



+
+





+
+







				parser = new sf2.Parser(b64dcod(abc2svg.sf2))
				parser.parse()
				presets = parser.getPresets()
			}

		// load the soundfont if not done yet
		} else if (!parser) {
		    w_instr++
		    if (conf.sfu.slice(-3) == ".js") {
			abc2svg.loadjs(conf.sfu,
				function() {
					load_res(s)	// load the instruments
					if (--w_instr == 0)
						play_start()
				},
				function() {
					errmsg('could not load the sound file '
						+ conf.sfu)
					if (--w_instr == 0)
						play_start()
				})
			return
		    }
		    var	r = new XMLHttpRequest()	// .sf2
			r.open('GET', conf.sfu, true)
			r.responseType = "arraybuffer"
			r.onload = function() {
				if (r.status === 200) {
					parser = new sf2.Parser(
							new Uint8Array(r.response))
					parser.parse()
					presets = parser.getPresets()
					load_res(s)	// load the instruments
					if (--w_instr == 0)
						play_start()
				} else {
					errmsg('could not load the sound file '
						+ conf.sfu)
					if (--w_instr == 0)
						play_start()
				}
			}
			r.onerror = function() {
					errmsg('could not load the sound file '
						+ conf.sfu)
				if (--w_instr == 0)
					play_start()
			}
			r.send()
			return
		}

		// create the instruments and start playing
		def_instr(s, sf2_create, parser, presets)
︙
563
564
565
566
567
568
569
570

571
572
573
574
575
576
577
574
575
576
577
578
579
580

581
582
583
584
585
586
587
588







-
+







		// This is needed for iPhone/iPad/...
		function play_unlock() {
		    var buf = ac.createBuffer(1, 1, 22050),
			src = ac.createBufferSource()

			src.buffer = buf
			src.connect(ac.destination)
			src.noteOn(0)
			src.start(0)
		}

		// initialize the audio subsystem if not done yet
		if (!gain) {
			ac = conf.ac
			if (!ac) {
				conf.ac = ac = new (window.AudioContext ||
︙
Changes to util/sndgen.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// sndgen.js - sound generation
//
// Copyright (C) 2019-2023 Jean-Francois Moine
// Copyright (C) 2019-2024 Jean-Francois Moine
//
// This file is part of abc2svg.
//
// abc2svg 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.
︙
47
48
49
50
51
52
53





































































































54
55
56
57
58
59
60
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







	i, n, dt, d, v,
	s = first,
	rst = s,		// left repeat (repeat restart)
	rst_fac,		// play factor on repeat restart
	rsk = [],		// repeat variant array (repeat skip)
	b_tim,			// time of last measure bar
	b_typ			// type of last measure bar

	function get_beat() {
	    var	s = first.p_v.meter

		if (!s.a_meter[0])
			return C.BLEN / 4
		if (!s.a_meter[0].bot)
			return (s.a_meter[1]
				&& s.a_meter[1].top == '|')	// (cut time)
					? C.BLEN / 2 : C.BLEN / 4
		if (s.a_meter[0].bot == "8"
		 && s.a_meter[0].top % 3 == 0)
			return C.BLEN / 8 * 3
		return C.BLEN / s.a_meter[0].bot | 0
	} // get_beat()

	// create the starting beats
	function def_beats() {
	    var	i, s2, s3, tim,
		beat = get_beat(),		// time between two beats
		d = first.p_v.meter.wmeasure,	// duration of a measure
		nb = d / beat | 0,		// number of beats in a measure
		v = voice_tb.length,		// beat voice number
		p_v = {				// voice for the beats
			id: "_beats",
			v: v,
//			time:
			sym: {
				type: C.BLOCK,
				v: v,
//				p_v: p_v,
				subtype: "midiprog",
				chn: 9,			// percussion channel
				instr: 16384,	// percussion bank
//				time:
//				next:
				ts_prev: first
//				ts_next: 
			}
//			vol:
		},
		s = {
			type: C.NOTE,
			v: v,
			p_v: p_v,
//			time:
			dur: beat,
			nhd: 0,
			notes: [{
				midi: 37	// Side Stick
			}]
		}

		abc_time = -d			// start time of the beat ticks

		// check for an anacrusis
		for (s2 = first; s2; s2 = s2.ts_next) {
			if (s2.bar_type && s2.time) {
				nb = (2 * d - s2.time) / beat | 0
				abc_time -= d - s2.time
				break
			}
		}

		// add the tempo
		s2 = p_v.sym			// midiprog
		for (s3 = first; s3 && !s3.time; s3 = s3.ts_next) {
			if (s3.type == C.TEMPO) {
				s3 = Object.create(s3)	// new tempo
				s3.v = v
				s3.p_v = p_v
				s3.prev =
					s3.ts_prev = s2
				s2.next =
					s2.ts_next = s3
				s2 = s3
				play_fac = set_tempo(s2)
				break
			}
		}

		voice_tb[v] = p_v
		p_v.sym.p_v = p_v
		first.time = s2.time = tim = abc_time
		if (s3)
			p_v.sym.time = tim
		for (i = 0; i < nb; i++) {
			s3 = Object.create(s)	// new beat tick
			s3.time = tim
			s3.prev = s2
			s2.next = s3
			s3.ts_prev = s2
			s2.ts_next = s3
			s2 = s3
			tim += beat
		}
		s2.ts_next = first.ts_next
		s2.ts_next.ts_prev = s2
		first.ts_next = p_v.sym
		rst = s2.ts_next
	} // def_beats()

	// build the information about the parts (P:)
	function build_parts(first) {
	    var	i, j, c, n, v,
		s = first,
		p = s.parts,
		st = [],
︙
183
184
185
186
187
188
189
190

191
192




193
194
195
196
197
198
199
284
285
286
287
288
289
290

291
292
293
294
295
296
297
298
299
300
301
302
303
304







-
+


+
+
+
+







			else if (d != ',')
				rsk.push(s)	// last
		}
	} // set_variant()

	// add() main

	// if some MIDI stuff, load the associated module
	// if some chord stuff, set the accompaniment data
	if (cfmt.chord)
		abc2svg.chord(first, voice_tb, cfmt)

	// if %%playbeats, create the sounds
	if (cfmt.playbeats)
		def_beats()

	if (s.parts)
		build_parts(s)

	// set the time parameters
	rst_fac = play_fac
	while (s) {
︙
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267











268
269
270


271
272
273
274
275
276
277
357
358
359
360
361
362
363









364
365
366
367
368
369
370
371
372
373
374



375
376
377
378
379
380
381
382
383







-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+







				 && rst.bar_type.slice(-1) != ':')
					rst.bar_type += ':' // restart confirmed
				set_variant(s)
				rst_fac = play_fac
			    }

			// left repeat
			} else if (s.rbstop == 2) {
				if (s.bar_type.slice(-1) == ':') {
					if (b_typ & 4)
						break
					b_typ |= 4
				} else {
					if (b_typ & 8)
						break
					b_typ |= 8
			} else if (s.bar_type.slice(-1) == ':') {
				if (b_typ & 4)
					break
				b_typ |= 4
				rst = s			// new possible restart
				rst_fac = play_fac
// fixme: does not work when |1 split at end of line
//			} else if (s.rbstop == 2) {
//				if (b_typ & 8)
//					break
//				b_typ |= 8
				}
				rst = s			// new possible restart
				rst_fac = play_fac
//				rst = s			// new possible restart
//				rst_fac = play_fac
			}
			break
		case C.GRACE:
			if (s.time == 0		// if before beat at start time
			 && abc_time == 0) {
				dt = 0
				if (s.sappo)
︙
395
396
397
398
399
400
401
402

403
404
405
406
407
408
409
410
501
502
503
504
505
506
507

508

509
510
511
512
513
514
515







-
+
-







	// set the MIDI controls up to now
	function set_ctrl(po, s2, t) {
	    var	i,
		p_v = s2.p_v,
		s = {
			subtype: "midictl",
			p_v: p_v,
			v: p_v.v,
			v: s2.v
			chn: p_v.chn
		}

		for (i in p_v.midictl) { // MIDI controls at voice start time
			s.ctrl = Number(i)
			s.val = p_v.midictl[i]
			po.midi_ctrl(po, s, t)
		}
︙
549
550
551
552
553
554
555
556

557
558
559
560
561
562
563
654
655
656
657
658
659
660

661
662
663
664
665
666
667
668







-
+







				} else {
					s = po.s_end
				}
				po.repv = 1
			}
			break
		}
	    if (s && s != po.s_end) {
	    if (s && s != po.s_end && !s.noplay) {
		switch (s.type) {
		case C.BAR:
			break
		case C.BLOCK:
			if (s.subtype == "midictl")
				po.midi_ctrl(po, s, t)
			else if (s.subtype == 'midiprog')
︙
Changes to util/sndmid.js.
︙
92
93
94
95
96
97
98
99

100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

116
117


118
119
120
121
122
123
124
125
126
127








128
129
130
131
132
133
134
92
93
94
95
96
97
98

99
100
101
102
103
104
105
106
107
108
109



110
111

112
113
114
115
116
117
118
119
120
121
122




123
124
125
126
127
128
129
130
131
132
133
134
135
136
137







-
+










-
-
-


-
+


+
+






-
-
-
-
+
+
+
+
+
+
+
+







		}
		po.op.send(new Uint8Array([0x90 + c, k, 127]), t)	// note on
		po.op.send(new Uint8Array([0x80 + c, k, 0]), t + d - 20) // note off
	} // note_run()

	// send a MIDI control
	function midi_ctrl(po, s, t) {
		po.op.send(new Uint8Array([0xb0 + s.chn,
		po.op.send(new Uint8Array([0xb0 + po.v_c[s.v],
					s.ctrl, s.val]),
			t * 1000)
	} // midi_ctrl()

	// change the channel and/or send a MIDI program	
	function midi_prog(po, s) {
	    var	i,
		c = s.chn

		po.v_c[s.v] = c
		if (s.instr != undefined)
			return
		i = po.c_i[c]

		// at channel start, reset and initialize the controllers
		if (i == undefined) {
		if (po.c_i[c] == undefined) {
//fixme: does not work with fluidsynth
			po.op.send(new Uint8Array([0xb0 + c, 121, 0]))
//fixme: is this useful?
if(0){
			if (s.p_v.midictl) {
			    for (i in s.p_v.midictl)
				po.op.send(new Uint8Array([0xb0 + c,
							i,
							s.p_v.midictl[i]]))
			}
		}

		po.c_i[c] = i = s.instr
		po.op.send(new Uint8Array([0xc0 + c, i & 0x7f])) // program
}
		}

		i = s.instr
		if (i != undefined) {		// if not channel only
			po.c_i[c] = i		// send a MIDI program
			po.op.send(new Uint8Array([0xc0 + c, i & 0x7f]))
		}
	} // midi_prog()

	// MIDI output is possible,
	// return the possible ports in return to get_outputs()
	function send_outputs(access) {
	    var	o, os,
		out = []
︙
172
173
174
175
176
177
178
179
180
181

182

183
184
185
186
187
188
189
175
176
177
178
179
180
181

182
183
184
185
186
187
188
189
190
191
192
193







-


+

+







					)
				}
			)
		}, // get_outputs()

		// set the output port
		set_output: function(name) {
		    var o, os
			if (!Midi5.ma)
				return
		    var o,
			os = Midi5.ma.outputs.values()

			while (1) {
				o = os.next()
				if (!o || o.done)
					break
				if (o.value.name == name) {
					op = o.value
					break
︙