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
  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).

- `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.  


  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`

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







|
|







|
|
>
>



|







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 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...).  
  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:  
  `        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
  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
  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.







|







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








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







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.  
















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

		"$c" --headless --disable-gpu\
			--print-to-pdf=$out --print-to-pdf-no-header /tmp/o.html
		rm /tmp/o.html
		exit 0
	fi
done

# try weasyprint
if command -v weasyprint >/dev/null 2>&1; then







>
|
|







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

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")';$

   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 $







>







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







<
<
<
<







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







<







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


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
// abc2svg - cmdline.js - command line
//
// Copyright (C) 2014-2021 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.


|







1
2
3
4
5
6
7
8
9
10
// abc2svg - cmdline.js - command line
//
// 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

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

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

		return file
	},







|







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
				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
		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()







<
<
<
<
<
<
<







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)








	// 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
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
//		        C		  D
		[36, 1, 2, 3, 8, 2, 2, 7, 8,13,14, 2,
//		    37
//	       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
		[-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 ])
abc2svg.isb40 = new Int8Array(		// interval with sharp to base-40 interval
	[0, 1, 6,11,12,17,18,23,28,29,34,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







|
<
<
|
<
<
<
<
<
<
<
>
|
<
<
<
>
|
>
|

|
<
<







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.b40l5 = new Int8Array([			// base-40 to line of fifth


//		  C			  D







	-14, -7,  0,  7, 14,  0,-12, -5,  2,  9, 16,  0,
//		  E		      F			      G	



	-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,7,12,17,18,23,24,29,30,35])



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
	"aug7": "+7",
	"7+5": "+7",
	"7#5": "+7",
	"sus": "sus4",
	"7sus": "7sus4"
} // ch_alias





// font weight
// reference:
//	https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight
abc2svg.ft_w = {
	thin: 100,
	extralight: 200,
	light: 300,







>
>
>
>







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
    // constants
    var	C = abc2svg.C;

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



// -- constants --

// staff system
var	OPEN_BRACE = 0x01,
	CLOSE_BRACE = 0x02,
	OPEN_BRACKET = 0x04,







|
>
>







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

	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)
	else
		syntax(1, "Unsecure code")
}







<
|
<
<

412
413
414
415
416
417
418

419


420
	}

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

// inject javascript code
function js_inject(js) {

	eval('"use strict";\n' + js)


}
Changes to core/deco.js.
1
2
3
4
5
6
7
8
9
10
// abc2svg - deco.js - decorations
//
// Copyright (C) 2014-2022 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.


|







1
2
3
4
5
6
7
8
9
10
// abc2svg - deco.js - decorations
//
// 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

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",
	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",
	"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",
	"8va(": "5 8va 12 6 6",
	"8va)": "5 8va 12 6 6",
	"8vb(": "7 8vb 12 6 6",
	"8vb)": "7 8vb 12 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",
	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",
	"-(": "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",







|
|
|
|
|
<
|
|
|
|
|
|
|
|
|
|
|
|






|
|
|
|
>
|
|
|
|
|
|
|
|
|


|
|


|
|
|
|
|
|
|


|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|







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.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",

	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 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(": "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(": "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,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
		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	// 7 (below the staff)
	]

/* -- get the max/min vertical offset -- */
function y_get(st, up, x, w) {
	var	y,
		p_staff = staff_tb[st],







|







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_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
	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,

		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.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)







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


|
>



<
<
<
<
<
<
<
<
<
<
<
<
<















>







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
}




























































































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














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








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







371
372
373
374
375
376
377

















































378
379
380
381
382
383
384
				s.ymx = de.y + dd.h
			}
		}
	    }
	}
}


















































/* 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
	de.y = 3 * (yc - 18)
}

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

		s2 = de.s,
		st = s2.st,
		s = de.start.s,
		x = s.x



























































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


	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 -= 6
		if (w < 10) {
			x -= 10 - w
			w = 10
		}
	}
	y = y_get(st, up, x - dd.wl - 5, 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)







|


>





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
>








|
|
<
|
<
|
|
<
|







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



	de.up = up
















	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 - 4
		sh_en(de)		// shift the ending point?

		if (w < 20)

			w = 20
	}

	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
	}

	de.lden = false;
	de.has_val = true;
	de.val = w;
	de.x = x;
	de.y = y
	de.up = up
	if (up)
		y += dd.h;


	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,

	s = de.s,
	dd = de.dd,
	x = de.x,
	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
		if (s.type == C.BAR) {
			s.invis = 1
		} else {
		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 (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)

	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)







<


>
>


















|
>



|
<
<










|



|













<
<
<












<
<






<
<










>
>
>
>
>
>
>
>
>
|
|
|
|

<







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

	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, inv,
	up = de.up,
	s = de.s,
	dd = de.dd,
	x = de.x,
	w = dd.wl + dd.wr



	// glyphs inside the staff
	switch (dd.glyph) {
	case "brth":
	case "caes":
	case "lphr":
	case "mphr":
	case "sphr":
	case "short":
	case "tick":
		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)
				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;




	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 (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 (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 (up)
		y_set(s.st, 1, x - dd.wl, w, y + dd.h)
	else
		y_set(s.st, 0, x - dd.wl, w, y - dd.hd)


	de.y = y
}

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

835
836




837
838
839
840
841
842
843
	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.-]+);?/)) {

			error(1, null, "%%deco: bad position '$1'", str)
			return




		}
		dd.str = str
	}

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







|
|
>


>
>
>
>







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] == '@') {
			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
		dd.ty = ty
	}
	return dd
} // get_dd()

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

	while (1) {
		nm = a_dcn.shift()
		if (!nm)
			break
		dd = get_dd(nm)
		if (!dd)







|







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







>
>
>
>
>
>
>
>
>
>
>
>
>







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
		case 40:		/* stemless */
			s.stemless = true
			break
		case 41:		/* rbend */
			s.rbstop = 2	// with end
			break
		case 42:		// editorial




			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




			j = curvoice.acc[s.notes[0].pit + 19]
			if (s.notes[0].acc || !j)
				continue
			court = 1			// defer
			break
		case 44:		// cross-voice ties




			do_ctie(nm, s, s.notes[0])	// (only one note for now)
			continue
//		default:
//			break
		}

		// add the decoration in the symbol







>
>
>
>















>
>
>
>






>
>
>
>







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
		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 10:		// color
			nt.color = nm
			continue
		case 40:		// stemless chord (abcm2ps behaviour)
			s.stemless = true
			continue
		case 44:		// cross-voice ties







<


>
>
>







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

			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
		de = a_de[i]
		if (de.s == s)
			de.x += dx
	}
}

/* -- adjust the symbol width -- */
function deco_width(s) {
    var	dd, i, w,
		wl = 0,

		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
			break
		case 3:
			switch (dd.glyph) {
			case "brth":
			case "lphr":
			case "mphr":
			case "sphr":
				if (s.wr < 20)
					s.wr = 20
				break





			}
			// fall thru
		default:
			switch (dd.ty) {
			case '<':
				w = dd.wl + dd.wr + 6
				if (wl < w)
					wl = w
				break
			case '>':
				w = dd.wl + dd.wr + 8
				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
			if (w > wl)
				wl = w
		}
	}
	return wl
} // deco_wch()








|

|
>







<
<
<

|
|










>
>
>
>
>





|




|







<
<












|







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, wlnt) {
    var	dd, i, w,
	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 */



		case 2:			/* arpeggio */
			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 = wlnt + dd.wl + dd.wr + 6
				if (wl < w)
					wl = w
				break
			case '>':
				w = wr + dd.wl + dd.wr + 6
				if (s.wr < w)
					s.wr = w
				break
			}
			break
		}
	}


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

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








|
|







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 + (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
					if (stv_g.scale != 1)
						y += stv_g.dy / 2
				}
			}
		}

		// check if user JS decoration

		uf = user[f]
		if (uf && typeof(uf) == "function") {
			uf(x, y, de)
			continue

		}

		// check if user PS definition
		if (self.psdeco(f, 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







>
|
|
|
|
>



|







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.deco[f]
			if (uf && typeof(uf) == "function") {
				uf.call(self, x, y, de)
				continue
			}
		}

		// check if user PS definition
		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
			 || 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] == '@') {
				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)

		} else if (de.lden) {
			out_deco_long(x, y, de)
		} else {
			xygl(x, y, f)
		}
		if (stv_g.g)
			g_close();







|
|
|
<
<
<
<
<
<

<
>







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		// string
			&& !tgls[dd.glyph]
			&& !glyphs[dd.glyph]) {		// with a class






			out_deco_str(x, y,		// - dd.h * .2,

					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
			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,
		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++) {







|







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, 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
				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 */
				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
				} else {
					x += dd.wl + 8
				}
				y = 3 * (s.notes[0].pit - 18)
						- (dd.h - dd.hd) / 2
				break
			case '@':







<


|
<
<
<

















|







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

				pos = s.pos.orn
				break
			case 6:				/* dynamic */



				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 -= 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
			de = {
				s: s,
				dd: dd,
				st: s.st,
				ix: a_de.length,
				defl: {},
				x: x,
				y: y,

				pos: pos

//				dy: 0





















			}



			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







|
>
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>







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
			}
			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
				s: s,
				dd: dd,
				st: s.st,
				m: m,
				ix: 0,
				defl: {},
				x: x,
				y: 3 * (note.pit - 18)
//				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 == '<')
						de.x -= dd.wr + 8


					else if (dd.ty == '>')
						de.x += dd.wr + 8

				}
			}

			a_de.push(de)
			if (dd.dd_en) {
				de.ldst = true
			} else if (dd.dd_st) {







|









|

>
>
|
|
>







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) - (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 == '<') {
						de.x -= dd.wr + 8
						if (s.notes[m].acc)
							x -= 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
				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
			if (de2.m != undefined)
				de.m = de2.m;
			a_de.push(de);
			de2.start = de
		}
	} // ll_deco








|







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.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
// -- 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,
	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;








|







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, 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
			for (;;) {
				if (!s.next)
					break
				s = s.next
				if (s.rbstop)
					break
			}



			y2 = y_get(p_voice.st, true, s1.x, s.x - s1.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
				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]) +
						wh[1]
				if (y < y2)
					y = y2
			}
			if (s.rbstart)
				s = s.prev
		}







>
>
>
|





|










|







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, 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, 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, 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
				s = s.next
				if (s.rbstop)
					break
			}
			if (s1 == s)
				break
			x = s1.x


			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 != "[]")







>
>







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

			continue

		f_staff[dd.func](de)

		if (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 */
	for (i = 0; i < nd; i++) {
		de = a_de[i];
		dd = de.dd
		if (!dd)		// if error
			continue
		if (dd.dd_en		// if start



		 || !f_staff[dd.func])











			continue

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


		y_set(de.st, de.up, de.x, de.val, y)















	}

	draw_all_chsy()		// draw all chord symbols

	/* draw the repeat brackets */
	for (v = 0; v < voice_tb.length; v++) {
		p_voice = voice_tb[v]







|















|
>

>

>
|

>













|



|

|
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>

>
|
>
>
>
>
>
|

|










>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
		}
	} // 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
		 || dd.ty == '<' || dd.ty == '>' || dd.ty == '@')
			continue

		f_staff[dd.func](de)
		if (dd.func != 6
		 || 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
			}
		}
	}

	// 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
			continue

		// 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
		 || 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
			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, 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
		     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.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);







>
>
|







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































	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







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

	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 */
/*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

		for (s = some_part; s; s = s.ts_next) {
			s2 = s.part
			if (!s2 || s2.invis)
				continue

			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.ymx = s2.ymn + h
				anno_start(s2)
			}
			xy_str(s2.x, 2 - ht + gene.curfont.size * .22, s2.text)





			anno_stop(s2)
		}
	}


	return dy /= staff_tb[0].staffscale

















}






































|
|
|
>
|
>
|
>
>
|
>
>
>
>

|


|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<



















<
<
<
|




>

<
<
<
|
|
|



|
>
>
>
>
>



>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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 -- */
// (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 + 2,
		dosh = 0,
		shift = 1,
		x = -100,	// (must be negative for %%soloffs)
	yn = 0			// y min when x < 0













































	// output the parts


	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)



		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.wl = 0
				s2.wr = w
				s2.ymn = ymin
				s2.ymx = s2.ymn + h
				anno_start(s2)
			}
			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
	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
	[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,
		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);







|







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,
	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
	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;
				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;
				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)






		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
	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 */


	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)
			;




		else if (s1.stem != s2.stem && s1.nflags < s2.nflags)
			b += ys * s2.stem

		else



			b += ys * s1.stem
	} 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)







|
|




|
|



















|
>
>
>
>
>
>

>








|


<


>
>

|
>
|
>
|
>
|
>
>
|
<
>
>
>
>
|
|
>
|
>
>
>
|







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].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].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 (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
	}

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


	/* 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) {
		n = 1
		while (1) {
			if (s.stem != s1.stem
			 && (s.nflags == 1
			  || s.beam_br1  || s.beam_br2)) {
				n = 0
				break
			}
			if (s == s2)

				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
				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 */
/*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:
			if (s.invis)
				break
			/*fall thru*/
		case C.CLEF:
			y = a * s.x + b
			if (s1.stem > 0) {
				y = s.ymx - y







|
<













|







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 and clefs

    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:
			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
	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,
		k, k1, k2, x1,

		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,







|

>







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, 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
		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)
		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







|







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)
		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
					break
				s = k
			}
			k2 = s
			while (k2.type != C.NOTE)
				k2 = k2.prev;
			x1 = k1.xs
			bd = beam_dir
			if (k1 == k2) {
				if (k1 == s1) {
					x1 += bstub
				} else if (k1 == s2) {
					x1 -= bstub
				} else if (k1.beam_br1
				        || (k1.beam_br2







|







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
			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
						  && k1.dots < k.dots))
							x1 += bstub
						else
							x1 -= bstub
					}
				}
				if (k1.stem != beam_dir) {

					bd = k1.stem
					k1.ys = bm.a * k1.xs + bm.b
						- staff_tb[k1.st].y - bh
				}

			}












			draw_beam(x1, k2.xs,
				  shift * bd,
				  bh, bm, i)
			if (s == s2)
				break
		}
	}
	if (s1.tmp)
		unlksym(s1)







>
|



>
|
>
>
>
>
>
>
>
>
>
>
>
>

|







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
					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,
				  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
// -- 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()





























	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)

	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('<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,







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


















>
|
|
|
|
>
>
>
>
>
>
>
>







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

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

    var	i,
	k, g, x1, y1, x2, y2, height, addy,
	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
	k1 = path[0],
	k2 = path[i2]

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

	var	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");








	/* fix endpoints */
	x1 = k1.x
	if (k1.notes && k1.notes[0].shhd)
		x1 += k1.notes[0].shhd;
	x2 = k2.x
	if (k2.notes)







|
>

|






|

|
<
<
<
|
<
<







|
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
|
|
>
|
|
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>







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
		   recurr) {	// recurrent call when slur on two staves
    var	i,
	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 starts on a note
	k1 = path[0],
	k2 = path[i2],



	nn = 1



	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 != 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
	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;







<
<







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]


		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
	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)
			continue
		y = a * k.x + addy
		if (k.ymx < y)
			k.ymx = y
		else if (k.ymn > y)
			k.ymn = y


		if (i == i2 - 1) {
			dx = x2
			if (sl.nte)
				dx -= 5;
			if (i)
				y -= height / 3
		} else {
			dx = path[i + 1].x
		}
		if (i != 0)
			x1 = k.x
		else

			y -= height / 3
		dx -= x1;
		y_set(upstaff, dir > 0, x1, 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
			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) {

			for (s3 = tsnext; s3 && s3.time == s2.time; s3 = s3.ts_next) {
				if (s3.type == C.GRACE)
//fixme: check if s2 in the grace notes

					break
			}



			if (s3.type == C.GRACE)






				s3 = null
		    }
		    if (!s2.grace || s2.time == tsnext.time || !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
		    }
		}







|






>
>




<
<

|



<
>

|
|




















<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|




















|
|
>

|
<
>

|
>
>
>
|
>
>
>
>
>
>
|
|
|







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 != 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;


		} else {
			dx = k.x + k.wr
		}
		if (i != 0)
			x1 = k.x

		if (!i || i == i2)
			y -= height / 3
		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

















			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 (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) {

					s3 = null
					break
				}
			}
		    } 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
				s = s.next
			else
				s = s.ts_next
		}

		if (!s2.grace) {		// if end on a normal note
			while (s) {
				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) {







|
<







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)

					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

/* -- 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,
	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)
	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.tp)
			draw_tuplet(s2)
		if (s2.tpe)
			break
	}

	if (s2)







|







<
|


















|
>
|
>
>
>







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

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


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







>







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

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


		if (tp.f[2] == 0)		// if 'which' == number
			xy_str(xm, ym, tp.p.toString(), 'c')
		else
			xy_str(xm, ym, 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)
		} else {
			if (s3.ymn > ym)
				s3.ymn = ym;
			y_set(upstaff, false, xm - 3, 6, ym)
		}
		return
	}

	// here, what is square bracket

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

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








|

|




|

|


>

|

|









|



|




|







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

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

		yy = ym + gene.curfont.size * .22
		if (tp.f[2] == 0)		// if 'which' == number
			xy_str(xm, yy, tp.p.toString(), 'c')
		else
			xy_str(xm, yy, tp.p + ':' + tp.q, 'c')

		for (s3 = s1; ; s3 = s3.next) {
			if (s3.x >= xm)
				break
		}
		if (dir == C.SL_ABOVE) {
			ym += gene.curfont.size
			if (s3.ymx < ym)
				s3.ymx = ym;
			y_set(stu, 1, xm - 3, 6, ym)
		} else {
			if (s3.ymn > ym)
				s3.ymn = ym;
			y_set(std, 0, xm - 3, 6, ym)
		}
		return
	}

	// here, 'what' is square bracket

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

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

︙︙
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
//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
		 && s2.stem > 0)
			x2 += 3.5
	}

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

	/* sole or upper voice: the bracket is above the staff */
	if (s1.st == s2.st) {




		y1 = y2 = staff_tb[upstaff].topbar + 2
	} else {
		y1 = s1.ymx;
		y2 = s2.ymx
	}

	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)
			x1 += 3
	}

	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
	}

	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)







|






|
<
|
>
>
>
>
|

|
<

|
<
<
<
|
|
|
|
<
<
|
<
<
<
<
<
|







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

    // above
    if (dir == C.SL_ABOVE) {
	if (s1.st >= s2.st) {

		if (s1.stem > 0)
			x1 += 3
		ym = y_get(s1.st, 1, x1 - 4, 8)
		y1 = ym > staff_tb[s1.st].topbar + 2
			? ym
			: staff_tb[s1.st].topbar + 2
	} else {
		y1 = staff_tb[s1.st].topbar + 2

	}
	if (s2.st >= s1.st) {



		ym = y_get(s2.st, 1, x2 - 4, 8)
		y2 = ym > staff_tb[s2.st].topbar + 2
			? ym
			: staff_tb[s2.st].topbar + 2


	} else {





		y2 = staff_tb[s2.st].topbar + 2
	}

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

	a = (y2 - y1) / (x2 - x1);
	s0 = 3 * (s2.notes[s2.nhd].pit - s1.notes[s1.nhd].pit) / (x2 - x1)
︙︙
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
	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) {
			if (s3 == s2)
				break
			continue
		}
		yy = ym + (s3.x - xm) * a;
		yx = y_get(upstaff, 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) {
			yy = ym + (s3.x - xm) * a
			if (s3.ymx < yy)
				s3.ymx = yy
			y_set(upstaff, true, 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 == upstaff) {
		for (s3 = s1; !s3.dur; s3 = s3.next)
			;
		y1 = y_get(upstaff, 0, s3.x - 4, 8)
	} else {
		y1 = 0
	}

	if (s2.st == upstaff) {
		for (s3 = s2; !s3.dur; s3 = s3.prev)
			;
		y2 = y_get(upstaff, 0, s3.x - 4, 8)



	} else {
		y2 = 0
	}

	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)







|





|













|



|







<
|
>
|
|
<
<
<
|

|

>
|
|
<
|
>
>
>

|







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 != stu) {
			if (s3 == s2)
				break
			continue
		}
		yy = ym + (s3.x - xm) * a;
		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 == stu) {
			yy = ym + (s3.x - xm) * a
			if (s3.ymx < yy)
				s3.ymx = 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 */

	if (s1.st <= s2.st) {
		ym = y_get(s1.st, 0, x1 - 4, 8)
		y1 = ym < -2
			? ym



			: -2
	} else {
		y1 = -2
	}
	if (s2.st <= s1.st) {
		if (s2.stem < 0)
			x2 -= 3

		ym = y_get(s2.st, 0, x2 - 4, 8)
		y2 = ym < -2
			? ym
			: -2
	} else {
		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
	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) {
			if (s3 == s2)
				break
			continue
		}
		yy = ym + (s3.x - xm) * a;
		yx = y_get(upstaff, 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) {
			yy = ym + (s3.x - xm) * a
			if (s3.ymn > yy)
				s3.ymn = yy;
			y_set(upstaff, false, 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)
	else
		y_set(upstaff, false, xm - 3, 6, yy)
}

// -- draw a ties --
function draw_tie(not1, not2,
			job) {	// -: start and end
				// 1: no starting note
				// 2: no ending note







|





|













|



|














|

|







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 != std) {
			if (s3 == s2)
				break
			continue
		}
		yy = ym + (s3.x - xm) * a;
		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 == std) {
			yy = ym + (s3.x - xm) * a
			if (s3.ymn > yy)
				s3.ymn = 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(stu, 1, xm - 3, 6, yy + 2)
	else
		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
 *   - tuplets and slurs
 * - not scaled
 *   - measure numbers
 *   - lyrics
 *   - staff decorations
 *   - chord symbols
 *   - repeat brackets

 * 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







>







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
			draw_all_lyrics()
			break
		}
	}

	draw_deco_staff()



	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 = []




	for (st = stl.length; st >= 0; st--) {

		if (stl[st])
			break
	}
	if (st < 0)
		return

	for (v = 0; v < voice_tb.length; v++) {







>
>









>
>
>
|
>







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; ) {
		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
			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,
	y, staffsep, dy, maxsep, mbot, val, p_voice, p_staff,
	fmt = tsfirst.fmt,
	sy = cur_sy




	/* 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 */
		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 +
			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;

		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)







|

<

>
>
>















|
|
<
|
<






<
<
<
<



|


















|
|







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, fmt, s,
	y, staffsep, dy, maxsep, mbot, val, p_voice, p_staff,

	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)
		return y



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





	/* set the vertical offset of the 1st staff */
	y *= p_staff.staffscale;
	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 || 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
		if (!/[\[|]/.test(stafflines))
			return				// no line
		w = x2 - x1;
		set_sscale(-1)

		// check if default staff
		if (cache && cache.st_l == stafflines

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







>







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
					'" d="m0 ' + y + 'h' + w.toFixed(1);
				dy = 0
			}
			ln += '"/>'
		}
		y = staff_tb[st].y
		if (!cache
		 && w > get_lwidth() - 10) {

			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 + '"')







|
>







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
		 && 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
		case '[':
			break
		default:
			set_hl(p_st, j, x, -7, 7)
			break
		}
	} // hl_rest()

















	// ---- 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
		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
						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 ==







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





|












<
|
<
<
<
<
<







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] = 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]) {

						xstaff[st] = st1(st, s)





						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
			   && 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) {



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







|
>
>







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
				 && 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
	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.KEY:
				p_voice.ckey = s
			default:
				continue
			case C.NOTE:	// (beams may start on invisible notes)
				break
			}







>
>
>
>







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

				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)







|
>







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
			 || !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
	set_scale(p_voice.sym);
}

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
































































































	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 */



}

/* -- 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) {







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>















>

>
>
>







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
// abc2svg - format.js - formatting functions
//
// Copyright (C) 2014-2022 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 = {
		serif: 1,
		serifBold: 1,
		'sans-serif': 1,
		'sans-serifBold': 1,
		Palatino: 1.1,
		monospace: 1.35
	},
	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},


|
















<
<
|





|







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-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_scale_tb = {
		serif: 1,
		serifBold: 1,
		'sans-serif': 1,
		'sans-serifBold': 1,
		Palatino: 1.1,
		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
	staffsep: 46,
	stemheight: 21,			// one octave
	stretchlast: .25,
	stretchstaff: true,
	subtitlefont: {name: txt_ff, size: 16},
	subtitlespace: 3,
	sysstaffsep: 34,

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







>













|







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: 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
measrepnb: true,
rbmax: true,
rbmin: true,
shiftunison: true,
slurheight: true,
squarebreve: true,    
staffsep: true,

stemheight: true,
stretchlast: true,
stretchstaff: true,
tieheight: true,
timewarn: true,

vocalspace: true
} // sfmt

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








>





>







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
	if (!scale)
		scale = 1.1;
	font.swfac = font.size * scale
}

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

	// "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
	font = cfmt[xxxfont];
	if (!font) {			// set-font-<n> or new element
		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







|









|
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







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, ft2, k

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

	// fill the values


	font = {}















	a = p.match(/\s+(no)?box(\s|$)/)
	if (a) {				// if box
		if (a[1]) {
			font.box = false	// nobox
			font.pad = 0
		} else {
			font.box = true
︙︙
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
	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(") {

		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.normal = true
		p = '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)
		}

		// 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], '')
		}











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

		switch (p) {
		case "":
		case "*": return
		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
		}
	}

	font.name = p

	if (font.size)
		set_font_fac(font)
	else






















		font.swfac = 0









}

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

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








<
<
|
|
>





<

|
|
|
<
|
<
<
<
<
<
<
<
|
|






<
<
<
<




















>
>
>
>
>
>
>
>
>
>






|












>
|



|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>















|







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], "")
	}



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


		font.src = p.slice(0, n + 1)
		font.fid = abc2svg.font_tb.length
		abc2svg.font_tb.push(font)

		font.name = 'ft' + font.fid







		p = p.replace(font.src, '')
	}

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




		}

		// 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 "*": 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

	if (font.size)
		set_font_fac(font)

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

	cfmt[xxxfont] = font
}

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

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

︙︙
403
404
405
406
407
408
409
410







411
412
413
414
415
416
417
	align: 'j',
	center: 'c',
	fill: 'f',
	justify: 'j',
	obeylines: 'l',
	ragged: 'f',
	right: 'r',
	skip: 's'







}
function get_textopt(v) {
    var	i = v.indexOf(' ')
	if (i > 0)
		v = v.slice(0, i)
	return textopt[v]
}







|
>
>
>
>
>
>
>







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',
// 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
	case "barsperstaff":
	case "infoline":
	case "measurenb":
	case "rbmax":
	case "rbmin":
	case "measrepnb":
	case "shiftunison":

		v = parseInt(param)
		if (isNaN(v)) {
			syntax(1, "Bad integer value");
			break
		}
		cfmt[cmd] = v
		break







>







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
	case "pagescale":
	case "parskipfac":
	case "scale":
	case "slurheight":
	case "stemheight":
	case "tieheight":
		f = +param
		if (isNaN(f)) {
			syntax(1, errs.bad_val, '%%' + cmd)
			break
		}
		switch (cmd) {
		case "scale":			// old scale
			f /= .75
		case "pagescale":


			cmd = "scale";
			img.chg = true
			break
		}
		cfmt[cmd] = f
		break
	case "annotationbox":







|







>
>







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) || !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
	case "squarebreve":
	case "splittune":
	case "straightflags":
	case "stretchstaff":
	case "timewarn":
	case "titlecaps":
	case "titleleft":

		cfmt[cmd] = get_bool(param)
		break
	case "dblrepbar":
		param = ":: " + param
		// fall thru
	case "bardef":			// %%bardef oldbar newbar
		v = param.split(/\s+/)







>







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
	case "concert-score":
		if (cfmt.sound != "play")
			cfmt.sound = "concert"
		break
	case "writefields":
		set_writefields(param)
		break



	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) {







>
>
>






<







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":

		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
				break
			case C.SL_HIDDEN:
				curvoice.tup[2] = 1
				break
			}
			break
		}


		set_pos(cmd[1], cmd[2])
		break
	case "sounding-score":
		if (cfmt.sound != "play")
			cfmt.sound = "sounding"
		break
	case "staffwidth":







>
>







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
		break
	case "voicemap":
		set_v_param("map", param)
		break
	case "voicescale":
		set_v_param("scale", param)
		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"







>
>
>
>
>
>







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
}

// 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)
			if (!font.swfac)
				set_font_fac(font)
			if (!font.pad)
				font.pad = 0








		}
		add_fstyle(".f" + font.fid +
			(cfmt.fullsvg || "") +
			"{" + style_font(font) + "}")
		if (font.src)
			add_fstyle("@font-face{\n\
 font-family:" + font.name + ";\n\







|
|




>
>
>
>
>
>
>
>







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 = 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
		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]
		if (fid != undefined)
			return font_tb[fid]
		font_st[st] = font_tb.length	// will be the font id
		font2.fid = font2.used = undefined
		font = font2
	}
	use_font(font)
	return font
}







|

|
|






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 = abc2svg.font_st[st]
		if (fid != undefined)
			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
// abc2svg - front.js - ABC parsing front-end
//
// Copyright (C) 2014-2022 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


// translation table from the ABC draft version 2.2
var abc_utf = {
	"=D": "Đ",
	"=H": "Ħ",
	"=T": "Ŧ",
	"=d": "đ",


|


















|
>







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-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
	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
		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
		init_tune()
		img.chg = true;
		set_page();
	} // end_tune()

	// get %%voice
	function do_voice(select, in_tune) {







|







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.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
						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()




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

	// scan the file
	if (bol == undefined)







|
|
>
>
|
>
>
>







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.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
		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 == '%') {
			if (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)







>
|
|













<
<







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 == ':')
		  || 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
			}


		}

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







|
|

|
|

<
<
|
<
|



















|







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 + 1] != '%')
						break
					eol = file.indexOf('\n', eol + 1)
					if (file[bol + 2] != line1)
						continue


					text = file.slice(bol + 3,

							eol < 0 ? undefined : eol)
					a = text.match(/([^\s]+)\s*(.*)/)
					switch (a[1]) {
					case "tune":
						break
					case "voice":
						do_voice(uncomment(a[2],
								true), true)
						continue
					default:
						opt.t_opts.push(
							uncomment(text, true))
						continue
					}
					break
				}
				if (parse.tune_v_opts) {
					opt.v_opts = parse.tune_v_opts;
					parse.tune_v_opts = null
				}
				parse.eol = bol
				continue
			case "voice":
				if (parse.state != 0) {
					syntax(1, errs.not_in_tune, "%%voice")
					continue
				}
				select = uncomment(a[2])
︙︙
737
738
739
740
741
742
743




744
745
746
747
748
			continue
		}
		txt_add = '\n';
		last_info = line0
	}
	if (include)
		return




	if (parse.state >= 2)
		end_tune();
	parse.state = 0
}
Abc.prototype.tosvg = tosvg







>
>
>
>





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
// abc2svg - gchord.js - chord symbols
//
// Copyright (C) 2014-2022 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.


|







1
2
3
4
5
6
7
8
9
10
// abc2svg - gchord.js - chord symbols
//
// 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
		}
		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;







<
<
<
<
<
<
<







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) {







			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
				}
				if (c == ';') {
					i++;
					gch.text += c
					continue
				}
				break

			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,
		tr = curvoice.tr_sco,
		csa = p.split('/')


		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++;
				ip++
			}
			while (p[ip] == 'b' || p[ip] == '\u266d') {
				a--;
				ip++
			}

			n = note_names.indexOf(p[o]) + 16






			b40 = (abc2svg.pab40(n, a) + tr + 200) % 40
			b40 = abc2svg.b40k[b40]
			csa[i] = p.slice(0, o) +
					note_names[abc2svg.b40_p[b40]] +
					acc_name[abc2svg.b40_a[b40] + 2] +





					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







>














<
<
<
|
|
<


>






|
>
>
>
|
|

<
|
|


>
|
>
>
>
>
>
>
|
<
|
<
|
>
>
>
>
>
|







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



	function gch_tr1(p, tr) {
	    var	i, o, n, ip,

		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

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

			} else if (p[ip] == 'b' || p[ip] == '\u266d') {
				n -= 7
				ip++
			}
			n += tr					// transpose

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


			csa[i] = p.slice(0, o)

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

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

	if (s.a_gch)
		s.a_gch = s.a_gch.concat(a_gch)
	else
		s.a_gch = a_gch







|







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, 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
		/* set the offsets and widths */
		set_font(gch.font);
		gch.text = str2svg(gch.text)
		wh = gch.text.wh
		switch (gch.type) {
		case '@':
			break


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







>
>
|
|















<
<
<
<
<
<







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 */
			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






		}
	}

	/* 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
			if (y2 < staff_tb[s.st].ann_bot)
				staff_tb[s.st].ann_bot = y2
		}
		break
	}

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







|

|

















|




















|







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 >= 0)
			y_set(s.st, 1, x, w, y + h + pad + 2)
		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, 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)	// 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
			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]

				w = an.text.wh[0]


				if (an.pos == C.SL_ABOVE) {
					y = y_get(s.st, true, s.x, w) + 2
					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
					if (y < minmax[s.st].ydn)
						minmax[s.st].ydn = y
				}
				break
			}
		}
	}







>

>
>

|



|







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, 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, x, w) - 2
					if (y < minmax[s.st].ydn)
						minmax[s.st].ydn = y
				}
				break
			}
		}
	}
︙︙
Changes to core/license.
1
2
3
// abc2svg - ABC to SVG translator
// @source: https://chiselapp.com/user/moinejf/repository/abc2svg
// Copyright (C) 2014-2023 Jean-Francois Moine - LGPL3+


|
1
2
3
// abc2svg - ABC to SVG translator
// @source: https://chiselapp.com/user/moinejf/repository/abc2svg
// Copyright (C) 2014-2024 Jean-Francois Moine - LGPL3+
Changes to core/lyrics.js.
1
2
3
4
5
6
7
8
9
10
// abc2svg - lyrics.js - lyrics
//
// Copyright (C) 2014-2022 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.


|







1
2
3
4
5
6
7
8
9
10
// abc2svg - lyrics.js - lyrics
//
// 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
			}
			s = s.next;
			i++
			continue
		case '-':
		case '_':
			word = p[i]
			ln = 2			// line continuation
			break
		case '*':
			word = ""
			break
		default:
			word = "";
			while (1) {







|







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 = 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
		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)
				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.shift = 0
			continue
		}
		spw = cwid(' ') * ly.font.swfac
		w = p.wh[0] + spw * 1.5
		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
			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 -= shift			// right width
		if (w > wx)
			wx = w			// max width
	}

	// set the left space
	while (!s3.seqst)







|












|
>
|




|















<
|















>







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

			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
				}
			}
			continue
		}
		if (ly.font != gene.curfont)		/* font change */
			gene.curfont = ly.font
		p = ly.t;

		w = p.wh[0]
		shift = ly.shift
		if (hyflag) {
			if (ly.ln == 2 && p == "_") {	// '_'
				p = "-"
			} else if (ly.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 '_'
			out_wln(lastx + 3, y, x0 - lastx + 3);
			lflag = false;
			lastx = s.x + s.wr
		}
		if (ly.ln == 2) {		// '-' or '_'
			if (x0 == 0 && lastx > s.x - 18)
				lastx = s.x - 18
			if (p == '-')
				hyflag = true
			else
				lflag = true;
			x0 = s.x - shift
			continue
		}
		x0 = s.x - shift;
		if (ly.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,







>



|
|
|






|




|


|







|







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 (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
		 && ln != 3) {				// not '_'
			out_wln(lastx + 3, y, x0 - lastx + 3);
			lflag = false;
			lastx = s.x + s.wr
		}
		if (ln >= 2) {				// '-' or '_'
			if (x0 == 0 && lastx > s.x - 18)
				lastx = s.x - 18
			if (ln == 2)			// '-'
				hyflag = true
			else
				lflag = true;
			x0 = s.x - shift
			continue
		}
		x0 = s.x - shift;
		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

	/* 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 == "_") {
				lflag = true;
				x0 = realwidth - 15
				if (x0 < lastx + 12)
					x0 = lastx + 12
			}
			break
		}







|







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 == 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
	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)

		}
		return (y - a_h[j - 1] / 6) / 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);
		y += a_h[j] * 1.1
	}
	return y / sc
}

// -- draw all the lyrics --
/* (the staves are not yet defined) */







|
>

|








|







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 + a_h[j] * .22)	// (descent)
		}
		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 + 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
	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) {
/*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) {
					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)
			}
		}
	}
}







|










|











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; 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; 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
// abc2svg - mei.js - MEI front-end
//
// Copyright (C) 2019-2021 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.


|







1
2
3
4
5
6
7
8
9
10
// abc2svg - mei.js - MEI front-end
//
// 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
					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)







>







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







<
<







52
53
54
55
56
57
58


59
60
61
62
63
64
65
	soloffs: {},
	sth: {},
	strtab: {},
	temperament: { fn: 'temper' },
	tropt: {},

	nreq: 0,



	// 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
// abc2svg - music.js - music generation
//
// 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.


|







1
2
3
4
5
6
7
8
9
10
// abc2svg - music.js - music generation
//
// 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

	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

		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







>
|







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
		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
//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)
		return
	next.seqst = next.time != s.time ||
			(w_tb[s.type] != w_tb[next.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







|
|



|







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 || next.seqst)
		return
	next.seqst = next.time != s.time ||
			(w_tb[s.type] != w_tb[next.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
				wlnote -= 3
				break
			}
		}

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

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







|







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)

		/* 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
		 && 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
				}

				/* 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







|
>
>
>
|
|
>
|







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:

				// 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
				break
			case C.CLEF:		/* extra space at start of line */
				if (s2.second
				 || s2.clef_small)
					break
				// fall thru
			case C.KEY:



			case C.METER:
				wlw += 3
				break
			}
		}

		/* leave room for guitar chord */







>
>
>







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
		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);
		s.wl = xx
		return
	case C.BAR:
		bar_type = s.bar_type
			switch (bar_type) {
			case "|":
				w = 5		// 3 + 2







|







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







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

		/* 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






		}
		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







>
>
>
>
>
>














|
















>
>
>
>
>
>



<
<
<
<







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)

		/* 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




		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
				s_chs = s;
			self.set_width(s);
			st = s.st
			if (xl[st] == undefined)
				xl[st] = 0
			if (wr[st] == undefined)
				wr[st] = 0;




			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







>
>
>
>







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
				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
		     && !s2.ts_prev.bar_type) {
			delete s2.seqst;		/* no space */
			s2.time = tim
		    } else if (s2.dur) {
			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;



		xa = maxx
		do {
			st = s2.st;
			xl[st] = xa
			if (s2.wr > wr[st])
				wr[st] = s2.wr
			s2 = s2.ts_next







|



|








|
>
|
>
>
>







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.type == C.CLEF
		     && !s2.ts_prev.bar_type) {
			delete s2.seqst;		/* no space */
			s2.time = tim
		    } else {
			s2.shrink = 10			// cannot be null
		    }
		}
		tim = s2.time
		if (!s)
			break

		// update the min left space per staff
		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
			if (s2.st != st)
				continue
			if (s2.type == C.BAR) {
				if (s2.v == v)
					break
				continue
			}


			s2.invis = s2.play = true
			if (s2.seqst && s2.ts_next.seqst)
				s2.seqst = false
		}
		s3 = to_rest(s3)
		s3.dur = s3.notes[0].dur = dur;
		s3.invis = true;







>
>







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
			if (s2.st != st)
				continue
			if (s2.type == C.BAR) {
				if (s2.v == v)
					break
				continue
			}


			s2.invis = s2.play = true
			if (s2.seqst && s2.ts_next.seqst)
				s2.seqst = false
		}
		s3 = to_rest(s3)

		s3.dur = s3.notes[0].dur = dur;







>
>







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



		s = so				// start of sequence


		while (s.ts_prev























		 && s.ts_prev.time == so.time) {

			s = s.ts_prev












			if (s.bar_type) {


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


			}









//			if (s.type == C.GRACE)
//				so = s		// keep the grace notes in the next line

		}
		if (!s1)



			return so

		// search the insertion point in the new line
		for (s = so; ; s = s.ts_next) {
			switch (s.type) {
//			default:
//				if (w_tb[s.type])
//					break
			case C.KEY:
			case C.METER:

			case C.CLEF:


				continue
			}
			break
		}



		while (s1 != so) {
		    if (s1.bar_type
		     && s1.next
		     && (s1.bar_type.slice(-1) == ':'
		      || s1.text)
		     && s1.bar_type != ':') {
			new_type(s1)		// return t1 and t2
			s2 = clone(s1)
			s1.bar_type = t1
			delete s1.a_gch
			if (t1 == '|')
				delete s1.rbstop // (needed for play variant)
			s2.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
			}
			lktsym(s2, s)		// time
			if (s1.seqst)
				s2.seqst = 1

			if (s == so)

				so = s2


			if (s1.text) {
				s2.invis = true
				delete s1.text
				delete s1.rbstart

			}
			delete s1.part
			delete s2.a_dd
		    }


			s1 = s1.ts_next



		}
		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

		// advance in the next line
		for (s2 = s; s2; 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)







>
>
|
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
|
>

|
>
>
|
|
>
>
|
>
>
|
>
>
|
>
>

>
>
>
>
>
>
>
>
>
|
|
>

|
>
>
>


|
|
|
<
<
<


>
|
>
>





>
>
|
<
<
<
<
<
|

|
<
<
<
|
<
<
<
<
|
|
|
<
|
|
|
>
|
>
|
>
>

|
|
|
>

|
|
<
>
>
|
>
>
>

















|


|







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 |:
				 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()

		// 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
			else if (!s1 && s.type == C.GRACE && s.seqst)
				so = s		// if grace note after a bar
						// move the start of line
		}
		if (!s1
		 || !s1.bar_type
		 || (s1.bar_type.slice(-1) != ':'
		  && !s1.text))
			return so

		// search the new start of the next line
		for (so = s1; so.time == s1.time; so = so.ts_prev) {
			switch (so.ts_prev.type) {



			case C.KEY:
			case C.METER:
//			case C.PART:
			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 (1) {





			new_type(s1)
			s2 = clone(s1)
			s2.bar_type = t1



			s1.bar_type = t2




			s2.ts_prev = so.ts_prev
			s2.ts_prev.ts_next = s2
			s2.ts_next = so

			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) {
				s1.invis = 1 //true
				delete s1.xsh
				delete s2.text
				delete s2.rbstart
			}
			delete s2.part
			delete s1.a_dd

			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, w

		// advance in the next line
		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
				lkvsym(s3, s1)		// voice link

				// care with spacing
				if (s3.seqst) {
					self.set_width(s3)
					s3.shrink = s3.wl
					s4 = s3.ts_prev

					while (!s4.seqst)




						s4 = s4.ts_prev

					s3.shrink += s4.wr
					s3.space = 0
					s4 = s3.ts_next
					while (!s4.seqst)


						s4 = s4.ts_next









					s4.shrink = s3.wr + s4.wl
				}
				delete s3.part
				continue
			}
			if (w_tb[s2.type])
				break		// symbol with a width
		}







>
|
>
>
>
>

>
|

|
|
>
>

>
>
>
>
>
>
>
>
>
|







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 (1) {
						if (s4.wr > w)
							w = s4.wr
						if (s4.seqst)
							break
						s4 = s4.ts_prev
					}
					s3.shrink += w
					s3.space = 0
					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 + 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
				mc = {
					lm: cfmt.leftmargin,
					rm: cfmt.rightmargin
				}
				break
			case "mc_new":
			case "mc_end":


				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

			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]







>
>












>







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
//		s.ymx = top;
		s.ymx = 24;
		s.ymn = 0
		break
	}
}

// set the ottava decorations and the associated pitch shift
function set_ottava() {
    var	s, st, delta, note, g, o,
	m = nstaff + 1,
	staff_d = new Int16Array(new Array(m * 2)),	// (-ottava)
	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)"];

		a_dcn.push((start ? dc_st : dc_en)[2 + ottava])
		deco_cnv(s)
	}

	for (st = 0; st <= nstaff; st++) {
		staff_d[st] = 0;
		staff_noo[st] = 0
	}
	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) {
				for (m = s.nhd; m >= 0; m--) {
					note = s.notes[m];
					if (!note.opit)
						note.opit = note.pit;
					note.pit += delta
				}
			}
			break
		case C.GRACE:
			for (g = s.extra; g; g = g.next) {
				delta = staff_d[st]
				if (delta
				 && !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
					}
				}
			}
			break
		}














































	}
}

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








|

|

|
<

<
<
<
<
|
<
<
<
|
<
<
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<





<
<
|




|





<
<
|




|





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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 pitch of the notes under an ottava sequence
function set_ottava() {
    var	s, s1, st, o, d,
	m = nstaff + 1,
	staff_d = new Int8Array(m)






	// update the pitches of a symbol



	function sym_ott(s, d) {


	    var	g, m, note


















		switch (s.type) {
		case C.REST:
			if (voice_tb.length == 1)
				break
		case C.NOTE:


			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 += d
				}
			}
			break
		case C.GRACE:
			for (g = s.extra; g; g = g.next) {


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

			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) {


				lktsym(s2, s3)
				if (s3.type == C.BAR)
					delete s3.bar_num
			} else {
				s3 = s
				while (s3.ts_next)
					s3 = s3.ts_next







|










|







>
>







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 = 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, 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
				s3 = s3.ts_next
			while (s3 && s3.v < s.v) {
				s3 = s3.ts_next	// keep in order
				if (s3 && s3.seqst)
					break
			}
			if (s3) {


				lktsym(s4, s3)
			} else {
				s3 = s
				while (s3.ts_next)
					s3 = s3.ts_next
				s3.ts_next = s4
				s4.ts_prev = s3







>
>







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
}

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







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







|
|

|
|
|
|

>
>
>
>
>
>






|







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],
	[10, 12],
	[10, 10],
	[10, 10],			/* crotchet */
	[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(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
			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.ymn = 12 - 8
				s.ymx = 24;
				s.ymn = 0
				break
			}

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







<
|
>
|
<
|



>











<
<
<
<
<
<
<
<
<







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:

			s.y = 12
			if (s.rep_nb > 1		// if measure repeat
			 || s.bar_mrep) {

				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.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
				 || 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
			case C.NOTE:
			case C.GRACE:
				break
			}

			st = s.st;
			v = s.v;







|







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)
				// 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
			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,
		shift, dots, dx,
		v_s_tb = [],
		sy = cur_sy






















	for (s = tsfirst; s; s = s.ts_next) {
		if (s.invis)
			continue

		if (s.type == C.STAVES)
			sy = s.sy




		if (!s.dur)
			continue
		v_s = v_s_tb[s.v]
		if (!v_s) {
			v_s = {}
			v_s_tb[s.v] = v_s
		}
		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)
				continue
			not_alone = true;
			s2 = v_s.s
			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 (s2.y < ymax)
						ymax = s2.y
				}
			} else {
				if (s2.time == s.time) {
					if (s2.ymx > ymin) {
						ymin = s2.ymx
						if (s2.dots)
							dots = true

					}
				} else {
					if (s2.y > ymin)
						ymin = s2.y


				}
			}
		}

		/* 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)
			 || !s2.dur
			 || s2.invis)
				continue
			not_alone = true

			if (sy.voices[s2.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 (s2.y < ymax)

						ymax = s2.y
				}
			} else {
				if (s2.time == s.time) {
					if (s2.ymx > ymin) {

						ymin = s2.ymx
						if (s2.dots)

							dots = true
					}
				} else {

					if (s2.y > ymin)
						ymin = s2.y
				}





			}
		}
		if (!not_alone) {
			s.y = 12;
			s.ymx = 24;
			s.ymn = 0
			continue
		}
		if (ymax == 127 && s.y < 12) {
			shift = 12 - s.y
			s.y += shift;
			s.ymx += shift;
			s.ymn += shift
		}
		if (ymin == -127 && s.y > 12) {
			shift = s.y - 12







			s.y -= shift;

			s.ymx -= shift;
			s.ymn -= shift
		}
		shift = ymax - s.ymx
		if (shift < 0) {
			shift = Math.ceil(-shift / 6) * 6
			if (s.ymn - shift >= ymin) {
				s.y -= shift;
				s.ymx -= shift;
				s.ymn -= shift
				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
				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) {







|
<



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



>
|

>
>
>
>
|
|
|
|
<
|
<
|
>
|
|
|
|
>
|
|
|
|
|
|
|
|
|
>
|
|
|
<
<
|
<
|
|
|
>
|
|
<
>
|
>
>
|
|
<
<
|
|
|
|
|
>
|
<
|
|
>
>
|

<
|
<
<
<
<
<
<
|
<
|

|
>
|
|
<
>
|
|
>
|
<
|
>
>
>
|
>
|
<
<
|
|
>
|
|
>
|
<
|
>
|
|
|
>
>
>
>
>
|
<
|
<
<
<
|
|
<
<
|
<
|
<
|
|
>
>
>
>
>
>
>
|
>
|
<
|
<
|
<
|
|
<
<
|
|
<
<
|
|
|
>
|
>
>
|
>
>
|
|
>
>
|
|
|
<
<
<
<
<
<







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, v_s, ymax, ymin, d,

		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) {
		case C.STAVES:
			sy = s.sy
			// fall thru
		default:
			continue
		case C.REST:
			if (s.invis || !s.multi)
				continue
			v_s = v_s_tb[s.v]
			if (!v_s) {

				v_s_tb[s.v] = v_s = { d: 0}

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


					v_s.d = d - s.y

			} else {
				if (d <= 12)
					v_s.d = d - s.y
			}

			v_s.s = s

			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


					if (s2.st == s.st
					 && s.ymx > s2.ymn
					 && !s2.invis) {
						if (s2.type == C.NOTE) {
							v_s.d = s2.ymn - s.ymx
							break
						}

						if (s2.type == C.REST
						 && s2.y < 18
						 && s.y >= 6)
							v_s.d = -6
					}
			}

			continue






		case C.NOTE:

			if (s.invis || !s.multi)
				continue
			break
		}

		// check if any clash with a rest

		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

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


//				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 {
						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 (d >= v_s.d)



						continue
				}


			} else {

				if (s2.ymn + v_s.d >= s.ymx)

					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

				}

				if (v_s.d) {

					if (v_s.d < 0) {	// if it was go down
						rshift()	// shift the rest


						continue
					}


					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






		}
	}
}

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


			unlksym(s)
			// fall thru
		case C.TEMPO:
		case C.BLOCK:
		case C.REMARK:
			continue
		}







<
<


>
>







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


				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
			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)
		if (!cur_sy.st_print[st])
			s.invis = true


		s.fmt = fmt
	}

	/* add keysig */
	for (v = 0; v < nv; v++) {
		if (!cur_sy.voices[v]
		 || cur_sy.voices[v].second







|


>
>







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.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
	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)
		;






	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







>
>
>
>
>
>







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
				trem_adj(s)
				break
			}

			nflags = s.nflags

			if (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) {







|







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

	// name or subname?

	for (v = 0; v < nv; v++) {
		p_voice = voice_tb[v]
		if (!cur_sy.voices[v]
		 || !gene.st_print[p_voice.st])
			continue
		if (p_voice.new_name) {

			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 */







|


>
|




|
>





>







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,
	fmt = tsnext ? tsnext.fmt : cfmt

	// name or subname?
	if (fmt.systnames) {		// display the names in the staff system
	    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.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
	case "pagescale":
	case "pagewidth":
	case "scale":
	case "staffwidth":
		self.set_format(s.subtype, s.param)
		break
	case "mc_start":		// multicol start




		multicol = {

			posy: posy,
			maxy: posy,
			lm: cfmt.leftmargin,
			rm: cfmt.rightmargin,
			w: cfmt.pagewidth,
			sc: cfmt.scale
		}
		break
	case "mc_new":			// multicol new




		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 (posy < multicol.maxy)
			posy = multicol.maxy
		cfmt.leftmargin = multicol.lm
		cfmt.rightmargin = multicol.rm
		cfmt.pagewidth = multicol.w
		cfmt.scale = multicol.sc
		multicol = undefined







>
>
>
>

>









>
>
>
>










>
>
>
>







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
		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,
	non_empty = [],
	non_empty_gl = [],
	sy = cur_sy

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








<
<
<
<
<
<
<
<
<
<
<
<
<
<



|
<







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















/* -- 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, 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
			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))

			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







|
>







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((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
			 s.next.prev = null
	}

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


	/*
	 * 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 = s.sy;
			while (nstaff < sy.nstaff)
				reset_staff(++nstaff)
			non_empty = []
			continue

		// the block symbols will be treated after music line generation
		case C.BLOCK:
			if (!s.play) {
				blocks.push(s)
				unlksym(s)







>











|



|







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 = non_empty
			sy = s.sy;
			while (nstaff < sy.nstaff)
				reset_staff(++nstaff)
			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
		}
		non_empty_gl[st] = non_empty[st] = true
	}
	tsnext = s;

	/* set the last empty staves */
	set_brace()
	sy.st_print = new Uint8Array(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) {
					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
		}
	}






}

/* -- position the symbols along the staff -- */
// (possible hook)
Abc.prototype.set_sym_glue = function(width) {
    var	s, g, ll, x,
	some_grace,
	spf,			// spacing factor

	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








	/* calculate the whole space of the symbols */
	for (s = tsfirst; s; s = s.ts_next) {
		if (s.type == C.GRACE && !some_grace)
			some_grace = s
		if (s.seqst) {
			xmin += s.shrink







			if (s.space) {
				if (s.space < s.shrink) {
					xse += s.shrink;
					xx += s.shrink
				} else {

					xx += s.space

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





	// 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
		for (var cnt = 4; --cnt >= 0; ) {
			spf = (width - xs - xse) / (xx - xse);








			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 (Math.abs(x - width) < 0.1)
				break



		}
		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







|




<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<













|













>
>
>
>
>
>





<
|
<
>



|
>
>
>
>
>
>
>


|




>
>
>
>
>
>
>





>

>













|
|
|
|
|
>
>
>
|
>

<

<
<
<
<
<







|
|
|
|
|
<
|
>
>
>
>
>
>
>
>




















>
>


>
>
>


<
<
<
<
<
<
<
<
<
<
<
<







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 = non_empty

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

















	// 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 = 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	g, x, some_grace, stretch,

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

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

	if (xmin >= width) {





		x = 0
		for ( ; s; s = s.ts_next) {
			if (s.seqst)
				x += s.shrink;
			s.x = x
		}
//		realwidth = width
		spf_last = .65
	} else {
		if (stretch) {
			if (xx == xse)			// if no space
				xx += 10

			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












	}
	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
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)
			p_v.sym.prev = p_v.s_prev


		s = p_v.s_next			// (set in set_piece)

		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 {







|

>
>

>







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) {
			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
		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






	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]







<
<
<
<






>
>
>
>
>







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





	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

	// 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
	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 (indent)

				posx += indent;

			draw_sym_near();		// delayed output
			line_height = set_staff();

			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())







|









>
>
|
>
|
>


>



<
<

>







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 = .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) {
				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();


				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
// abc2svg - parse.js - ABC parse
//
// 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.


|







1
2
3
4
5
6
7
8
9
10
// abc2svg - parse.js - ABC parse
//
// 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
	case 'F':
		s.clef_type = "b";
		s.clef_line = 4
		break
	case 'n':				// none
		i = 4
		s.invis = 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]







>
















<
<
<
<
<







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;





		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
				a = 0		// no accidental
		}
		nt.acc = a
		return an
	}

	// set the microtonal accidental after transposition
	switch (a) {
	case -2:
		if (n > 0)
			n -= d * 2
		else
			n -= d
		break
	case -1:







|







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 (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
	if (isNaN(n) || n < 0 || n > 16)
		return //undefined
	return "||||||||||||||||".slice(0, n)
}

// create a block symbol in the tune body
function new_block(subtype) {

	var	s = {
			type: C.BLOCK,
			subtype: subtype,
			dur: 0
		}


	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)


	return s
}

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







>
|





>



>
>







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,
	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
		case "staffscale=":
			val = +a.shift()
			if (isNaN(val) || val < .3 || val > 2)
				syntax(1, "Bad %%staffscale value")
			else
				curvoice.staffscale = val
			break




		case "transpose=":		// (abcMIDI compatibility)
			if (cfmt.nedo) {
				syntax(1, errs.notransp)
				break
			}
			val = get_transp(a.shift())
			if (val == undefined) {







>
>
>
>







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







<
<
<
<
<
<
<
<
|







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 & 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
					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
				break
			}
			if (!in_parenth) {
				if (meter.bot)
					m2 = +meter.bot
				wmeasure += m1 * C.BLEN / m2
			}







|







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











































/* Q: tempo */
function new_tempo(text) {
    var	i, c, d, nd,
	txt = text,			// (for info.Q)
	s = {
		type: C.TEMPO,







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
	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.v = par_sy.top_voice
	s.p_v = voice_tb[s.v]
	s.fmt = cfmt
	s.st = s.p_v.st
	s.time = tim
}

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







<


<
|
|
|
|
<
<
<
|
|







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
	}


	if (!glovar.tempo)
		syntax(0, "No previous tempo")

	s.time = curvoice.time
	text = 'Q' + s.time
	if (parse.pq
	 && parse.pq[text] == s.time)



		return				// already seen
	link_pq(s, text)
}

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

	// skip this line if the current voice is ignored
︙︙
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
	case 'P':
		if (!parse.state)
			break
		if (parse.state == 1) {
			info.P = text
			break
		}

		// memorize the part in the control
		tim = curvoice.time
		s = {

			text: text,
			time: tim
		}







		set_ref(s)
		if (cfmt.writefields.indexOf(info_type) < 0)
			s.invis = true
		if (!parse.ctrl)
			parse.ctrl = {}
		if (!parse.ctrl[tim])
			parse.ctrl[tim] = {}
		parse.ctrl[tim].part = s
		s.v = par_sy.top_voice
		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':







<
<
<

>

|

>
>
>
>
>
>
>
|
|
|
<
<
<
<
<
|
<
<
<







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
		}



		s = {
			type: C.PART,
			text: text,
			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
		}

		if (cfmt.writefields.indexOf('P') < 0)
			s.invis = 1 //true





		link_pq(s, text)



		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
		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) {
		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;







<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







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


	if (fac == 1)















		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

	// 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 = '['







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







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)




















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








|







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 = 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
			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.ulen < 0)			// L:auto
		adjust_dur(s);


	if (bar_type == "[" || bar_type == "|:") {


		s2 = curvoice.last_sym
		if (s2 && s2.time == curvoice.time) {

			// search if a previous bar at this time
			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) {
//		&& !s2.a_gch && !s2.a_dd
//		&& !s.a_gch && !s.a_dd) {

				// remove the invisible repeat bars
				// when no shift is needed
				if ((bar_type == "["
				 && !s2.text
				 && (!curvoice.st
				  || (par_sy.staves[curvoice.st - 1].flags & STOP_BAR)
				  || s.norepbra))
				 || s2.bar_type == "|") {	// "|" + "|:" => "|:"
					if (bar_type != "[")
						s2.bar_type = bar_type
					if (s.text)
						s2.text = s.text





					if (s.a_gch)
						s2.a_gch = s.a_gch
					if (s.norepbra)
						s2.norepbra = s.norepbra
					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 == ":|") {

						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 "[]":







<
<
<
|
|
|
|
>



>
|
>
>

<

|
<
<
<
<
<
<
<
|



|


|
<
<
|
<
<
<
|

>
>
>
>
>
|
|

|










|
>




<
<
<
<
|
<
<







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 (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 == "|:")
	 && !curvoice.eoln
	 && !s.a_gch && !s.invis) {		// no annotation nor invisible
		s2 = curvoice.last_sym


		// if the previous symbol is also a bar







		if (s2 && s2.type == C.BAR) {
//		&& !s2.a_gch && !s2.a_dd
//		&& !s.a_gch && !s.a_dd) {

				// remove the invisible variant bars
				// when no shift is needed
				if ((bar_type == "["
				  && !s2.text)


				 || s.norepbra) {



					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.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 == "|:") {
					switch (s2.bar_type) {
					case ":|":		// :| + |: => ::
						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
	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 */
	if (s.rbstart
	 && bar_type != "["
	 && !curvoice.norepbra
	 && s.st > 0
	 && !(par_sy.staves[s.st - 1].flags & STOP_BAR)) {
		s2 = {
			type: C.BAR,
			fname: s.fname,
			istart: s.istart,
			iend: s.iend,
			bar_type: "[",
			multi: 0,
			invis: true,
			text: s.text,
			rbstart: 2
		}
		sym_link(s2);
		s2.st = s.st
		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







|
<
<
<
|
|
<
<
<
<
<
|
<
<
<
<
<
<
|
<
<
<







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 */

	// possibly shift the volta bracket if not on the first staff



	if (s.text && s.st > 0 && !s.norepbra
	 && !(par_sy.staves[s.st - 1].flags & STOP_BAR)





	 && bar_type != '[')






		s.xsh = 4			// volta shift




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

	if (!map[nn]) {
		nn = 'o' + nn.replace(/[',]+/, '')	// ' octave
		if (!map[nn]) {
			nn = 'k' + ntb[(pit + 75 -
					curvoice.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



	}





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








|
|
|
|




|
|







|
>
|
|
|
>
>
>
|
>
>
>
>
>







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(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[(note.pit + 75 -
					p_v.ckey.k_sf * 11) % 7]
			if (!map[nn]) {
				nn = 'all'		// 'all'
				if (!map[nn])
					return
			}
		}
	}
	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
	switch (line.next_char()) {
	case "'":
		line.index++
		return ty + C.SL_ABOVE
	case ",":
		line.index++
		return ty + C.SL_BELOW



	}
	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







>
>
>







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







<







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

					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
			s.fmr = 1		// full measure rest
			s.notes = [{
				pit: 18,
				dur: s.dur
			}]
		} else {
			glovar.mrest_p = true




		}
		break
	case 'y':
		s.type = C.SPACE;
		s.invis = true;
		s.dur = 0;
		c = line.next_char()







>
>
>
>







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
				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.tr_sco) {

				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]) {







<
<
<
<
<





>
>
>

>








>







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






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







<
|
|
<
<
<
<







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 (grace && s.ottava)
		grace.ottava = s.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
			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)
	}
} // get_deco()

// characters in the music line (ASCII only)
var nil = "0",
    char_tb = [
	nil, nil, nil, nil,		/* 00 - .. */
	nil, nil, nil, nil,







<
<
<
<
|
<







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
	}




	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
	"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) */
],
    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







|
<
<







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[]



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
// abc2svg - subs.js - text output
//
// Copyright (C) 2014-2022 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.


|







1
2
3
4
5
6
7
8
9
10
// abc2svg - subs.js - text output
//
// 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
	.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

















/* -- return the character width -- */
function cwid(c) {
	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 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

	// 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'

			document.body.appendChild(el)
			abc2svg.eltxt = el	// reused after new Abc()
		}

	    var	c,
		font = gene.curfont,
		h = font.size,
		w = 0,
		n = str.length,







|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


|







|















|










>

<







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]),
// 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, 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 (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

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

		}

	    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
			j = str.indexOf(';', i)
			if (j > 0 && j - i < 10) {
				i = j;
				c = 'a'		// XML character reference
			}
			break
		}
		w += cwid(c) * swfac
	}
	return [w, h]
    }
  }
})()

// convert a string to a SVG text, handling the font changes







|







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







<







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)

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

















	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);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










<






<







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':

		output += '" text-anchor="middle">'
		break
	case 'j':
		output += '" textLength="' + w.toFixed(1) + '">'
		break
	case 'r':

		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
	if (cfmt.titlecaps)
		return title.toUpperCase()
	return title
}

// return the width of the music line
function get_lwidth() {


	return (img.width - img.lm - img.rm
					- 2)	// for bar thickness at eol
			/ cfmt.scale
}

// header generation functions
function write_title(title, is_subtitle) {







>
>







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
	} 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
	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)' -- */







|







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 + 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
			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);
		w = wh[0];
		str = str.split('\n');
		xy_str(w, 0, str[0])
		for (j = 1; j < str.length; j++) {




			vskip(h);
			xy_str(w, 0, str[j])
		}
		vskip(h * .3);
		use_font(gene.curfont)
	}
}

/* -- write heading with format -- */
var info_font_init = {
	A: "info",







|


|

>
>
>
>

|

|







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, wh[1] * .22, head, null, null, wh);
		w = wh[0];
		str = str.split('\n');
		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, wh[1] * .22, str[j])
		}
		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
			}
			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

	}
	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)
				vskip(down1 - down2);
			i = 0
			while (1) {
				vskip(gene.curfont.size)
				if (composer)
					j = composer.indexOf("\n", i)
				else
					j = -1
				if (j < 0) {
					put_inf2r(xcomp, 0,
						composer ? composer.substring(i) : null,
						origin,
						align)
					break
				}

				xy_str(xcomp, 0, 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');
			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);
		xy_str(0, 0, info.P);
		down2 = 0
	}
	vskip(down2 + cfmt.musicspace)
}







<







<
|
>










<










<

<
|
<


|





|





>
|
<


<
<








|
>
|
<

<
<
<






|
|
>
>
|
>
|
|
<
|



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 = down2 = 0
	if (parse.ckey.k_bagpipe
	 && !cfmt.infoline
	 && cfmt.writefields.indexOf('R') >= 0)
		rhythm = info.R
	if (rhythm) {
		set_font("composer");

		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");

		if (cfmt.aligncomposer < 0) {
			xcomp = 0;
			align = ' '
		} else if (cfmt.aligncomposer == 0) {
			xcomp = lwidth * .5;
			align = 'c'
		} else {
			xcomp = lwidth;
			align = 'r'
		}

		if (composer || origin) {

			down2 = cfmt.composerspace + 2

			i = 0
			while (1) {
				down2 += gene.curfont.size
				if (composer)
					j = composer.indexOf("\n", i)
				else
					j = -1
				if (j < 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,
					composer.slice(i, j), align);

				i = j + 1
			}


		}

		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");
			down2 += cfmt.infospace + gene.curfont.size
			put_inf2r(lwidth, -down2 + gene.curfont.size *.22,
				rhythm, area, 'r')

		}



	}

	/* parts */
	if (info.P
	 && cfmt.writefields.indexOf('P') >= 0) {
		set_font("parts");
		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) {

		down2 = down1
	}
	vskip(down2 + cfmt.musicspace)
}
Changes to core/svg.js.
1
2
3
4
5
6
7
8
9
10
// abc2svg - svg.js - svg functions
//
// Copyright (C) 2014-2022 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.


|







1
2
3
4
5
6
7
8
9
10
// abc2svg - svg.js - svg functions
//
// 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
\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
	},
	defined_glyph = {},
	defs = '',
	fulldefs = '',		// unreferenced defs as <filter>
	stv_g = {		/* staff/voice graphic parameters */
		scale: 1,
		dy: 0,







|
>
|







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







|
|
|
|







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:-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
  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"},
  marcato: {x:-3, y:-2, c:"\ue4ac"},
  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
  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"},
  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







|
|
|
|

|















|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|







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, 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
  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:-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:-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
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:	{
		dx: 0,
		dy: 5,
		style: 'font:italic 14px text,serif'

	},
dacs:	{
		dx: 0,
		dy: 3,
		style: 'font:16px text,serif',
		anchor: ' text-anchor="middle"'
	},
pf:	{
		dx: 0,
		dy: 5,
		style: 'font:italic bold 16px text,serif'
	},
'@':	{
		dx: 0,
		dy: 5,
		style: 'font:12px text,sans-serif'
	}
}


function out_deco_str(x, y, name, str) {


	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))
		return
	}
	var	a, f,
		a_deco = deco_str_style[name]

	if (!a_deco) {
		xygl(x, y, name)


		return
	}
	x += a_deco.dx;


	y += a_deco.dy;
	if (!a_deco.def) {


		style += "\n." + name + " {" + a_deco.style + "}";
		a_deco.def = true
	}


	out_XYAB('<text x="X" y="Y" class="A"B>', x, y,
		name, a_deco.anchor || "");
	set_font("annotation");
	out_str(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)
	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)
	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) {







|


|
>

|


|





|
<
<
<
<
|


>

|
>
>


|
|


<
<

|
|
>
>


|
>
>
|
|
>
>
|
|
|
>
>



|

















|








|














<







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:	{				// cresc., decresc., dim., ...
		dx: 0,
		dy: 5,
		style: 'font:italic 14px text,serif',
		anchor: ' text-anchor="middle"'
	},
dacs:	{				// long repeats (da capo, fine...)
		dx: 0,
		dy: 3,
		style: 'font:bold 15px text,serif',
		anchor: ' text-anchor="middle"'
	},
pf:	{
		dx: 0,
		dy: 5,
		style: 'font:italic bold 16px text,serif',




		anchor: ' text-anchor="middle"'
	}
}
deco_str_style.at = deco_str_style.crdc

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">A</text>\n',
			x - 2, y, m_gl(de.dd.str))
		return
	}



	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
	}

    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(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, 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, 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) {

	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

var deco_l_tb = {
	glisq: out_glisq,
	gliss: out_gliss
}

function out_deco_long(x, y, de) {

	var	name = de.dd.glyph


	if (deco_l_tb[name])
		deco_l_tb[name](x, y, de)
	else
		error(1, null, "No function for decoration '$1'", name)












































}

// return a tempo note
function tempo_note(s, dur) {
    var	p,
	elts = identify_note(s, dur)








>
|
>

|
<
<

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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,
	name = de.dd.glyph,
	de1 = de.start

	if (!deco_l_tb[name]) {


		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

// create the SVG image of the block
function svg_flush() {
	if (multicol || !output || !user.img_out || posy == 0)
		return

    var	i, font,




	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 +
			' viewBox="0 0 ' + img.width.toFixed(0) + ' ' +
			 posy.toFixed(0) + '">\n'
	} 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 += fulldefs

	if (style || font_style) {
		head += '<style>' + font_style
		if (cfmt.fgcolor || cfmt.bgcolor) {
			head += '\n.f' + font.fid + (cfmt.fullsvg || '')
				+ '{'
				+ (cfmt.fgcolor ? ('color:' + cfmt.fgcolor + ';')
						: '')
				+ (cfmt.bgcolor ? ('background-color:' + cfmt.bgcolor)
						: '')
				+ '}'

		}

		head += 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)







>
>
>
>












|
|
<
<
|
<
<
|
|
<
|
<
|
<
<
|
|
<
|
|
|
|
|
>
|
>
|
<







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 != undefined)
		head += user.imagesize


	else


		head += ' width="' + w
			+ 'px" height="' + posy.toFixed(0) + 'px"'

	head += ' viewBox="0 0 ' + w + ' '

		+ posy.toFixed(0) + '"'


	if (cfmt.fgcolor || cfmt.bgcolor)
		head += ' style="'

			+ (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
	}
	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
	} else {
		style = '';
		fulldefs = ''
	}
	defs = '';
	posy = 0

}

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







|
|






>











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 < 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
// abc2svg - tail.js
//
// Copyright (C) 2014-2022 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.


|







1
2
3
4
5
6
7
8
9
10
// abc2svg - tail.js
//
// 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

// 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.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







>







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
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_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;

    var	hook_init		// set after setting the first module hooks

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







>
















|
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










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

Abc.prototype.y_set = y_set

























}	// 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
// abc2svg - tune.js - tune generation
//
// 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.


|







1
2
3
4
5
6
7
8
9
10
// abc2svg - tune.js - tune generation
//
// 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
		set_ref(s)
    if (!curvoice.ignore) {
	s.prev = curvoice.last_sym
	if (curvoice.last_sym)
		curvoice.last_sym.next = s
	else
		curvoice.sym = 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)







>
>







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
	}
	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
	8,	// custos
	6,	// sm (sequence marker, after bar)
	0,	// grace (must be null)
	2,	// key
	3,	// meter
	9,	// mrest
	9,	// note
	0,	// part
	9,	// rest
	4,	// space (before bar)
	0,	// staves
	7,	// stbrk
	0,	// tempo
	0,	// (free)
	0,	// block
	0	// remark
])

function sort_all() {
    var	s, s2, time, w, wmin, ir, fmt,
	fl, new_sy,
	nv = voice_tb.length,
	vtb = [],
	vn = [],			// voice indexed by range
	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

		ir = 0
		bt = ""
		while (1) {
			v = vn[ir++]
			if (v == undefined)
				break
			s = vtb[v]
			if (!s || !s.bar_type || s.invis)

				continue
			if (!bt) {
				bt = s.bar_type


				continue
			}
			if (s.bar_type != bt)
				break



		}




		if (!v)









			return			// no problem

		

		if (bt == "::" || bt == ":|") {

			ir = 0

			while (1) {
				v = vn[ir++]
				if (v == undefined)
					break
				s = vtb[v]
				if (!s || s.invis
				 || s.bar_type != "::")

					continue
				s2 = clone(s)

				s.bar_type = ":|"
				s2.bar_type = "|:"








				s2.next = s.next


				s2.prev = s
				s.next = s2
			}
		} else {
			error(2, s, "Different bars $1 and $2",
				bt, s.bar_type)
		}
	} // 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])
			vn[sy.voices[v].range] = v















	}







	// insert the first staff system in the top 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







|
|



|
|




|

|







|




|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<



|
<

|





|
>



>
>




>
>
>
|
>
>
>
>
|
>
>
>
>
>
>
>
>
>


|
>
|
>

>






|
>


>
|
|
>
>
>
>
>
>
>
>

>
>




|
|



<
<




|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
|







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([
	6,	// bar
	2,	// clef
	8,	// custos
	6,	// sm (sequence marker, after bar)
	0,	// grace (must be null)
	3,	// key
	4,	// meter
	9,	// mrest
	9,	// note
	0,	// part
	9,	// rest
	5,	// space (before bar)
	0,	// staves
	1,	// stbrk
	0,	// tempo
	0,	// (free)
	0,	// block
	0	// remark
])

function sort_all() {
    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

















	// check if different bars at the same time
	function b_chk() {
	    var	bt, s, s2, v, t,

		ir = 0

		while (1) {
			v = vn[ir++]
			if (v == undefined)
				break
			s = vtb[v]
			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 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

		// 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 != bt
				 || (bt == '|' && !s.text))
					continue
				s2 = clone(s)
				if (bt == "::") {
					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(1, s, "Different bars $1 and $2",
				(bt + (t || '')), (s.bar_type + (s.text || '')))
		}
	} // b_chk()



	// 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]) {
			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
				}
			}
		}
	}

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















		}
		// not reached
	}

	// loop on the symbols of all voices
	while (1) {
		if (new_sy) {







<
<




>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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


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

		if (wmin > 127)
			break			// done

		// check the type of the measure bars
		if (wmin == 5)			// 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)

				continue
			w = w_tb[s.type]

			if (s.type == C.GRACE && s.next && s.next.type == C.GRACE)
				w--




			if (s.time != time



			 || w != wmin)








				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
		}

		fl = wmin		/* start a new sequence if some width */
	}
}

// adjust some voice elements

function voice_adj(sys_chg) {
    var	p_voice, s, s2, v, sl




































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








|









|
>


>
|

>
>
>
>
|
>
>
>
|
>
>
>
>
>
>
>
>

>












>
|




>
|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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 == 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
			 || s.time != time)
				continue
			w = w_tb[s.type]
			if (!w
			 && 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.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 = 1 //true		// start a new sequence
	}
}

// adjust some voice elements
// (possible hook)
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

	// terminate voice cloning
	if (curvoice && curvoice.clone) {
		parse.istart = parse.eol
		do_cloning()
	}









	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)







>
>
>
>
>
>
>
>







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
						s.a_ly = s2.a_ly;
						s2.a_ly = null
						break
					}
					break
				}
				continue
			}

			if (s.feathered_beam)
				set_feathered_beam(s)





		}
	}
}

/* -- create a new staff system -- */
function new_syst(init) {
    var	st, v, sy_staff, p_voice,







<
|
|
|
>
>
>
>
>







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

			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
			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.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
			bar_tim = s.time
			wmeasure = s.wmeasure


			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)
					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
			}
			if (wmeasure == 1) {		// if M:none
				if (s.bar_dotted)
					continue
				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
			}

			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)
						rep_tim = bar_tim + k * wmeasure
					else
						rep_tim = tim
					if (!nu)
						s.bar_num = n
				} else {
					if (cfmt.contbarnb)
						bar_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 {
				n |= 0
				s.bar_num = n
			}
			if (!k)
				ptim = tim
			break
		}
	}







|
>












<
<
|
|


>
>









|











|



|










|

















|
<
<
|



|
|
<
<




|
<







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
		 && !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 (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)
					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
				break
			}
			if (wmeasure == 1) {		// if M:none
				if (s.bar_dotted)
					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
				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)


						rep_tim = tim - bar_tim
					if (!nu)
						s.bar_num = n
				} else {
					if (!cfmt.contbarnb)
						bar_tim = tim - rep_tim


					n = bar_num + (tim - bar_tim) / wmeasure
					if (n == (n | 0))
						s.bar_num = n
				}
			} else if (n == (n | 0)) {

				s.bar_num = n
			}
			if (!k)
				ptim = tim
			break
		}
	}
︙︙
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
		return

    var	i, note, notes, map, tmp, ns,
	ty = '',
	a = text.split(/\s+/)

	if (a.length < 3) {
		syntax(1, 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







|







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

	for (; i < a.length; i++) {
		switch (a[i]) {
		case "heads=":
			if (!a[++i]) {
				syntax(1, not_enough_p)
				break
			}
			map[0] = a[i].split(',')
			break
		case "print=":
		case "play=":

			if (!a[++i]) {
				syntax(1, not_enough_p)
				break
			}
			tmp = new scanBuf;
			tmp.buffer = a[i];
			note = parse_acc_pit(tmp)


			if (a[i - 1][1] == 'r')
				map[1] = note
			else
				map[3] = note
			break
		case "color=":
			if (!a[++i]) {
				syntax(1, 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]
	}
	// return undefined
} // get_transp()

/* -- process a pseudo-comment (%% or I:) -- */
// (possible hook)
Abc.prototype.do_pscom = function(text) {







|






>

|





>
>







|








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<















|
|
|
|







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, errs.not_enough_p)
				break
			}
			map[0] = a[i].split(',')
			break
		case "print=":
		case "play=":
		case "print_notrp=":
			if (!a[++i]) {
				syntax(1, errs.not_enough_p)
				break
			}
			tmp = new scanBuf;
			tmp.buffer = a[i];
			note = parse_acc_pit(tmp)
			if (a[i - 1][5] == '_')		// if print no transpose
				note.notrp = 1 //true
			if (a[i - 1][1] == 'r')
				map[1] = note
			else
				map[3] = note
			break
		case "color=":
			if (!a[++i]) {
				syntax(1, errs.not_enough_p)
				break
			}
			map[2] = a[i]
			break
		}
	}
}





























































// get a abcm2ps/abcMIDI compatible transposition value as a base-40 interval
// The value may be
// - [+|-]<number of semitones>[s|f]
// - <note1>[<note2>]  % <note2> default is 'c'
function get_transp(param) {
	if (param[0] == '0')
		return 0
	if ("123456789-+".indexOf(param[0]) >= 0) {	// by semi-tone
	    var	val = parseInt(param)
		if (isNaN(val) || val < -36 || val > 36) {
//fixme: no source reference...
			syntax(1, errs.bad_transp)
			return
		}
		val += 36
		val = ((val / 12 | 0) - 3) * 40 + abc2svg.isb40[val % 12]
		if (param.slice(-1) == 'b')
			val += 4
		return val
	}
	// return undefined
} // get_transp()

/* -- process a pseudo-comment (%% or I:) -- */
// (possible hook)
Abc.prototype.do_pscom = function(text) {
︙︙
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
			}
			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
	case "ottava":
		if (parse.state != 3)
			return
		n = parseInt(param)
		if (isNaN(n) || n < -2 || n > 2) {

			syntax(1, errs.bad_val, "%%ottava")
			return
		}


		glovar.ottava = true;

		parse.ottava.push(n)




		return
	case "repbra":
		if (curvoice)
			curvoice.norepbra = !get_bool(param)
		return
	case "repeat":
		if (parse.state != 3)







<
<
<
<
<


<
<
<
<

<
<
<
<
<
<
<
<

<
<
<
<
<
<
<



|

>
>
>
>
>
>
>
>
>
>
>
>
>





|
>



>
>
|
>
|
>
>
>
>







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":





		switch (param) {
		case "start":




		case "new":








		case "end":







			break
		default:
			syntax(1, "Unknown keyword '$1' in %%multicol", param)
			return
		}
		s = {
			type: C.BLOCK,
			subtype: "mc_" + param,
			dur: 0
		}
		if (parse.state >= 2) {
			curvoice = voice_tb[0]
			curvoice.eoln = 1 //true
			sym_link(s)
			return
		}
		set_ref(s)
		self.block_gen(s)
		return
	case "ottava":
		if (parse.state != 3)
			return
		n = parseInt(param)
		if (isNaN(n) || n < -2 || n > 2
		 || (!n && !curvoice.ottava)) {
			syntax(1, errs.bad_val, "%%ottava")
			return
		}
		k = n
		if (n) {
			curvoice.ottava = n
		} else {
			n = curvoice.ottava
			curvoice.ottava = 0
		}
		a_dcn.push(["15mb", "8vb", "", "8va", "15ma"][n + 2]
			+ (k ? '(' : ')'))
		return
	case "repbra":
		if (curvoice)
			curvoice.norepbra = !get_bool(param)
		return
	case "repeat":
		if (parse.state != 3)
︙︙
1085
1086
1087
1088
1089
1090
1091




1092
1093
1094
1095
1096
1097
1098
			}
			s.xmx = val
		} else {
			s.xmx = 14
		}
		sym_link(s)
		return




	case "stafflines":
	case "staffscale":
	case "staffnonote":
		set_v_param(cmd, param)
		return
	case "staves":
	case "score":







>
>
>
>







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
		case 0:
			cfmt.transp = 0
			// fall thru
		case 1:
			cfmt.transp = (cfmt.transp || 0) + val
			return
		}
		curvoice.tr_sco = val
		set_transp()
		return
	case "tune":
//fixme: to do
		return
	case "user":
		set_user(param)
		return







|
|







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

/* -- generate a piece of tune -- */
function generate() {
    var s, v, p_voice;

	if (a_dcn.length) {
		syntax(1, "Decoration without symbol")
		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();
	sort_all()			/* define the time / vertical sequences */

    if (tsfirst) {




	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)







|
















|



>
>
>
>









<
<
<







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(s) without symbol: $1", a_dcn)
		a_dcn = []
	}

	if (parse.tp) {
		syntax(1, "No end of tuplet")
		s = parse.tps
		if (s)
			delete s.tp
		delete parse.tp
	}

	if (vover) {
		syntax(1, "No end of voice overlay");
		get_vover(vover.bar ? '|' : ')')
	}

	self.voice_adj()
	sort_all()			/* define the time / vertical sequences */

    if (tsfirst) {
	for (v = 0; v < voice_tb.length; v++) {
		if (!voice_tb[v].key)
			voice_tb[v].key = parse.ckey	// set the starting key
	}
	if (user.anno_start)
		anno_start = a_start
	if (user.anno_stop)
		anno_stop = a_stop
	self.set_bar_num()

	if (info.P)
		tsfirst.parts = info.P	// for play




	// give the parser result to the application
	if (user.get_abcmodel)
		user.get_abcmodel(tsfirst, voice_tb, abc2svg.sym_name, info)

	if (user.img_out)		// if SVG generation
		self.output_music()
    } // (tsfirst)
︙︙
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

	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









		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



	}
	s.k_b40 = b40
	s.k_sf = abc2svg.b40sf[b40]

	// transpose the accidental list
	if (!s.k_a_acc)
		return

	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)
			+ curvoice.tr_sco

		a_acc[n] = {
			pit: abc2svg.b40p(b40),
			acc: abc2svg.b40a(b40) || 3
		}
	}
	s.k_a_acc = a_acc
}





















































/* -- 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 (parm) {
		a_vf = parse_staves(parm)	// => array of [vid, flags]
		if (!a_vf)
			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)
		/*
		 * 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]) {







|
|
>
>
>
|
>
>
>
>
>
>
>
>
>

|
|
>
>
>
>
>
|
|
>
|
>
|
>
>
>
>
|
>
>
>
>
>
|
|
>
|
>
>
|
>
>
>


<




>

|
|
<
<
|






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







>
>
>
>
>
>
>
>





>
>
>












<
|
|







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

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


	// transpose the accidental list
	if (!s.k_a_acc)
		return
	d = b40 - s.orig.k_b40
	a_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


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

	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






	}
	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







|
>
>
|
>
>
>
>
>
>







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.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
			p_voice = p_voice.voice_down
			if (!p_voice)
				break
			v = p_voice.v
		}
	}
	par_sy.top_voice = a_vf[0][0].v



	/* 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







>
>







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

		if (!par_sy.voices[v])
			continue

		// set the staff of the overlay voices
		p_voice2 = p_voice.voice_down
		while (p_voice2) {

			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
		 && !(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







>








|



<
<







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 == undefined
		 && !(par_sy.staves[st - 1].flags & STOP_BAR))
			p_voice.norepbra = true
	}



	curvoice = parse.state >= 2 ? voice_tb[par_sy.top_voice] : null
}

	// get a voice or create a clone of the current voice
	function clone_voice(id) {
		var v, p_voice
︙︙
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
	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
	    else
		for (s = curvoice.last_sym; /*s*/; s = s.prev) {
			if (s.type == C.BAR
			 || s.time <= time)	/* (if start of tune) */
				break
		}
		vover = {







|







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 = 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
		if (w_tb[s.type])
			return false
	return true
}

// treat a clef found in the tune body
function get_clef(s) {













	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
		s.prev = s2.prev
		if (s.prev)



			s.prev.next = s
		s2.prev = s
		s2.next = null
		curvoice.last_sym = s2
		if (s.soln) {
			delete s.soln
			curvoice.eoln = true
		}


	}



}

// treat K: (kp = key signature + parameters)
function get_key(parm) {
    var	v, p_voice, transp, sndtran, tr_p, nt,
//		[s_key, a] = new_key(parm)	// KO with nodejs
		a = new_key(parm),
		s_key = a[0],
		s = s_key


	a = a[1]






	if (parse.state == 1) {		// in tune header (first K:)

		if (s_key.k_sf == undefined && !s_key.k_a_acc) { // empty K:
			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 = ''
		}


		goto_tune()
	} else {
		set_kv_parm(a)
	}

	tr_p = curvoice.tr_p			// transposition change 1=sco, 2=snd
	curvoice.tr_p = 0
	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

	}


	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

	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()) {
		s_key.fmt = cfmt

		curvoice.key = clone(s_key)
		if (s_key.k_none)
			curvoice.key.k_sf = 0
	} else {
		sym_link(s_key)			// (don't move the key)
	}


}

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







>
>
>
>
>
>
>
>
>
>
>
>
>







|
|
|
>
>
>
>
>
>
>
|
>
>
>
|
|
>
|
|
|
|
<
|
>
>
>
|
|
<





>
>

>
>
>




|



|
>



>
>
>
>
>
|
>
|






<
<


<
<
<


|

>
>

|
<
<
|
<
|
<
<
<
<
|
|
>


|
|
|
|
|
>
|
|
<
<
<
|
<
<

|
|
<
>
|
|
|
<
<
|
>
>














|
<
<
<
<
<
<
<
<







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
	}

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

	if (s3) {
		s2 = curvoice.last_sym
		curvoice.last_sym = s3.prev
		sym_link(s)
		s.next = s3
		s3.prev = s

		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,
//		[s_key, a] = new_key(parm)	// KO with nodejs
		a = new_key(parm),
		s_key = a[0],
		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:)
		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.ckey = clone(s_key)
		}



		if (a.length) {
			memo_kv_parm('*', a)
			a = []
		}
		if (!glovar.ulen)
			glovar.ulen = C.BLEN / 8;
		goto_tune()
	} else if (!empty) {


		if (curvoice.tr_sco)

			curvoice.tr_sco = undefined




		s.k_old_sf = curvoice.ckey.k_sf	// memorize the previous key
		curvoice.ckey = s
		sym_link(s)
	}

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



	}



	p_voice = curvoice.clone
	if (p_voice)

		curvoice.clone = null		// don't stop the multi-voice sequence
	get_voice(curvoice.id + ' ' + a.join(' '))
	if (p_voice)
		curvoice.clone = p_voice



	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
			p_voice.init = 0	// set back the global voice parameters








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












//	par_sy.voices[v] = {
//		range: -1
//	}

	return p_voice
}








|
|
<
















>
>
>
>
>
>
>
>
>
>
>







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)

		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
// 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,
	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)
		tosvg(parse.fname, file, bol, eol)
	}
	include--
	parse = parse_sav	// restore the parse context
}

// treat a 'V:' info







|













|







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.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.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
	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,
			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()
	}


	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;







|







<
<
<
|
>







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.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)




	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
		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
		 && !p_voice.pos.stm) {
			p_voice.pos = clone(p_voice.pos)
			p_voice.pos.stm &= ~0x07
			p_voice.pos.stm |= C.SL_BELOW
		}
	}








<
<
<
<
<
<
<
<
<
<
<




|







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












	// update some voice parameters
	for (v = 0; v < voice_tb.length; v++) {
		p_voice = voice_tb[v];
		p_voice.ulen = glovar.ulen
		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
COPYING
COPYING.LESSER
MIDI-1.js
Scc1t2/
abc2svg-1.js
abc2svg.ttf
abc2svg.woff

abcdoc-1.js
abcjsc
abcmjs
abcnode
abcqjs
abctopdf
abcweb1-1.js







>







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
// edit.js - file used in the abc2svg editor
//
// Copyright (C) 2014-2022 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.


|







1
2
3
4
5
6
7
8
9
10
// edit.js - file used in the abc2svg editor
//
// 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
			"\nLine: " + line)
	else if (typeof msg == 'object')
		alert("window error: " + msg.type + ' ' + msg.target.src)
	else
		alert("window error: " + msg)
	return false
}







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

	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(/.*\//) || ''







>
>
>
>
>
>













>







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

	// 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];

		src_change()
	}

	// Read the file as text
	reader.readAsText(files[0], "UTF-8")
}








>







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
			selsrc(1);
			alert(texts.load + sl.value)
			return
		}
	}
	elt_ref.diverr.innerHTML = '';
	selx[0] = selx[1] = 0;

	render2()
}
function render2() {
    var	content = elt_ref.source.value,
	def = (abc2svg.a_inc && abc2svg.a_inc["default.abc"]) || ''

	// load the required modules







>







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
	link.style.display = "none";

	// add the link to the DOM
	document.body.appendChild(link);

	// click the new link
	link.click()


}

// destroy the clicked element
function destroyClickedElement(evt) {
	document.body.removeChild(evt.target)
}








>
>







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
			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) {







<







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







>







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
			}
			sym = sym.ts_prev
		}
		// not reached
	}

	function gsot(si) {		// go to the first symbol of a tune




		return syms[si].p_v.sym
	}
	function get_se(si) {			// get the starting symbol
	    var	sym = syms[si]

		while (!sym.seqst)
			sym = sym.ts_prev
		return sym







>
>
>
>
|







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

			src_change()
		}
		reader.readAsText(data[0],"UTF-8")
//		return
	}
}








>







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
<body ontouchstart="" bgcolor="#faf0e6" spellcheck="false">

<!-- left -->
<div id="dleft">

<!-- menu bar -->
    <ul id="nav">
	<li class="dropbutton"><label id="f">File</label>
		<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>
		</ul>
	</li>
	<li class="dropbutton"><label id="pr">Preferences</label>
		<ul class="droplinks">
			<li><label id="fs">Font size</label>
			    <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>
				 <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>
				 <input id="gvol" type="range" min="1" max="10" value="7"
					onchange="set_vol(this.value / 10)"/>
				<label id="gvl">0.70</label>
			</li>
			<li id="playdiv4" style="display: none">
				<label id="sp">Speed</label>
				 <input id="spv" type="range"
					min="1" max="20" value="10" step=".5"
					onchange="set_speed(this.value)"/>
				<label id="spvl">1</label>
			</li>
		</ul>
	</li>
	<li class="dropbutton"><label id="lg">Language</label>
		<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>
		<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>
<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>

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







|





|


|

|




|





|


|


|



|



|








|
















|




|
|







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"><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><span id="saveas">Save file</span></li>
		</ul>
	</li>
	<li class="dropbutton"><span id="pr">Preferences</span>
		<ul class="droplinks">
			<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">
				<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">
				<span id="gv">Volume</span>
				 <input id="gvol" type="range" min="1" max="10" value="7"
					onchange="set_vol(this.value / 10)"/>
				<span id="gvl">0.70</span>
			</li>
			<li id="playdiv4" style="display: none">
				<span id="sp">Speed</span>
				 <input id="spv" type="range"
					min="1" max="20" value="10" step=".5"
					onchange="set_speed(this.value)"/>
				<span id="spvl">1</span>
			</li>
		</ul>
	</li>
	<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"><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>
<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=""/>
<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
</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
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>







|












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-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
	"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",
	"Double voice in %%score": "Double voice in %%score",
    "Empty line in tune header - ignored": "Leerzeile in Kopfbereich - ignoriert",

	"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",







|


>







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(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
		"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",

	"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 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 '-'",







>













>







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
			"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 without symbol": "Pas de symbole où mettre la décoration",
	"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 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",







>
|



>
>







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":
			"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
		"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é",

	"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 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 '-'",







>
















>







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
			"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",
	"Double voice in %%score": "Double voice in %%score",
	"Empty line in tune header - ignored":
				"Linea vuota nella testata - ignorata",

	"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",







|



>







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(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
		"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",

	"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 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 '-'",







>















>







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
	"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",
	"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 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",
	"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",







|



>



|







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(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": "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
		"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",

	"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 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 '-'",







>
















>







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
// abc2svg music font
var musicfont = 'url("data:application/octet-stream;base64,\
AAEAAAAOAIAAAwBgRkZUTY1L868AAFgoAAAAHEdERUYAFQAUAABYDAAAABxPUy8yWMFdCgAAAWgA\
AABWY21hcFz/TQsAAAQIAAADemN2dCAAIgKIAAAHhAAAAARnYXNw//8AAwAAWAQAAAAIZ2x5Zg27\
S/YAAAiwAABGeGhlYWQTZto6AAAA7AAAADZoaGVhCWn/GwAAASQAAAAkaG10eNlp+7kAAAHAAAAC\
SGxvY2HP4L6kAAAHiAAAASZtYXhwANkBFgAAAUgAAAAgbmFtZdbpNH4AAE8oAAADJHBvc3SIfxKM\
AABSTAAABbUAAQAAAAEAAF56eDVfDzz1AAsEAAAAAADRlyIXAAAAAN4tda//OPzvBUsEiAAAAAgA\
AgAAAAAAAAABAAAEiPzvAFwEJf84/XQFSwABAAAAAAAAAAAAAAAAAAAAkgABAAAAkgDlAAUAAAAA\
AAIAAAABAAEAAABAAC4AAAAAAAEBgAGQAAUACAKZAswAAACPApkCzAAAAesAMwEJAAACAAUDAAAA\
AAAAAAAAARAAAAAAAAAAAAAAAFBmRWQAQAAA7LcDOP84AFwEiAMRAAAAAQAAAAAAAAF2ACIAAAAA\
AVUAAAGQAAACWAAAAFcAAAAjAAAAJQAAACT//wBkAAAEIwAABCUAAAHg/9wDXgB6AwsAAALSAAAC\
v/+6AdYAAAMLAAADDgAAAyf/yADIAAABaP//Aa4AAAEiAAABkAAAAXwAAAGQAAABkAAAAYEAAAGQ\
AAABkAAAAYEAAAGZAAkBmAAJAfQAAAEEABQBBAAKAmsAJAISAAABwgAAAUkAAAFAAAABSv/+ASwA\
AAIwAAABSgAAAUoAAABkAAABQAAAAUAAAAFAAAABQAAAAGQAAAE2AAAA5gAAATYAAAE7AAABOwAA\
ATsAAAE7AAABOwAAATsAAAE7AAABOwAAATsAAAE7AAABDQAAAMgAAAD/AAABCwAUAW4AAACMAAAA\
jAAAAQ0AMgFu//UAqQAAAToAAAFA//0AUAAAAVQAAABkAAABGAAAAlgAAAC2AAABkAAEAIIAAACC\
AAABLAAAASwAAADuAAAA/wAAAUkAAAGPAAAB2AAAAdgAAAIz//ADIP/hAXv/tAG4/9sBFv9+ARP/\
2wDcAAAA6P/kAr//tAIz/7QCv/+0Ayv/2wFf/9sCaf9+AV//fgJp/34BXwAAAf0ABQG1AAABtQAA\
AkQADQJEAA0BGAAAATYAAAEs//8BLAAAAPoAAADIAAABGP84APoAAADIAAAEDQAAAhwADAH0AAAB\
9AAAAfQAAAH0AAAB9AAAAfQAAAB4AAAALQAAAhwAAAD6AAAA+v/oAcIAAAFIAAABQAAAAgoAAAIK\
AAAAZAAAAAAAAwAAAAMAAAAcAAEAAAAAAnQAAwABAAAAHAAEAlgAAACSAIAABgASAAAAIOAA4DDg\
OeBD4EjgUOBc4GLgaeB+4IzgleCk4Kngs+EB4bnhu+Hn4fLh9OH34fnh/OIA4kniZOJr4oPkoOSi\
5KTkqOSs5MDkzuTR5OrlAeUl5S3lMeU55WflaeVt5YLl0OXi5hDmEuYU5hjmJOYw5lDmVekS6RXp\
GOkg6SXpXeoC6qTso+yl7Kfsqey3//8AAAAAACDgAOAw4DjgQ+BF4FDgXOBi4GngeuCA4JTgoOCp\
4LPhAeG54bvh5+Hy4fTh9+H54fzh/uJA4mDiauKA5KDkouSk5KjkrOTA5M7k0eTh5QDlIOUp5S/l\
OeVm5WnlbOWC5dDl4uYQ5hLmFOYY5iTmMOZQ5lXpEOkU6RjpIOkl6V3qAuqk7KLspeyn7Knst///\

AAP/5CAFH9Yfzx/GH8Ufvh+zH64fqB+YH5cfkB+GH4IfeR8sHnUedB5JHj8ePh48HjseOR44Hfkd\
4x3eHcobrhutG6wbqRumG5MbhhuEG3UbYBtCGz8bPhs3GwsbChsIGvQapxqWGmkaaBpnGmQaWRpO\
Gi8aKxdxF3AXbhdnF2MXLBaIFecT6hPpE+gT5xPaAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\



AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\

AAAAAAAAAAAAAQYAAAMAAAAAAAAAAQIAAAACAAAAAAAAAAAAAAAAAAAAAQAABAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiAogAAAAqACoAKgA2\
AD4AbgB6AIYAkgCwASQBgAHwAjICvgNQA7ADxARgBPIFSgWKBiQGRgZaBqwG/AccB2IHogfcCCgI\
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\
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\
Q1SGKUl4RAMNBCldQ1SGKUl4RAMNBCldQ1QAAAAFAAD9VQE8AhIAJAAyAEAATgBcAAAZATMeBhUU\
BxYVFAcWFRQHFhUUBxYVFAc2NTQuAyM1HgMXNDY1NC4DJx4DFzQ2NTQuAyceAxc0NjU0LgMnHgMX\
NDY1NC4DHgYnMzs4LhwSEhISEhISEx4FKT5IQBYJRE1WFQEpPkhBFglETVYVASk+SEEWCURNVhUB\
KT5IQRYJRE1WFQEpPkhB/rsDVxs5Mzc6PUglLCsnLSwrJy0sKyctLCspKzY5GSE3ZEU0GKskVENd\
KQMNBDdlRTMZqyRUQ10pBAwEN2VFMxmrJFRDXSkDDgM3ZUUzGaskVENdKQQMBDdlRTMZAAAFAAD9\
vAE8AnkAIwAwAD0ASgBXAAAZATMyPgI1NCcWFRQHFhUUBxYVFAcWFRQHFhUUDgUHNTI+AjU0JjUO\
AycyPgI1NCY1DgMnMj4CNTQmNQ4DJzI+AjU0JjUOAx4cVVc9BR4TEhISEhISEhwuODszJwYdVVc9\
ARVWTUQJHVVXPQEVVk1ECR1VVz0BFVZNRAkdVVc9ARVWTUT9vANXKUh3RCEZOTYrKSssLScrLC0n\
KywtJyssJUg9OjczORuqKUl4RAMNBCldQ1SGKUl4RAMNBCldQ1SGKUl4RAMNBCldQ1SGKUl4RAMN\
BCldQ1QAAAACAAD/ZADhAbAACgAWAAA3IgYdATY3NjU0JjcyFhUUBwYjETMRNmcUKyImKx0HIzlL\
UkQoI3omE7kPODsvGyYmMiNJTFICTP68NAAAAgAA/oYAxQF6AAMADAAAFzc1BxEVNxEjNQcRNxyQ\
kKkZrAFlLZYtAUnoNP3A4jMCQwEAAAIAAP6YAP8BaAADAB8AADcVNzUDIzUHNTc1BzU3NTMVNzUz\
FTcVBxU3FQcVIzUHU1paHjU1NTUeWh01NTU1HVpGpxun/jejD1wPpw9aD6ifHKujD1wPpw9aD6if\
HAAAAAEAFP+EAQsAegAeAAAXNSYnBzAVIzUzNycwIzUzFRYXNzA1MxUjBgcXMDMVwygMM0g5MzM5\
SCESNEg5IRM0OXw7Jg0zO0oyMkg5IhEzOUciETRIAAQAAP9qAWwBsAAOABwAKwA6AAA3DgEdATI3\
Njc2NTQnJiM3MhYVFAcGBwYjETMRNhcOAR0BMjc2NzY1NCcmIzcyFhUUBwYHDgEjETMRNk4RHg4e\
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\

IyImNTQ2MzIWFRQHMj8BBiMiJjU0NjMyFhUUBzI/ASIOASMiJjU0NjMyFhUUBzI3NjIXAScTBiMi\


JjU0NjMyFhUUBzI/AQYjIiY1NDYzMhYVFAcyNwE/KCErNycbHCkXQQs2KB8rNycbHCkXPws0ASAc\


Eys3JxscKRdILgEWA/5qLVUoISs3JxscKRdBCzooISs3JxscKRdBCzQMKCggIB8ZHRsixAwoKCAg\
HxkdGyLHCQQpKB8gHhkdG00CAvqADAEkDCgoICAfGR0bIsgMKCggIB8ZHRsiAAP/8P8GAiYA+gAH\
AA8AEwAANiImNDYyFhQAIiY0NjIWFAUBMwFQMiMjMiMBiDIjIzIj/dIBuH7+R0sjMiMjMv7PIzIj\
IzJaAfT+DAAE/+H/BgMHAPoABwAPABMAFwAANiImNDYyFhQAIiY0NjIWFAUBMwEzATMBQTIjIzIj\
AncyIyMyI/zjAbh7/kd5Abh7/kdLIzIjIzL+zyMyIyMyWgH0/gwB9P4MAAL/tP+IAXwBGAARADsA\




ADcWMzI2NzY1NCcmIyIGBwYVFBciJwczMhQrASI0OwETNjU0IyIOAwcGJjc2NzYzMhYXPgEzMhYV\
FAbFAgUSMg4NDwIEEjULDycqGS00CwvhCwtLaAYLCAwPCxkKBRsFMQ8XJSMkBx0mIx4tWSgBNSQg\
JiUFATMcJyQpLiB6Hh4BHRIMDwcUEiwQCA8JWBAZExoeDzQwSWsAAAH/2//2Ab4BGABTAAA3BgcG\
KwEiPwE2JiMiBgcGJjc+AzMyFzYzMhc+ATMyFhUUDwEGFRQzMjc+BTc2FgcOAiMiJjU0PwE2NTQj\







Ig8BBgcnBiY/ATY1NCMiB1AHCAQENQ0NQgQGCA0WJAUVBBQQIh8SNwskJC0JCykTGSQFLwQIAQQF\
CwcMAw0BBhUGEhctHxUZBTQBFRsIQQgPJg0IBEMBFRsIFREDARqnDQ8aOQgMCSUaMBIoKCgQGCMa\
Cw99CwkOAgMJBg8FEgEJDQsfHxoWEw0NiAIEDhSrFgEBAQ8IqwIEDhQAAAAB/37/YAFeAbgAQQAA\
ByImNTQ2MzIWFRQHBhUUMzI+BzcjIjU0OwE+ATMyFhUUBiMiJjU0NzY0IyIOBwczMhQrAQ4BMiAw\
FxMSFxIKGQsQDwsNCg4NFAo1ExFBFGk0IDAXExIXEgoZBwwKBwgFBgMGATYTEz8hdqAmIBoiFA8O\
CwcNDgYREyUkPDdVJxUTS18mIBoiFA8OCwYcBQsKFA0aDR4GKMXBAAAB/9sAAAETARMAKgAANz4B\
JiMiBg8BBgcGKwEiPwE2JiMiBgcGJjc+ATMyFhc2MzIWFRQjIiY1NNAFAwMFFCQJPwcIBAQ1DQ1C\
BAYIDhciBRUEITgiGx0EHyQaICsPG+cDBwQsGJwRAwEaow0PGjUIDAk8QBoNJx4ZNxYNFAAAAAEA\
AAAAANwBGAAxAAAzIiY1NDYyFhUUBxYzMjY1NC4CJyY1NDYzMhYVFAYjIiY1NDcmIyIGFRQeAhcW\
FRRQHjIVGhcQDBMWIQkLGAY6Ny0iNhYQDRYHDxEPGRESHgUwKxsQFhAMEhAQFhILDwcNBCUwIygk\
GBAYFA4DDhMRDQkTDBEDICtVAAAB/+T//ADnAQ8APAAAJwYuAT8BIgYjIiYOAQcGJyY3PgE3HgEz\
MjYzMhcWFA8BBhUUMzI2MzIXFjc2JyI1NDYzMhUUBisBLgEjIgoGCwEFsAUfDAMUDB8FDwQDCAwL\
AQ4vFSIrBAgFCweeAgIBDQYaIw0IBQckEg0mKB4dGCUIDgMECA0GwQYGAjIFDQsJEh4wAgEGCwEB\
EQenBgIDAxoKDg0DHQ4VNx4vAxgABf+0/4gFSwEYABEAIwC2AMgA2gAAJRYzMjY3NjU0JyYjIgYH\


BhUUBRYzMjY3NjU0JyYjIgYHBhUUFyInBzMyFCsBIjQ7ARM2NTQjIg4DBwYmNzY3NjMyFhc+ATMy\
Fz4BMzIWFz4BMzIXPgEzMhYXPgEzMhc+ATMyFhc+ATMyFhUUBiMiJwczMhQrASI0OwETNjU0IyIG\
BxUUBiMiJwczMhQrASI0OwETNjU0IyIGBxUUBiMiJwczMhQrASI0OwETNjU0IyIGBxUUBiUWMzI2\
NzY1NCcmIyIGBwYVFAUWMzI2NzY1NCcmIyIGBwYVFAIKAwQSMg4NDwMDEzQLD/7LAwQSMg4NDwMD\

EzQLDxMWGS00CwvhCwtLaAYLCAwPCxkKBRsFMQ8XJSMkBx0mIy8TEiIbIyQHHSYjLxMSIhsjJAcd\
JiMvExIiGyMkBx0mIx4ta0kWGS00CwvhCwtLaAYLDhQUa0kWGS00CwvhCwtLaAYLDhQUa0kWGS00\
CwvhCwtLaAYLDhQUawODAwQSMg4NDwMDEzQLD/7LAwQSMg4NDwMDEzQLDygBNSQhJSQGATMcJiUo\

BwE1JCElJAYBMxwmJSgvIHoeHgEdEA4PBxQSLBAIDwlYEBkTGh4PMhwWExoeDzIcFhMaHg8yHBYT\
Gh4PNDBHbSB6Hh4BHRAODxgjAUdtIHoeHgEdEA4PGCMBR20geh4eAR0QDg8YIwFHbSgBNSQhJSQG\








ATMcJiUoBwE1JCElJAYBMxwmJSgAAAAE/7T/iAQGARgAbwCBAJMApQAAISInBzMyFCsBIjQ7ARM2\
NTQjIgYHFRQGIyInBzMyFCsBIjQ7ARM2NTQjIgYHFRQGIyInBzMyFCsBIjQ7ARM2NTQjIg4DBwYm\
NzY3NjMyFhc+ATMyFz4BMzIWFz4BMzIXPgEzMhYXPgEzMhYVFAYnFjMyNjc2NTQnJiMiBgcGFRQF\
FjMyNjc2NTQnJiMiBgcGFRQFFjMyNjc2NTQnJiMiBgcGFRQDUhYZLTQLC+ELC0toBgsOFBRrSRYZ\
LTQLC+ELC0toBgsOFBRrSRYZLTQLC+ELC0toBgsIDA8LGQoFGwUxDxclIyQHHSYjLxMSIhsjJAcd\
JiMvExIiGyMkBx0mIx4ta0wDBBIyDg0PAwMTNAsP/ssDBBIyDg0PAwMTNAsP/ssDBBIyDg0PAwMT\
NAsPIHoeHgEdEA4PGCMBR20geh4eAR0QDg8YIwFHbSB6Hh4BHRAODwcUEiwQCA8JWBAZExoeDzIc\
FhMaHg8yHBYTGh4PNDBHbSgBNSQhJSQGATMcJiUoBwE1JCElJAYBMxwmJSgHATUkISUkBgEzHCYl\
KAAAA/+0/4gCwQEYAEwAXgBwAAAzIicHMzIUKwEiNDsBEzY1NCMiDgMHBiY3Njc2MzIWFz4BMzIX\
PgEzMhYXPgEzMhYVFAYjIicHMzIUKwEiNDsBEzY1NCMiBgcVFAYnFjMyNjc2NTQnJiMiBgcGFRQF\
FjMyNjc2NTQnJiMiBgcGFRTIFhktNAsL4QsLS2gGCwgMDwsZCgUbBTEPFyUjJAcdJiMvExIiGyMk\
Bx0mIx4ta0kWGS00CwvhCwtLaAYLDhQUa0wDBBIyDg0PAwMTNAsPAVUDBBIyDg0PAwMTNAsPIHoe\
HgEdEA4PBxQSLBAIDwlYEBkTGh4PMhwWExoeDzQwR20geh4eAR0QDg8YIwFHbSgBNSQhJSQGATMc\
JiUoBwE1JCElJAYBMxwmJSgAAv/b/4gDKwEYAHIAhAAAJTY3NjMyFhc+ATMyFhUUBiMiJwczMhQr\

ASI0OwETNjU0IyIOAwcOASMiJjU0PwE2NTQjIg8BBgcnBiY/ATY1NCMiDwEGBwYrASI/ATYmIyIG\
BwYmNz4DMzIXNjMyFz4BMzIWFRQPAQYVFDMyNz4BFxYzMjY3NjU0JyYjIgYHBhUUAa0xFBgiIyQH\
HSYjHi1rSRYZLTQLC+ELC0toBgsHDxIOGAgaPC0VGQU0ARUbCEEIDyYNCARDARUbCEQHCAQENQ0N\
QgQGCA0WJAUVBBQQIh8SNwskJC0JCykTGSQFLwQIAgMPJdEDBBIyDg0PAwMTNAsPd2wYHRMaHg80\
MEdtIHoeHgEdEA4PDR8bNRA2OBUUDA6IAwMOFKsWAQEBDwirAwMOFKwRAwEapw0PGjkIDAklGjAS\
KCgoEBgjGg0NfQsJDgIINTkBNSQhJSQGATMcJiUoAAAC/9v/YAMZAbgAUwCZAAA3BgcGKwEiPwE2\
JiMiBgcGJjc+AzMyFzYzMhc+ATMyFhUUDwEGFRQzMjc+BTc2FgcOAiMiJjU0PwE2NTQjIg8BBgcn\
BiY/ATY1NCMiBxMiJjU0NjMyFhUUBwYVFDMyPgc3IyImNTQ2OwE+ATMyFhUUBiMiJjU0NzY0IyIO\


BwczMhYUBisBDgFQBwgEBDUNDUIEBggNFiQFFQQUECIfEjcLJCQtCQspExkkBS8ECAIDBQsHDAMN\
AQYVBhIXLR8VGQU0ARUbCEEIDyYNCARDARUbCPUgMBcTEhcSChkLEA8LDQoODRQKNQkKCQhBFGk0\





IDAXExIXEgoZBwwKBwgFBgMGATYJCwsJPyF2FREDARqnDQ8aOQgMCSUaMBIoKCgQGCMaDQ19CwkO\

AgMJBg8FEgEJDQsfHxoVFAwOiAMDDhSrFgEBAQ8IqwMDDhT+nyYgGiIUDw4LBw0OBhETJSQ8N1Un\




DAkIC0tfJiAaIhQPDgsGHAULChQNGg0eBgwQDMXBAAAAAf9+/2ACaQG4AHgAACUjDgEjIiY1NDYz\


MhYVFAcGFRQzMj4HNyMiJjU0NjsBPgEzMhYVFAYjIiY1NDc2NCMiBwYHFz4BMzIWFRQGIyImNTQ3\

NjQjIg4HBzMyFhQGKwEOASMiJjU0NjMyFhUUBwYVFDMyPgcBX5shdl8gMBcTEhcSChkLEA8LDQoO\
DRQKNQkKCQhBFGk0IDAXExIXEgoZJhcDAZsUaTQgMBcTEhcSChkHDAoHCAUGAwYBNgkLCwk/IXZf\
IDAXExIXEgoZCxAPCw0KDw0U5sXBJiAaIhQPDgsHDQ4GERMlJDw3VScMCQgLS18mIBoiFA8OCwYc\
cwwGAUtfJiAaIhQPDgsGHAULChQNGg0eBgwQDMXBJiAaIhQPDgsHDQ4GERMlJDw3VQAAAAH/fv9g\
A3QBuACuAAATMz4BMzIWFRQGIyImNTQ3NjQjIgcGBxc+ATMyFhUUBiMiJjU0NzY0IyIOBwczMhYU\
BisBDgEjIiY1NDYzMhYVFAcGFRQzMj4HNyMOASMiJjU0NjMyFhUUBwYVFDMyPgc3Iw4BIyImNTQ2\
MzIWFRQHBhUUMzI+BzcjIiY1NDY7AT4BMzIWFRQGIyImNTQ3NjQjIg4CBwbMnBRpNCAwFxMSFxIK\
GSYXAwGbFGk0IDAXExIXEgoZBwwKBwgFBgMGATYJCgoJPyF2XyAwFxMSFxIKGQsQDwsNCg8NFAqb\
IXZfIDAXExIXEgoZCxAPCw0KDg0VCpshdl8gMBcTEhcSChkLEA8LDQoODRQKNQkKCQhBFGk0IDAX\
ExIXEgoZDhUOCAYCAQ5LXyYgGiIUDw4LBhxzDAYBS18mIBoiFA8OCwYcBQsKFA0aDR4GDBAMxcEm\
IBoiFA8OCwcNDgYREyUkPDdVJ8XBJiAaIhQPDgsHDQ4GERMlJDs4VSfFwSYgGiIUDw4LBw0OBhET\
JSQ8N1UnDAkIC0tfJiAaIhQPDgsGHBMnIhsKAAH/fv9gBIABuADkAAABFz4BMzIWFRQGIyImNTQ3\
NjQjIgcGBxc+ATMyFhUUBiMiJjU0NzY0IyIOBwczMhYUBisBDgEjIiY1NDYzMhYVFAcGFRQzMj4H\
NyMOASMiJjU0NjMyFhUUBwYVFDMyPgc3Iw4BIyImNTQ2MzIWFRQHBhUUMzI+BzcjDgEjIiY1NDYz\
MhYVFAcGFRQzMj4HNyMiJjU0NjsBPgEzMhYVFAYjIiY1NDc2NCMiBwYHFz4BMzIWFRQGIyImNTQ3\
NjQjIg4HAdicFGk0IDAXExIXEgoZJhcDAZsUaTQgMBcTEhcSChkHDAoHCAUGAwYBNgkKCgk/IXZf\
IDAXExIXEgoZCxAPCw0KDw0UCpshdl8gMBcTEhcSChkLEA8LDQoODRQKmyF2XyAwFxMSFxIKGQsQ\
DwsNCg8NFAqbIXZfIDAXExIXEgoZCxAPCw0KDg0UCjUJCgkIQRRpNCAwFxMSFxIKGSYXAwGbFGk0\
IDAXExIXEgoZBwwKBwgFBgMGAQ8BS18mIBoiFA8OCwYccwwGAUtfJiAaIhQPDgsGHAULChQNGg0e\
BgwQDMXBJiAaIhQPDgsHDQ4GERMlJDw3VSfFwSYgGiIUDw4LBw0OBhETJSM8N1YnxcEmIBoiFA8O\
CwcNDgYREyUkPDdVJ8XBJiAaIhQPDgsHDQ4GERMlJDw3VScMCQgLS18mIBoiFA8OCwYccwwGAUtf\

JiAaIhQPDgsGHAUKCxMOGQ4dAAAAAAMAAP9gAt8BuAA2AHIAuwAAMyImNTQ2MzIWFRQHFjMyNjU0\
LgMnLgI1NDYzMhYVFAYjIiY1NDcmIyIGFRQeAhceARUUJQYuAT8BJiMiBiMiDgEHBicmNz4BNxYz\
MjYzMhcWFA8BBhUUHgEXFj4BJy4BNTQ2MzIVFAYjIiMuASMiBSImNTQ2MzIWFRQHDgEeARUUFjI+\
BzcjIiY1NDY7AT4BMzIWFRQGIyImNTQ3NjQjIg4HBzMyFhQGKwEOAVAeMhIMDhcMBhgWIQMMBRcD\
FBgUNy0iNhYQDRYFEA4PGRESHgUbFwEmBgsBBa4KFAYcBgUQEgUQBQMHCwwBLR4gKAcJDQsHmgQa\


Kg0FCQUCAyQUDCYrIAMDFzUJE/60IDAXExIXEgQBAQIGFhAPCw0KDg0UCjUJCgkIQRRpNCAwFxMS\
FxIKGQcMCgcIBQYDBgE2CQoKCT8hdisbEBYNCxgMEhYSCQwNBA4CDRIeDyMtJBgQGBQOCAgUEQ0J\
EwwRAxIfFVoDBAgNBr8FARgfBA0LCBMeLgQDCAIBEQejBgQHAwcLAwQNBggIFAsTNx4qAg2yJiAa\
IhQPDgsCBQQGAwgGBhETJSQ8N1UnDAkIC0tfJiAaIhQPDgsGHAULChQNGg0eBgwQDMXBAAAAAgAF\
//sB/AGaAAkALAAAAQ8BBhUUMzI2NwcOASMiJjU0PwEjNTM/AQc3MhU2MzIWFRQGIiY1NDcGDwEj\
ATZ/OQIUGEQSDCkyHyIiAzdpcxZZJpgZIDUYHRggFgk3EEJIAQkHuAgDFRcPKBkUJBoLC7MgSi54\
Ci0pHBUSGxEOEhMPJ9gAAQAA//0BtQDUAC8AACUyNTQnBiImNT4BMzIWFRQHBiMiLwEmIyIVFBc2\
MzIWFRQGByInJjU0NzYzFh8BFgFwLRoQHBQBFwkkLSkXHiYeohoRLhkQDw0VFA0dGBwoFiIqF6Ic\
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\
eVkyPHpYMR8eBi45OCUyEgG5/m9GaTgnRWocAU7vNVxHTnVJSHJBSe8AAAAAAgAA/3kCCwKoAB8A\
KAAAJTURMx4EFRQHFhUUBzY1NCYjERQGIyImNTQ2MzITHgEXNDY1NCYBIh4JMDg2IxUWIgV2OHlZ\
Mjx6WDE9DoUbAXZr5gFXJEc7QlgzJTIwJC5BGSFfnv7WRmk4J0VqAXY7ojUDDgNfnwAAAQAA/84A\
ZAAyAAcAABYiJjQ2MhYURyodHSodMh0qHR0qAAAAAAAOAK4AAQAAAAAAAACDAQgAAQAAAAAAAQAH\
AZwAAQAAAAAAAgAHAbQAAQAAAAAAAwAjAgQAAQAAAAAABAAHAjgAAQAAAAAABQAJAlQAAQAAAAAA\
BgAHAm4AAwABBAkAAAEGAAAAAwABBAkAAQAOAYwAAwABBAkAAgAOAaQAAwABBAkAAwBGAbwAAwAB\
BAkABAAOAigAAwABBAkABQASAkAAAwABBAkABgAOAl4AQwBvAHAAeQByAGkAZwBoAHQAIABcADIA\
NQAxACAAMgAwADEAOAAtADIAMAAxADkAIABKAGUAYQBuAC0ARgByAGEAbgBjAG8AaQBzACAATQBv\
AGkAbgBlAC4AIABUAGgAaQBzACAAZgBvAG4AdAAgAGkAcwAgAGwAaQBjAGUAbgBzAGUAZAAgAHUA\
bgBkAGUAcgAgAHQAaABlACAAUwBJAEwAIABPAHAAZQBuACAARgBvAG4AdAAgAEwAaQBjAGUAbgBz\
AGUAIABcACgAaAB0AHQAcAA6AC8ALwBzAGMAcgBpAHAAdABzAC4AcwBpAGwALgBvAHIAZwAvAE8A\
RgBMAFwAKQAuAABDb3B5cmlnaHQgXDI1MSAyMDE4LTIwMTkgSmVhbi1GcmFuY29pcyBNb2luZS4g\
VGhpcyBmb250IGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBTSUwgT3BlbiBGb250IExpY2Vuc2UgXCho\
dHRwOi8vc2NyaXB0cy5zaWwub3JnL09GTFwpLgAAYQBiAGMAMgBzAHYAZwAAYWJjMnN2ZwAAUgBl\
AGcAdQBsAGEAcgAAUmVndWxhcgAARgBvAG4AdABGAG8AcgBnAGUAIAAyAC4AMAAgADoAIABhAGIA\
YwAyAHMAdgBnACAAOgAgADEAMgAtADIALQAyADAAMgAyAABGb250Rm9yZ2UgMi4wIDogYWJjMnN2\
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\
AAAAAN2HW+gAAAAA0ZciFwAAAADeLXWv\
") format("truetype")'


|
|
|
|
|
|


|
|
|


|




|
<
<
|
<
|
>
|
<
|
>
|
>
>
>
|
>
|



|
|
<
<
|
|
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
<
<
<
|
|
|
|
|
|
|
|
|
>
|
<
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>
>
|
|
<
<
<
<
<
|
|
|
|
|
|
|
|
|
|
<
|
>
|
|
|
|
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
<
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
|
|
<
<
<
<
|
|
>
|
>
|
>
>
|
>
>
|
<
<
|
|
>
>
>
>
|
<
<
<
>
>
>
>
>
>
>
|
<
<
|
|
|
<
<
<
<
<
|
<
<
>
>
|
|
|
|
>
|
<
<
>
|
|
>
>
>
>
>
>
>
>
|
|
<
<
<
<
<
<
<
<
|
|
|
<
>
|
|
|
|
|
|
<
<
>
>
|
|
>
>
>
>
>
|
>
|
>
>
>
>
|
>
>
|
>
|
|
<
<
<
<
<
|
|
|
<
<
<
<
<
<
<
<
<
|
|
>
|
<
|
<
<
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
>
|
<
<
<
<
|
<
>
|
|
>
>
|
|
|
|
|
|
>
|
|
>
|
|
<
<
|
|
|
|
|
|
|
|
|
|
|
|
|
<
|
|
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<

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,\
AAEAAAAOAIAAAwBgRkZUTZHVOuoAAFgMAAAAHEdERUYAFQAUAABX8AAAABxPUy8yWMFdCgAAAWgA\
AABWY21hcHlUuFMAAAQIAAAD5mN2dCAAIgKIAAAH8AAAAARnYXNw//8AAwAAV+gAAAAIZ2x5ZqUq\
QgUAAAkcAABF/GhlYWQVmDJzAAAA7AAAADZoaGVhCWn/GwAAASQAAAAkaG10eNm9+0EAAAHAAAAC\
SGxvY2HHqraAAAAH9AAAASZtYXhwANkBEgAAAUgAAAAgbmFtZeq7sB0AAE8YAAADFXBvc3SIfxKM\
AABSMAAABbUAAQAAAAEAANGbj/xfDzz1AAsEAAAAAADRlyIXAAAAAOBezej/OPzvBUsEiAAAAAgA\
AgAAAAAAAAABAAAEiPzvAFwEJf84/XQFSwABAAAAAAAAAAAAAAAAAAAAkgABAAAAkgDhAAUAAAAA\
AAIAAAABAAEAAABAAC4AAAAAAAEBgAGQAAUACAKZAswAAACPApkCzAAAAesAMwEJAAACAAUDAAAA\
AAAAAAAAARAAAAAAAAAAAAAAAFBmRWQAQAAA7LcDOP84AFwEiAMRAAAAAQAAAAAAAAF2ACIAAAAA\
AVUAAAGQAAACWAAAAFcAAAAjAAAAJQAAACT//wBkAAAEIwAABCUAAAHg/9wDugAAAwsAAALSAAAC\
v/+6AdYAAAMLAAADDgAAAyf/yADIAAABaAAAAa4AAAEiAAABkAAAAXwAAAGQAAABkAAAAYEAAAGQ\
AAABkAAAAYEAAAGZAAkBmAAJAfQAAAEEABQBBAAKAmsAJAISAAABwgAAAUIAAAFAAAABSv/+ASwA\
AAIwAAABSgAAAUoAAABkAAABQAAAAUAAAAFAAAABQAAAAGQAAAE2AAAA5gAAATYAAAE7AAABOwAA\
ATsAAAE7AAABOwAAATsAAAE7AAABOwAAATsAAAE7AAABDQAAAMgAAAD/AAABCwAUAW4AAACMAAAA\
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\
AAAAZAAAAAAAAwAAAAMAAAAcAAEAAAAAAuAAAwABAAAAHAAEAsQAAABgAEAABQAgAAAAIOAA4DDg\


OeBI4FDgXOBi4GngjOCV4KTgqeCz4QHhu+Hn4gDiSeJk4mvig+Ss5MDk0eTq5QHlMeU55W3lguXQ\

5eLmGOYk5jDmUOZV6RjpIOkl6V3qAuqk7Knst///AAAAAAAg4ADgMOA44EPgUOBc4GLgaeB64JTg\
oOCp4LPhAeG54efh8uJA4mDiauKA5KDkwOTO5OHlAOUg5TnlZuWC5dDl4uYQ5iTmMOZQ5lXpEOkg\
6SXpXeoC6qTsouy3//8AA//kIAUf1gAAAAAfvh+zH64fqAAAAAAAAB+CH3kfLAAAHkkAAAAAAAAA\

AAAAAAAbkwAAAAAAAAAAGzcAABr0GqcalgAAGlkaThovGisAABdnF2MXLBaIFecAABPaAAEAAAAA\
AAAAAABYAFoAAAAAAAAAAABcAIAAggAAAAAAAACEAAAAhgCiALQAvAC+AMQAAADaAOAA8gD0AAAB\
FAAAAAAAAAEcAAAAAAAAAAABJAAAAAAAAAAAAAABKgAAAAAABwAIAAkAAAAKAAsADAANABIAEwAU\
ABUAFgAAABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgAuAAAALwAxAAAA\
MgAAAAAAMwAAADQAAAAAADUAAAA2ADcAOAA5ADoAOwA8AD0APgA/AEAAQQBCAEMARABFAEYARwBI\
AEkASgBLAEwATQBOAAAATwAAAFAAAAAAAAAAUQAAAAAAAABSAFQAAAAAAFUAVgBXAFgAWQBaAFsA\
XABdAF4AXwBgAGEAYgBjAGQAZQBmAGcAAAAAAAAAaABpAGoAawBsAAAAbQBuAG8AcQByAAAAcwAA\
AAAAdAB1AHkAAAB6AAAAewAAAAAAAAB8AIEAggCDAAAAhACFAAAAAACGAIwAjQAAAI4AAACPAAAA\
kAAAAQYAAAMAAAAAAAAAAQIAAAACAAAAAAAAAAAAAAAAAAAAAQAABAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiAogAAAAqACoAKgA2AD4AbgB6\
AIYAkgCwASQBgAHwAjQCwANSA7IDxgRkBPYFTgWOBhAGMgZGBpgG6AcIB04HjgfICBQIVAiaCPQJ\


CAkuCVQJhgmiCcQJ7AoCChwKUgpgCmwKeAqKCqYKyArWCuoK/AsMC1gLaAuCC5wL1AwMDFoMpg0M\
DW4N7A5kDooOpA7UDv4PVg9wD4oPsBAKECoQaBCQEKQQsBC+EM4Q9hEeEVYRYhFuEXoRhhGoEc4S\
BBJSErITJhNME3oTzhRCFJYU1hUaFXAWihdiF/gYqhlsGf4a0BvkHNAdEh1WHaAduh3eHfIeBh42\
HkYeWB50Hooerh7eH7ogdiCeILwg7iEsIV4hoCGyIcAh3CH2IhwiPiJsIoYisCLsIv4AAAACACIA\
AAEyAqoAAwAHAC6xAQAvPLIHBADtMrEGBdw8sgMCAO0yALEDAC88sgUEAO0ysgcGAfw8sgECAO0y\
MxEhESczESMiARDuzMwCqv1WIgJmAAABAAAAAAGRAZAAAwAAMREhEQGRAZD+cAABAAAAAAAAAAAA\
AAAAMQAAAQAAAAAAVwQDACAAABE1NjU0JyY1NDcGFRQXFhUUBxYVFAcGFRQXJjU0NzY1NDUjElc/\
FSVNTSUVP1cSIwIDAhhDNmA5NGY6MksiOWFNYRgYZkxgOSVKMjpmNDlgNkgAAQAAAAAAIwPoAAMA\
ABEzESMjIwPo/BgAAQAAAfQAJQPoAAMAABEzESMlJQPo/gwAAf//A2QAJARgAAMAABEzByMkASQE\
YPwAAgAAAUAAZAKeAAcADwAAEiImNDYyFhQCIiY0NjIWFEcqHR0qHR0qHR0qHQI6HSodHSr+6R0q\
HR0qAAAABQAAAAAEJAGuAC8ANwA/AEcAUwAAITUzHgEzMjY1NCcuBDU0NjMyFhc3MxcjLgEjIgYV\
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\
VVc9ARVWTUQJHVVXPQEVVk1E/o4CrClId0QhGTk2KykrLC0nKywtJyssJUg9OjczORuqKUl4RAMN\
BCldQ1SGKUl4RAMNBCldQ1SGKUl4RAMNBCldQ1QAAAAFAAD9VQE8AhIAJAAyAEAATgBcAAAZATMe\
BhUUBxYVFAcWFRQHFhUUBxYVFAc2NTQuAyM1HgMXNDY1NC4DJx4DFzQ2NTQuAyceAxc0NjU0LgMn\
HgMXNDY1NC4DHgYnMzs4LhwSEhISEhISEx4FKT5IQBYJRE1WFQEpPkhBFglETVYVASk+SEEWCURN\
VhUBKT5IQRYJRE1WFQEpPkhB/rsDVxs5Mzc6PUglLCsnLSwrJy0sKyctLCspKzY5GSE3ZEU0GKsk\
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\

NB8mOHg0JSIih2QBh+XZzy4kHTU0S00jLRW8tAAAAQAA/w0BAADAABYAADcOAiMiJjU0NjIWFRQH\
MjY3NjIXAyerAxkaEys3JjgpFyIzIQIVA5YwPAEHBCkoHyAeGR0bISwCAv5vEAAAAAEAAP4MAUgA\




wAAkAAAXBiMiJjU0NjMyFhUUBzI/AQYjIiY1NDYzMhYVFAcyNzYyFwMnqyghKzcnGxwpF0ELPDYY\
KzcnGxwpF0guAhUDxS3EDCgoICAfGR0bIsoMKSgfIB4ZHRtNAgL9bgwAAAEAAP4MAY8BwAA2AAA3\
BiMiJjU0NjMyFhUUBzI/ASIOASMiJjU0NjMyFhUUBzI3NjIXAScTBiMiJjU0NjMyFhUUBzI39igf\
KzcnGxwpFz8LOgEgHBMrNycbHCkXSC4BFgP+9C1VKCErNycbHCkXQQs8DCgoICAfGR0bIssJBCko\
HyAeGR0bTQIC/G4MASQMKCggIB8ZHRsiAAAAAAEAAP0MAdoBwABFAAATBiMiJjU0NjMyFhUUBzI/\
AQYjIiY1NDYzMhYVFAcyPwEGIyImNTQ2MzIWFRQHMj8BIg4BIyImNTQ2MhYVFAcyNzYyFwEnqygh\
KzcnGxwpF0ELOighKzcnGxwpF0ELOigfKzcnGxwpFz8LOgEgHBMrNyY4KRdILgIVA/6pLf48DCgo\
ICAfGR0bIsoMKCggIB8ZHRsiygwoKCAgHxkdGyLLCQQpKB8gHhkdG00CAvtuDAAAAAEAAP0MAhkC\
rgBWAAAlBiMiJjU0NjMyFhUUBzI/AQYjIiY1NDYzMhYVFAcyPwEiDgEjIiY1NDYzMhYVFAcyNzYy\
FwEnEwYjIiY1NDYzMhYVFAcyPwEGIyImNTQ2MzIWFRQHMjcBPyghKzcnGxwpF0ELNigfKzcnGxwp\
Fz8LNAEgHBMrNycbHCkXSC4BFgP+ai1VKCErNycbHCkXQQs6KCErNycbHCkXQQs0DCgoICAfGR0b\
IsQMKCggIB8ZHRsixwkEKSgfIB4ZHRtNAgL6gAwBJAwoKCAgHxkdGyLIDCgoICAfGR0bIgAD//D/\


BgImAPoABwAPABMAADYiJjQ2MhYUACImNDYyFhQFATMBUDIjIzIjAYgyIyMyI/3SAbh+/kdLIzIj\
IzL+zyMyIyMyWgH0/gwABP/h/wYDBwD6AAcADwATABcAADYiJjQ2MhYUACImNDYyFhQFATMBMwEz\
AUEyIyMyIwJ3MiMjMiP84wG4e/5HeQG4e/5HSyMyIyMy/s8jMiMjMloB9P4MAfT+DAAC/7T/iAF8\
ARgAEQA7AAA3FjMyNjc2NTQnJiMiBgcGFRQXIicHMzIUKwEiNDsBEzY1NCMiDgMHBiY3Njc2MzIW\
Fz4BMzIWFRQGxQIFEjIODQ8CBBI1Cw8nKhktNAsL4QsLS2gGCwgMDwsZCgUbBTEPFyUjJAcdJiMe\
LVkoATUkICYlBQEzHCckKS4geh4eAR0SDA8HFBIsEAgPCVgQGRMaHg80MElrAAAB/9v/9gG+ARgA\
UwAANwYHBisBIj8BNiYjIgYHBiY3PgMzMhc2MzIXPgEzMhYVFA8BBhUUMzI3PgU3NhYHDgIjIiY1\



ND8BNjU0IyIPAQYHJwYmPwE2NTQjIgdQBwgEBDUNDUIEBggNFiQFFQQUECIfEjcLJCQtCQspExkk\
BS8ECAEEBQsHDAMNAQYVBhIXLR8VGQU0ARUbCEEIDyYNCARDARUbCBURAwEapw0PGjkIDAklGjAS\
KCgoEBgjGgsPfQsJDgIDCQYPBRIBCQ0LHx8aFhMNDYgCBA4UqxYBAQEPCKsCBA4UAAAAAf9+/2AB\
XgG4AEEAAAciJjU0NjMyFhUUBwYVFDMyPgc3IyI1NDsBPgEzMhYVFAYjIiY1NDc2NCMiDgcHMzIU\
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\
AwGbFGk0IDAXExIXEgoZBwwKBwgFBgMGATYUFD8hdl8gMBcTEhcSChkLEA8LDQoPDRTmxcEmIBoi\
FA8OCwcNDgYREyUkPDdVJxUTS18mIBoiFA8OCwYccwwGAUtfJiAaIhQPDgsGHAULChQNGg0eBijF\
wSYgGiIUDw4LBw0OBhETJSQ8N1UAAAAB/37/YAN0AbgAqgAAEzM+ATMyFhUUBiMiJjU0NzY0IyIH\
BgcXPgEzMhYVFAYjIiY1NDc2NCMiDgcHMzIUKwEOASMiJjU0NjMyFhUUBwYVFDMyPgc3Iw4BIyIm\
NTQ2MzIWFRQHBhUUMzI+BzcjDgEjIiY1NDYzMhYVFAcGFRQzMj4HNyMiNTQ7AT4BMzIWFRQGIyIm\
NTQ3NjQjIg4CBwbMnBRpNCAwFxMSFxIKGSYXAwGbFGk0IDAXExIXEgoZBwwKBwgFBgMGATYTEz8h\
dl8gMBcTEhcSChkLEA8LDQoPDRQKmyF2XyAwFxMSFxIKGQsQDwsNCg4NFQqbIXZfIDAXExIXEgoZ\
CxAPCw0KDg0UCjUTEUEUaTQgMBcTEhcSChkOFQ4IBgIBDktfJiAaIhQPDgsGHHMMBgFLXyYgGiIU\
Dw4LBhwFCwoUDRoNHgYoxcEmIBoiFA8OCwcNDgYREyUkPDdVJ8XBJiAaIhQPDgsHDQ4GERMlJDs4\
VSfFwSYgGiIUDw4LBw0OBhETJSQ8N1UnFRNLXyYgGiIUDw4LBhwTJyIbCgAB/37/YASAAbgA4AAA\
ARc+ATMyFhUUBiMiJjU0NzY0IyIHBgcXPgEzMhYVFAYjIiY1NDc2NCMiDgcHMzIUKwEOASMiJjU0\
NjMyFhUUBwYVFDMyPgc3Iw4BIyImNTQ2MzIWFRQHBhUUMzI+BzcjDgEjIiY1NDYzMhYVFAcGFRQz\
Mj4HNyMOASMiJjU0NjMyFhUUBwYVFDMyPgc3IyI1NDsBPgEzMhYVFAYjIiY1NDc2NCMiBwYHFz4B\
MzIWFRQGIyImNTQ3NjQjIg4HAdicFGk0IDAXExIXEgoZJhcDAZsUaTQgMBcTEhcSChkHDAoHCAUG\





AwYBNhMTPyF2XyAwFxMSFxIKGQsQDwsNCg8NFAqbIXZfIDAXExIXEgoZCxAPCw0KDg0UCpshdl8g\
MBcTEhcSChkLEA8LDQoPDRQKmyF2XyAwFxMSFxIKGQsQDwsNCg4NFAo1ExFBFGk0IDAXExIXEgoZ\
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\
Abn+b0ZpOCdFahwBTu81XEdOdUlIckFJ7wAAAAACAAD/eQILAqgAHwAoAAAlNREzHgQVFAcWFRQH\
NjU0JiMRFAYjIiY1NDYzMhMeARc0NjU0JgEiHgkwODYjFRYiBXY4eVkyPHpYMT0OhRsBdmvmAVck\
RztCWDMlMjAkLkEZIV+e/tZGaTgnRWoBdjuiNQMOA1+fAAABAAD/zgBkADIABwAAFiImNDYyFhRH\


Kh0dKh0yHSodHSoAAAAAAA4ArgABAAAAAAAAAIMBCAABAAAAAAABAAcBnAABAAAAAAACAAcBtAAB\
AAAAAAADAB8B/AABAAAAAAAEAAcCLAABAAAAAAAFAAgCRgABAAAAAAAGAAcCXwADAAEECQAAAQYA\
AAADAAEECQABAA4BjAADAAEECQACAA4BpAADAAEECQADAD4BvAADAAEECQAEAA4CHAADAAEECQAF\
ABACNAADAAEECQAGAA4CTwBDAG8AcAB5AHIAaQBnAGgAdAAgAFwAMgA1ADEAIAAyADAAMQA4AC0A\
MgAwADEAOQAgAEoAZQBhAG4ALQBGAHIAYQBuAGMAbwBpAHMAIABNAG8AaQBuAGUALgAgAFQAaABp\
AHMAIABmAG8AbgB0ACAAaQBzACAAbABpAGMAZQBuAHMAZQBkACAAdQBuAGQAZQByACAAdABoAGUA\
IABTAEkATAAgAE8AcABlAG4AIABGAG8AbgB0ACAATABpAGMAZQBuAHMAZQAgAFwAKABoAHQAdABw\
ADoALwAvAHMAYwByAGkAcAB0AHMALgBzAGkAbAAuAG8AcgBnAC8ATwBGAEwAXAApAC4AAENvcHly\
aWdodCBcMjUxIDIwMTgtMjAxOSBKZWFuLUZyYW5jb2lzIE1vaW5lLiBUaGlzIGZvbnQgaXMgbGlj\
ZW5zZWQgdW5kZXIgdGhlIFNJTCBPcGVuIEZvbnQgTGljZW5zZSBcKGh0dHA6Ly9zY3JpcHRzLnNp\
bC5vcmcvT0ZMXCkuAABhAGIAYwAyAHMAdgBnAABhYmMyc3ZnAABSAGUAZwB1AGwAYQByAABSZWd1\
bGFyAABGAG8AbgB0AEYAbwByAGcAZQAgADoAIABhAGIAYwAyAHMAdgBnACAAOgAgADEANAAtADQA\
LQAyADAAMgAzAABGb250Rm9yZ2UgOiBhYmMyc3ZnIDogMTQtNC0yMDIzAABhAGIAYwAyAHMAdgBn\

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=\

") 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
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\\).
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]

OS2Version: 0
OS2_WeightWidthSlopeOnly: 0
OS2_UseTypoMetrics: 0
CreationTime: 1433498007
ModificationTime: 1654926804
PfmFamily: 17
TTFWeight: 400
TTFWidth: 5
LineGap: 92
VLineGap: 92
Panose: 2 0 5 3 0 0 0 0 0 0
OS2TypoAscent: 0





|











>




|







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







<





|







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

UnicodeInterp: none
NameList: Adobe Glyph List
DisplaySize: -96
AntiAlias: 1
FitToEm: 1
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
 361 129 450 70 450 0 c 4
EndSplineSet
Validated: 1
EndChar

StartChar: uniE0A3
Encoding: 38 57507 38
Width: 329
Flags: MW
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
 164 -91 297 -10 297 49 c 4
 297 56 295 62 292 68 c 4
313 81 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
 245 148 288 128 313 81 c 4
EndSplineSet
Validated: 1
EndChar

StartChar: uniE0A4
Encoding: 39 57508 39
Width: 320







|
|



|
|
|
|
|
<
<
|
<
|
|
|
|
<







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: 322
Flags: HMW
LayerCount: 2
Fore
SplineSet
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


194 138 m 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

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
// 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!




abc2svg.MIDI = {

    // parse %%MIDI commands
    do_midi: function(parm) {

    // build the equal temperament as a b40 float array
    function tb40(qs) {







>
>
>







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

    // set the MIDI parameters in the current voice
    set_vp: function(of, a) {
    var	i, item, s,
	abc = this,
	curvoice = abc.get_curvoice()




	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







>
>
>







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
		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);

// the module is loaded
abc2svg.modules.MIDI.loaded = true







<















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

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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

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
// ambitus.js - module to insert an ambitus at start of a voice
//
// Copyright (C) 2018-2021 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




abc2svg.ambitus = {
    do_ambitus: function() {
    var	C = abc2svg.C,
	s, v, p_v, min, max,
	voice_tb = this.get_voice_tb()



|




















>
>
>







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-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
    set_fmt: function(of, cmd, param) {
	if (cmd == "ambitus") {
		this.cfmt().ambitus = param
		return
	}
	of(cmd, param)
    },






















    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_width = abc2svg.ambitus.set_width.bind(abc, abc.set_width)
    }
} // ambitus

abc2svg.modules.hooks.push(abc2svg.ambitus.set_hooks);

// the module is loaded
abc2svg.modules.ambitus.loaded = true







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>














>




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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

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
// break.js - module to handle the %%break command
//
// Copyright (C) 2018-2021 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 ...]*




abc2svg.break = {

	// get the %%break parameters
	get_break: function(parm) {
	    var	C = abc2svg.C,
		b, c, d, sq,


|




















>
>
>







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

    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);

// the module is loaded
abc2svg.modules.break.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

abc2svg.mhooks.break = abc2svg.break.set_hooks
Changes to modules/capo.js.
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
//
// 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.


|







1
2
3
4
5
6
7
8
9
10
// capo.js - module to add a capo chord line
//
// 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
// 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




abc2svg.capo = {




    gch_build: function(of, s) {
    var	t, i, gch, gch2, i2,
	abc = this,
	p_v = abc.get_curvoice(),
	a_gch = s.a_gch








>
>
>

>
>
>







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
				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])
		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")







|







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.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
    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);

// the module is loaded
abc2svg.modules.capo.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

abc2svg.mhooks.capo = abc2svg.capo.set_hooks
Changes to modules/chordnames.js.
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
//
// 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.


|







1
2
3
4
5
6
7
8
9
10
// abc2svg - chordnames.js - change the names of the chord symbols
//
// 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
//	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




abc2svg.chordnames = {

    gch_build: function(of, s) {
    var	gch, ix, t,
	cfmt = this.cfmt()








>
>
>







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


    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








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

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
// clair.js - module to output Clairnote sheets (https:clairnote.org)
//
// Copyright (C) 2019-2021 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




abc2svg.clair = {

// table for helper lines (from C, to c'')
// index = (note pitch + 16)
// value = array of line numbers / null
    hl_tb: [


|




















>
>
>







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-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
	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);

// the module is loaded
abc2svg.modules.clairnote.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

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
// clip.js - module to handle the %%clip command
//
// Copyright (C) 2018-2021 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]




abc2svg.clip = {

    get_clip: function(parm) {
    var	C = abc2svg.C

	// get the start/stop points


|




















>
>
>







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

    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);

// the module is loaded
abc2svg.modules.clip.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

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
// combine.js - module to add a combine chord line
//
// Copyright (C) 2018-2022 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




abc2svg.combine = {

    // function called at start of the generation when multi-voices
    comb_v: function() {
    var	C = abc2svg.C,
	abc = this


|




















>
>
>







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



		return true
	}
	if (s2.a_ly)
		return false
	if (s2.beam_st != s.beam_st
	 || s2.beam_end != s.beam_end)
		return false;







|
>
|
>
>
>







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) {
			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
				s2 = s;
				s = s2.ts_next
			}
		} else if (s.type == C.REST) {
			if (s.invis
			 && !s2.invis)
				delete s.invis

		} else {
			combine_notes(s, s2)
			if (s2.ti1)
				s.ti1 = true
			if (s2.ti2)
				s.ti2 = true
		}







>







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
	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);

// the module is loaded
abc2svg.modules.voicecombine.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

abc2svg.mhooks.combine = abc2svg.combine.set_hooks
Changes to modules/diag.js.
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
//
// 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.


|







1
2
3
4
5
6
7
8
9
10
// diag.js - module to insert guitar chord diagrams
//
// 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
//	<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)




abc2svg.diag = {

    cd4: {},
// common diagrams by Guido Gonzato from http://www.guitar-chord.org/ (2021-08-27)
    cd6: {
	C: "x32010 ,0 x32010",







>
>
>







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



// n = number of strings
    do_diag: function(n) {
    var	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\
m0 6h12m0 6h-12\
m0 6h12"/>\n\
<path class="stroke" stroke-width="0.5" d="\
M-6 -34v24m4 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"/>'
		} else {
			glyphs.fb6 = '<g id="fb6">\n\
<path class="stroke" stroke-width="0.4" d="\
M-10 -34h20m0 6h-20\
m0 6h20m0 6h-20\
m0 6h20"/>\n\
<path class="stroke" stroke-width="0.5" d="\
M-10 -34v24m4 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"/>'
		}
	}

	// 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('/', '.')


	} // ch_cnv()

	// add a decoration and display the diagram
	function diag_add(nm) {			// chord name
	    var	dc, i, l, x,
		d = abc2svg.diag["cd" + n][nm]	// 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)
				+ '" 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">'
				+ 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)
					+ '" 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) + '"/>'
		}
		dc += '</g>'
		glyphs[nm] = dc
	} // diag_add()

    var	s, i, gch, nm


	for (s = voice_tb[0].sym; s; s = s.next) {
		if (!s.a_gch)

			continue
		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)
			this.deco_put(n + nm, s) // insert diag as decoration
		}






	}
    }, // do_diag()

    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":







>
>
>
|
<
|
<
<













|



|




|



|



|





|












>
>


|

|
|
>



<









|

<



|







|








|





|
>

<
|
>
|
<
|
|
|
|
|
>
>
|
<
|
>
>
>
>
>
>

|
<
<
<
<
<
<
<







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 = cfmt.diag,				// number of strings

	glyphs = this.get_glyphs()



	// 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 -24h12m0 6h-12\
m0 6h12m0 6h-12\
m0 6h12"/>\n\
<path class="stroke" stroke-width="0.5" d="\
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 -24.5h12.4"/>'
		} else {
			glyphs.fb6 = '<g id="fb6">\n\
<path class="stroke" stroke-width="0.4" d="\
M-10 -24h20m0 6h-20\
m0 6h20m0 6h-20\
m0 6h20"/>\n\
<path class="stroke" stroke-width="0.5" d="\
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 -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()

	// create a glyph of the diagram
	function diag_add(nm) {			// chord name
	    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

		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 - 25)
				+ '" class="frn">' + l[0] + '</text>\n'

		// fingers
		dc += '<text x="' + (n == 6 ? '-12,-8,-4,0,4,8'
					: '-8,-4,0,4')
				+ '" 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 - 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)
					+ ' -21h' + ((l[1] - l[2]) * 4 + 4) + '"/>'
		}
		dc += '</g>'
		glyphs[nm] = dc
	} // diag_add()

	// --- draw_gchord ---
	of(i, s, x, y)		// draw the chord symbols and the annotations


	if ((s.invis && s.play)	// play sequence: no chord nor annotation
	 || !n)			// no %%diagram
		return

	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)


	// 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)
	}
    }, // draw_gchord()








    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
		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.set_format = abc2svg.diag.set_fmt.bind(abc, abc.set_format)
    }
} // diag

abc2svg.modules.hooks.push(abc2svg.diag.set_hooks);

// the module is loaded
abc2svg.modules.diagram.loaded = true







|




|
|
<
|
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.draw_gchord = abc2svg.diag.draw_gchord.bind(abc,abc.draw_gchord)
	abc.set_format = abc2svg.diag.set_fmt.bind(abc, abc.set_format)
    }
} // diag

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

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
// equalbars.js - module to set equal spaced measure bars
//
// Copyright (C) 2018-2022 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




abc2svg.equalbars = {

    // new tune - clear the width of the start of the staff
    output_music: function(of) {
	this.equalbars_d = 0;
	of()


|




















>
>
>







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-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
	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,
	bars = [],
	tsfirst = this.get_tsfirst();

	of(width)			// compute the x offset of the symbols
	if (!this.cfmt().equalbars)
		return








|







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, 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
	}
	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) {
			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))
		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;







|





|
|







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 && s.time != t) {
			bars.push([s, s.time - t]);
			t = s.time
		}
	}

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

			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) {

				s2.x = d + (s2.x - x) * f
			}
		}
		d += w * bars[i][1];
		x = s2.x
		while (1) {
			s2.x = d;







|








|
>
>
>
>
|
>











|
>







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 - 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 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 {
				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
    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);

// the module is loaded
abc2svg.modules.equalbars.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

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




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]),








>
>
>







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

// the module is loaded
abc2svg.modules.gamelan.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

abc2svg.mhooks.gamelan = abc2svg.gamelan.set_hooks
Changes to modules/grid.js.
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
//
// 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.


|







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




abc2svg.grid = {
    pl: '<path class="stroke" stroke-width="1" d="M',

// generate the grid
    block_gen: function(of, s) {
	if (s.subtype != "grid") {







>
>
>







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
	}
	abc.vskip(hr * (nr + 1) + 6)
} // build_grid()

	// ----- block_gen() -----
    var	p_voice, n, font, f2


	img = abc.get_img()

	// set the text style
	font = abc.get_font('grid')
	if (font.class)
		font.class += ' mid'
	else







>







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
				cur_beat += beat
			}
			if (s.part)
				parts[chords.length] = s.part.text
			switch (s.type) {
			case C.NOTE:
			case C.REST:

				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)

						break
					s = s.ts_next
					if (s.type == C.METER) {
						beat = get_beat(s)
						wm = s.wmeasure
						continue
					}







>

















|
>







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
					 || 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
    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);

// the module is loaded
abc2svg.modules.grid.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

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
//
// This module is loaded when "%%grid2" appears in a ABC source.
//
// Parameters
//	%%grid2 y
// This command may appear globally or in a voice.




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()








>
>
>







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
    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);

// the module is loaded
abc2svg.modules.grid2.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

abc2svg.mhooks.grid2 = abc2svg.grid2.set_hooks
Changes to modules/grid3.js.
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
//
// 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.


|







1
2
3
4
5
6
7
8
9
10
// grid3.js - module to insert a manual chords
//
// 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
//	%%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.




abc2svg.grid3 = {

// generate the grid
    block_gen: function(of, s) {
	if (s.subtype != "grid3") {
		of(s)
		return
	}


	this.blk_flush()

    var	abc = this,
	cfmt = abc.cfmt(),
	img = abc.get_img(),
	posy = abc.get_posy(),
	txt = s.text,







>
>
>









>







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

// the module is loaded
abc2svg.modules.begingrid.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

abc2svg.mhooks.grid3 = abc2svg.grid3.set_hooks
Changes to modules/jazzchord.js.
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
//
// 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.


|







1
2
3
4
5
6
7
8
9
10
// abc2svg - jazzchord.js - Adds jazz chord styling to chord symbols
//
// 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
// Code adapted from Chris Fargen.
//	https://gist.github.com/chrisfargen/4324c6cf6fed2c8f9a6eae1680e53169
//
// This module is loaded by %%jazzchord.
//
// Parameters
//	%%jazzchord [ string '=' replacement-string ]*




abc2svg.jazzchord = {

    // default replacements
    defrep: {
	"-": "–",
	"°": "o",







>
>
>







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
		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])
			r += (a[2] ? "$0" : '') + "$8" + a[3]
		if (a[4])
			r += ((a[2] || a[3]) ? "$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]







>
>
>
>
>
>
>
>
>
>
>
>

|

|







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 += (r ? "$0" : '') + "$8" + a[3]
		if (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

    }, // 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.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








|









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

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
// jianpu.js - module to output jiănpŭ (简谱) music sheets
//
// 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.
//
// 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




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]),


|




















>
>
>







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-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
						break
					s1 = s1.prev
				}
				//add deco '{' on s1
				while (!s1.bar_type) {
					s1.dy = 14
					s1.notes[0].pit = 30


					s1 = s1.next
				}
				// add deco '}' on s1

				while (1) {
					s.dy = -14
					s.notes[0].pit = 20







>
>







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

		if (s.dur >= C.BLEN)
			n = 3 
		else if (s.dur == C.BLEN / 2)
			n = 1
		else
			n = 2

















		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,







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|







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

	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)
				ov_def(v)
		}
	}

	of()
  }, // output_music()

  draw_symbols: function(of, p_voice) {
    var	s, s2, nl, y,
	C = abc2svg.C,
	abc = this,
	dot = "\ue1e7",

	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)







|












>







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

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

	} // draw_note()

	// -- draw_symbols --
	for (s = p_voice.sym; s; s = s.next) {
		if (s.invis)
			continue
		switch (s.type) {







>







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

// the module is loaded
abc2svg.modules.jianpu.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

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
      return to;
    },
    writable: true,
    configurable: true
  });
}




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"],








>
>
>







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

	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)

// the module is loaded
abc2svg.modules.mdnn.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

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
// abc2svg - nns.js - module to output chords in the NNS
//			(Nashville Notation System)
//
// Copyright (C) 2021 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]
//		<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


//	%%nnsfont font_name size (default: 'monospace 16')




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"],





// inversions: 1st: (upper)6, 2nd: (upper)6 (lower) 4 

// generate the grid
    block_gen: function(of, s) {
	if (s.subtype != "nns") {
		of(s)
		return



|



















|





|
>
>

>
>
>







<
<



|
|
>
>
>
>
>







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-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= 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' 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"],


	// Roman
    rnn_nm: ["I", "♯I", "II", "♭III", "III", "IV", "♯IV",
		"V", "♯V", "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

	abc.vskip(hr * nr + 6)
} // build_nns()

	// ----- block_gen() -----
    var	p_voice, n, font, f2


	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,
	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) {
	    var	i, o, o2, a, n,
		csa = []

		i = p.indexOf('/')		// get the bass if any
		if (i > 0) {
			while (1) {
				if (p[i -1] != '<')







>















|

















|







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,
	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, 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
				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
			   else
				n = abc2svg.nns.nns_nm_m[n]	// minor
			} else {
			   if (!mode)
				n = abc2svg.nns.rnn_nm[n]
			   else
				n = abc2svg.nns.rnn_nm_m[n]







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

		// 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.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)
						}
						break
					}
				}
				break
			case C.BAR:
				bt = s.bar_type







<
<

<
|
<
<
|




>
>
>
>
>
>
>



















|
|












>
>
>
>











|







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 (!nns.roman) {

				n = abc2svg.nns.nns_nm[n]	// major and minor


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

	// -------- 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,







<







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()

		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
			nns.n = 1
		}
		while (parm.length) {
			var item = parm.shift()
			if (item == "nomusic")
				nns.nomusic = true
			else if (item == "roman")
				nns.roman = true
			else if (item == "repbrk")
				nns.repbrk = true
			else if (item.slice(0, 8) == "include=")
				nns.ls = item.slice(8).split(',')


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

// the module is loaded
abc2svg.modules.nns.loaded = true







|




>
>














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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

abc2svg.mhooks.nns = abc2svg.nns.set_hooks
Changes to modules/page.js.
1
2
3
4
5
6
7
8
9
10
// page.js - module to generate pages
//
// Copyright (C) 2018-2022 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.


|







1
2
3
4
5
6
7
8
9
10
// page.js - module to generate pages
//
// 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
// 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>




abc2svg.page = {

    // function called at end of generation
    abc_end: function(of) {

    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()


















    // 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),
	cfmt = page.abc.cfmt(),
	fh = font.size * 1.1,
	pos = [ '">',
		'" text-anchor="middle">',
		'" text-anchor="end">' ]

	// replace <>& by XML character references







>
>
>




>







>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




|







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.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
				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 = page.abc.parse.fname
				break
			case 'I':
				c = str[++i]
				s += c
				// fall thru
			case 'T':
				t = page.abc.info()[c]







>
>
|







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
					: 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
	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")


		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.user_out(
			'<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.hf + '</g>\n</svg>')
		page.hmax -= h;
		page.hf = ''
	} else {
		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\
	width="' + cfmt.pagewidth.toFixed(0) +
			'px" height="' + ht.toFixed(0) +
			'px">\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







>
>







>
|
<
<
<
<
<

|




|
<
<
<
<
|







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(sty +





			'<g transform="translate(0,' +
				page.topmargin.toFixed(1) + ')">\n' +
				page.hf + '</g>\n</svg>')
		page.hmax -= h;
		page.hf = ''
	} else {
		abc2svg.page.svg_tag(cfmt.pagewidth, ht, "header")




		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
    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(
			'<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 +
			'<g transform="translate(0,' +
				(h - page.fh).toFixed(1) + ')">' +
			page.hf + '</g>\n</svg>')
	}
	abc2svg.page.user_out('</div>')
	page.h = 0
    }, // close_page()

    // handle the output flow of the abc2svg generator







|
<
<
<
<
|

|







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.svg_tag(cfmt.pagewidth, h, "footer")




		abc2svg.page.user_out(page.ffsty +
			'<g transform="translate(0,' +
				(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
		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)





			return


		// if first definition, install the hook
		if (!page || !abc2svg.page.user_out) {
			this.page = page = {
				abc: this,
				topmargin: 38,	// 1cm
				botmargin: 38,	// 1cm







|
>
>
>
>
>

>







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 (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
				page.header = cfmt.header;
				cfmt.header = null
			}
			if (cfmt.footer) {
				page.footer = cfmt.footer;
				cfmt.footer = null
			}




			if (cfmt.header2) {
				page.header2 = cfmt.header2
				cfmt.header2 = null
			}
			if (cfmt.footer2) {
				page.footer2 = cfmt.footer2
				cfmt.footer2 = null







>
>
>
>







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
		}
		return
	}
	if (page) {
		switch (cmd) {
		case "header":
		case "footer":

		case "header2":
		case "footer2":
			page[cmd] = parm
			return
		case "newpage":
			if (!parm)
				break







>







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
    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);

// the module is loaded
abc2svg.modules.pageheight.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

abc2svg.mhooks.page = abc2svg.page.set_hooks
Changes to modules/pedline.js.
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
//
// 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.


|







1
2
3
4
5
6
7
8
9
10
// pedline.js - module to draw pedal lines instead of 'Ped .. *'
//
// 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
// 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




abc2svg.pedline = {
    draw_all_deco: function(of) {
    var	de, i,
	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

			if (de.prev
			 && de.prev.dd.name == "ped)") {
// ( .. ) ( .. )
//		\ de

//	\ de.prev
// \ de.prev.start
// |_____/\____|


				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




			} else {
				de.x -= 3

				de.val += 10
			}
		}
	}
	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)
	if (defl.nost) {

		this.out_svg("l2.5 6")
		val -= 2.5



	} else {
		this.out_svg("v6")
	}
	if (defl.noen) {

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




    }, // 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)

// the module is loaded
abc2svg.modules.pedline.loaded = true







>
>
>


|









>
|
<


>



>
>
|
|
|
|
|
>
>
>
>

|
>
|











|

>
|
|
>
>
>




>
|
|
|
|
|
>
>
>
>
















|
|
<
|
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, 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
			dp = de.prev

// ( .. ) ( .. )
//		\ de
//	  \ de.start
//	\ de.prev
// \ de.prev.start
// |_____/\____|
			if (dp && dp.dd.name == "ped)"
			 && dp.s.v == ds.s.v) {
				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 = 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 + 8)
	if (defl.nost) {
		if (defl.nost == 2) {		// \
			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')
		} 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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

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
//	%%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".




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])








>
>
>







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

    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);

// the module is loaded
abc2svg.modules.percmap.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

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
// psvg.js - small PS to SVG convertor for abc2svg

// Copyright (C) 2014-2021 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/>.




function Psvg(abcobj_r) {
    var	svgbuf = '',

// SVG functions - adapted from abcm2ps svg.c
	abcobj = abcobj_r,
	wps = new Wps(this),


|















>
>
>







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-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
	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) {
	var	dd, de2, script, defl,

		Os = wps.parse('/' + f + ' where'),
		A = Os.pop(),
	staff_tb = abcobj.get_staff_tb()

	if (!A)
		return false;
	defl = 0







|

>







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(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
		}
		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) {
		if (!this.psvg)			// no %%beginps yet
			return false
		return this.psvg.psdeco.call(this.psvg, f, 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);

// the module is loaded
abc2svg.modules.beginps.loaded = true







|


|














|
|
<
|
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, x, y, de) {
		if (!this.psvg)			// no %%beginps yet
			return false
		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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

abc2svg.mhooks.psvg = abc2svg.psvg.set_hooks
Changes to modules/roman.js.
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
//
// 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.



|







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




abc2svg.roman = {
    note_nm: "CDEFGAB",

    // chord names
    nm_M: ["I", "♯I", "II", "♭III", "III", "IV", "♯IV",
		"V", "♯V", "VI", "♭VII", "VII"],







>
>
>







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

    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








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

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
// soloffs.js - module to set the X offset of some elements at start of music line
//
// Copyright (C) 2018-2021 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




abc2svg.soloffs = {

    set_fmt: function(of, cmd, parm) {
	if (cmd == "soloffs") {
	    var	i, v,
		C = abc2svg.C,


|




















>
>
>







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

    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);

// the module is loaded
abc2svg.modules.soloffs.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

abc2svg.mhooks.soloffs = abc2svg.soloffs.set_hooks
Changes to modules/sth.js.
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
//
// 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.


|







1
2
3
4
5
6
7
8
9
10
// sth.js - module to set the stem heights
//
// 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
// 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.




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,







>
>
>







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
	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);

// the module is loaded
abc2svg.modules.sth.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

abc2svg.mhooks.sth = abc2svg.sth.set_hooks
Changes to modules/strtab.js.
1
2
3
4
5
6
7
8
9
10
// abc2svg - strtab.js - tablature for string instruments
//
// Copyright (C) 2020-2022 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.


|







1
2
3
4
5
6
7
8
9
10
// abc2svg - strtab.js - tablature for string instruments
//
// 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
// 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




abc2svg.strtab = {

    // draw the tablature
    draw_symbols: function(of, p_v) {
    var	s, m, not, stb, x, y, g,
	C = abc2svg.C,







>
>
>







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
		case C.NOTE:
			draw_heads(stb, s)
			break
		}
	}
	abc.out_svg('</g>\n')
    }, // draw_symbols()

























    // set a format parameter
    set_fmt: function(of, cmd, parm) {




	if (cmd == "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") {
		this.set_v_param("minfret", parm)
		return
	}
	of(cmd, parm)
    }, // set_fmt()

    // change the notes when the global generation settings are done








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
>
>
>
|














<
|







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

	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
		switch (s.type) {
		case C.KEY:
		case C.REST:
		case C.TIME:
			s.invis = true
		default:
			delete s.a_dd
			continue
		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)







|







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

//		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.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








>



















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

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
// temper.js - module to define the temperament
//
// Copyright (C) 2018-2021 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.


|







1
2
3
4
5
6
7
8
9
10
// temper.js - module to define the temperament
//
// 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
// %%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




abc2svg.temper = {

    // get the temperament
    set_fmt: function(of, cmd, param) {
	if (cmd == "temperament") {
	    var	i, tb,







>
>
>







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

    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);

// the module is loaded
abc2svg.modules.temperament.loaded = true







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

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}
abc2svg.mhooks.temper = abc2svg.temper.set_hooks


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
// tropt.js - module to optimize the notes after transposition
//
// Copyright (C) 2022 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.




abc2svg.tropt = {

    // function called before start of the generation
    set_pitch: 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(),


|


















>
>
>



|







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







|







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.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
					nt.pit = np
					nt.acc = na
				}
			}
		}
	}
	of(last_s)
    }, // set_pitch()

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







|







116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
					nt.pit = np
					nt.acc = na
				}
			}
		}
	}
	of(last_s)
    }, // 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
		}
	}
	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.set_vp = abc2svg.tropt.set_vp.bind(abc, abc.set_vp)
    }
} // tropt

abc2svg.modules.hooks.push(abc2svg.tropt.set_hooks)

// the module is loaded
abc2svg.modules.tropt.loaded = 1 //true







|




|
|
<
|
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.voice_adj = abc2svg.tropt.voice_adj.bind(abc, abc.voice_adj)
	abc.set_vp = abc2svg.tropt.set_vp.bind(abc, abc.set_vp)
    }
} // tropt

if (!abc2svg.mhooks)
	abc2svg.mhooks = {}

abc2svg.mhooks.tropt = abc2svg.tropt.set_hooks
Changes to toabc.js.
1
2
3
4
5
6
7
8
9
10
// abc2svg - toabc.js - convert ABC to ABC
//
// Copyright (C) 2016-2022 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.


|







1
2
3
4
5
6
7
8
9
10
// abc2svg - toabc.js - convert ABC to ABC
//
// 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
		return ln
	} // meter_dump()

	function note_dump(s, note, tie_ch) {
	    var	p, j, sl, s2, a, d,
		ln = ""

		if (note.sls) {
			for (j = 0; j < note.sls.length; j++) {
				sl = note.sls[j];
				ln += slti_dump(sl.ty, '(')
				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]







|
<
<
|
<
<
<
<
<
<
<







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.sl1)


			ln += slti_dump(note.sl1, '(')







		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
					' ' + s.repeat_k + ']'
		}
		if (s.tp)
			tuplet_dump(s)
		if (s.sls) {
			for (i = 0; i < s.sls.length; i++) {
				sl = s.sls[i];





				line += slti_dump(sl.ty, '(')

				if (sl.is_note) {
					if (sl.note.sl2)
						sl.note.sl2++
					else
						sl.note.sl2 = 1
				} else {
					if (sl.note.s.sl2)
						sl.note.s.sl2++
					else
						sl.note.s.sl2 = 1
				}
			}
		}
		if (s.a_gch)
			gch_dump(s.a_gch)
		if (s.a_dd)
			line += deco_dump(s.a_dd)







>
>
>
>
>
|
>
|
|
|

|
|
|
|

|







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.nte) {
					if (sl.nte.sl2)
						sl.nte.sl2++
					else
						sl.nte.sl2 = 1
				} else if (sl.se) {
					if (sl.se.sl2)
						sl.se.sl2++
					else
						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
			break
		case C.STAVES:
			if (nv == 1)
				break
			staves_dump(s)
			break
		case C.STBRK:



			voice_out();
			abc2svg.print('%%staffbreak ' + s.xmx.toString() +
				(s.stbrk_forced ? 'f' : ''))
			break
		case C.BLOCK:
			voice_out();
			block_dump(s)
			break
		case C.REMARK:
			info_out('r:' + s.text)







>
>
>
|
|
|







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' : '') + ']'
			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
// abc2svg - tohtml.js - HTML+SVG generation
//
// Copyright (C) 2014-2022 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


// 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.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()


|
















|
>
















>







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-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,
	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
		abc2svg.print('</table>')
	}

	user.page_format = true

	// output the html header
	user.img_out = function(str) {


		if (init_done) {
			abc2svg.print(str)
			return




		}

		var	header = cfmt.header,
			footer = cfmt.footer,
			topmargin = cfmt.topmargin || "1cm",
			botmargin = cfmt.botmargin || "1cm",
			media_s = '@media print {\n\







>
>



>
>
>
>







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
			((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\
<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\
  <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







|










|







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(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" 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
		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)
				abc2svg.print(' v:' + s.v
					+ '  MIDI program '
					+ (s.chn + 1) + ' '
					+ s.instr)
			else
				abc2svg.print(' v:' + s.v
					+ '  MIDI channel ' + (s.chn + 1))







|







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 != 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
// abc2svg - toodt.js - ABC translation to ODT+SVG
//
// Copyright (C) 2017-2019 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.


|







1
2
3
4
5
6
7
8
9
10
// abc2svg - toodt.js - ABC translation to ODT+SVG
//
// 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
//
// 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,

	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 '\'


// get the command line arguments
function get_args(args) {
    var	a, i

	if (!args)			// compatibility
		return







>




|
>
>
>
>
>
>
>
>
>
>
|
|
|
|
>







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'

	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
		content + '\
 </office:text>\n\
</office:body>\n\
</office:document-content>\n',
		{ compression: "DEFLATE" });

	// Fonts/abc2svg.ttf



	zip.file('Fonts/abc2svg.ttf',
		fs.readFileSync(__dirname + sep + 'abc2svg.ttf'),
		{ compression: "STORE" });

// manifest.rdf (?)

	// META-INF/manifest.xml







>
>
>







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
	(footer || '') + '\
  </style:master-page>\n\
 </office:master-styles>\n\
</office:document-styles>',
		{ compression: "DEFLATE" });

// - generate the ODT file










	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







>
>
>
>
>
>
>
>
>
>





>







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
}

// entry point from cmdline
abc2svg.abc_init = function(args) {
	console.log('ODT generation started');

	get_args(args);










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






	    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"';







>
>
>
>
>
>
>
>
>













>
>
>
>
>
>







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







<
<
<








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);



	}

	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
// abcweb-1.js file to include in html pages
//
// Copyright (C) 2014-2022 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.


|







1
2
3
4
5
6
7
8
9
10
// abcweb-1.js file to include in html pages
//
// 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
					+ 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,







<







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

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







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







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


















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








<
<
<







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



	} // 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
		    var	i, j, e

			// start the generation
			outb = err = ""
			abc.tosvg(mu.n, t)	// music source

			abc2svg.abc_end()	// close the page if %%pageheight





			if (err)
				outb += '<pre class="nop" style="background:#ff8080">'
					+ err + "</pre>\n"

			if (abc.cfmt().with_source && outb)
				outb = '<pre class="source">'







>
>
>
>







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







>







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
			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 init argument
    user = {
	read_file: function(fn) {
		return a_inc[fn]
	}, // read_file()
	errmsg: function(msg, l, c) {	// get the errors







|
|







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()

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
	} // 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",
						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) {
		abc.tosvg(abc2svg.music[0].n,	// global definitions
			  abc2svg.music[0].t)
		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()







<
<
|
<












|
<
|
<
<
<
<
<
<
<







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("abc2svg-1.js", 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)

		musgen(abc2svg.music[0])	// global definitions








	// 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
	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 "],
	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+"],







|







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 "],
	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
			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.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







>
>







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

		// 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
				nv = s.v
				bk[nv] = 0		// bank 0
				if (p_v.midictl) {
					if (p_v.midictl[0])	// MSB
						bk[s.v] = (bk[s.v] & ~0x1fc000)
								+ (p_v.midictl[0] << 14)
					if (p_v.midictl[32])	// LSB
						bk[s.v] = (bk[s.v] & ~0x3f80)
								+ (p_v.midictl[32] << 7)
				}
			}
			switch (s.subtype) {
			case "midiprog":
				break
			case "midictl":
				if (s.ctrl != 0 && s.ctrl != 32)







|


|
|

|
|

|







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
				nv = s.v
				bk[nv] = 0		// bank 0
				if (s.p_v.midictl) {
					if (s.p_v.midictl[0])	// MSB
						bk[s.v] = (bk[s.v] & ~0x1fc000)
								+ (s.p_v.midictl[0] << 14)
					if (s.p_v.midictl[32])	// LSB
						bk[s.v] = (bk[s.v] & ~0x3f80)
								+ (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
				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
		 && !params[0]) {
			params[0] = []		// load the piano
			f(0, sf2par, sf2pre)
		}
	} // def_instr()

	// load the needed instruments







|







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
		 && !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
				parser = new sf2.Parser(b64dcod(abc2svg.sf2))
				parser.parse()
				presets = parser.getPresets()
			}

		// load the soundfont if not done yet
		} else if (!parser) {

		    if (conf.sfu.slice(-3) == ".js") {
			abc2svg.loadjs(conf.sfu,
				function() {
					load_res(s)	// load the instruments


				},
				function() {
					errmsg('could not load the sound file '
						+ conf.sfu)


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


				} else {
					errmsg('could not load the sound file '
						+ conf.sfu)


				}
			}
			r.onerror = function() {
					errmsg('could not load the sound file '
						+ conf.sfu)


			}
			r.send()
			return
		}

		// create the instruments and start playing
		def_instr(s, sf2_create, parser, presets)







>




>
>




>
>













>
>



>
>





>
>







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

		// initialize the audio subsystem if not done yet
		if (!gain) {
			ac = conf.ac
			if (!ac) {
				conf.ac = ac = new (window.AudioContext ||







|







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.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
// sndgen.js - sound generation
//
// 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.


|







1
2
3
4
5
6
7
8
9
10
// sndgen.js - sound generation
//
// 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
	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






































































































	// build the information about the parts (P:)
	function build_parts(first) {
	    var	i, j, c, n, v,
		s = first,
		p = s.parts,
		st = [],







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
			else if (d != ',')
				rsk.push(s)	// last
		}
	} // set_variant()

	// add() main

	// if some MIDI stuff, load the associated module
	if (cfmt.chord)
		abc2svg.chord(first, voice_tb, cfmt)





	if (s.parts)
		build_parts(s)

	// set the time parameters
	rst_fac = play_fac
	while (s) {







|


>
>
>
>







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







<
|
|
|
|
>
>
>
|
|
|
|
<
|
|







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.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
			}
			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
	// 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,
			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)
		}







|
<







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: s2.v

		}

		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
				} else {
					s = po.s_end
				}
				po.repv = 1
			}
			break
		}
	    if (s && s != po.s_end) {
		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')







|







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 && !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
		}
		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,
					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) {
//fixme: does not work with fluidsynth
			po.op.send(new Uint8Array([0xb0 + c, 121, 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

	} // midi_prog()

	// MIDI output is possible,
	// return the possible ports in return to get_outputs()
	function send_outputs(access) {
	    var	o, os,
		out = []







|










<
<
<


|


>
>






|
|
>
|
>
>
|
>







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




		// at channel start, reset and initialize the controllers
		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]]))
			}
}
		}

		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
					)
				}
			)
		}, // get_outputs()

		// set the output port
		set_output: function(name) {
		    var o, os
			if (!Midi5.ma)
				return

			os = Midi5.ma.outputs.values()

			while (1) {
				o = os.next()
				if (!o || o.done)
					break
				if (o.value.name == name) {
					op = o.value
					break







<


>

>







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) {

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