abc2svg
Check-in Differences
Not logged in

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

Difference From 7190e10838e534a3 To 433944c7887548a5

2019-02-06
14:25
batch: add 'abctopdf' ... (check-in: 2c9cf4bafe user: jef tags: trunk)
2019-02-01
15:55
New release v1.19.1 ... (check-in: 433944c788 user: jef tags: trunk, v1.19.1)
14:01
copyright update to 2019 ... (check-in: 83a7d2efe0 user: jef tags: trunk)
2018-06-21
08:33
back to trunk ... (check-in: 68ef6ecf8e user: jef tags: trunk)
2018-05-28
07:26
core: fix: accept 'exp' with bagpipe keys ... (check-in: 1909caa58f user: moinejf@free.fr tags: master)
2018-05-27
13:12
New release v1.17.4 ... (check-in: 7190e10838 user: moinejf@free.fr tags: trunk, v1.17.4)
13:10
core: remove useless double quotes ... (check-in: d41e047436 user: moinejf@free.fr tags: trunk)

Deleted .gitignore.
1
2
3
4
5
6
7
8
9
10










-
-
-
-
-
-
-
-
-
-
#
.*
*-1.css
*-1.js
*edit-1.xhtml
*~
abc2svg.woff
abc2svg.ttf
# important!
!.gitignore
Changes to README.md.
︙
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
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







-
+





-
+








-
+
+
+

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







-
+





-
+

-
+



-
+



+
+
-
+
-
-
+
-
-
-
-









-
-
+
+
+















-
-
-
+
-
-
+
-
-
+
-


-
+







**abc2svg** may be used in any web browser.
The needed files are available in my site
[http://moinejf.free.fr/js/](http://moinejf.free.fr/js).  
They are updated on release change.

These files are:

- `abc2svg-1.js`
- `abc2svg-1.js`   
  This script is the **abc2svg** core.  
  It contains the ABC parser and the SVG generation engine.  
  It must be included in the (X)HTML header of the pages
  where ABC rendering is needed (in `<script src=` tags).

- `abcemb-1.js`
- `abcemb-1.js`   
  This script is to be used with the core in (X)HTML files.  
  It replaces the ABC sequences by SVG images of the music
  (the ABC sequences start on `X:` or `%abc` at start of line,
  and stop on any ML tag).  
  See the
  [%%beginml documentation](http://moinejf.free.fr/abcm2ps-doc/beginml.xhtml)
  for an example.   
  When the URL of the (X)HTML file ends with '#' followed by a string,
  only the tunes containing this string are displayed.
  only the first tune containing this string is displayed.   
  Note that, if the ABC sequence contains the characters '<', '>' or '&',
  it must be enclosed in a XML comment (starting after the first `X:` or `%abc`).

- `abcemb2-1.js`   
  This script is also to be used with the core in (X)HTML files.  
  The differences with the previous script are
  - the ABC sequences are replaced in HTML elements with the class `abc`,
  - the string after '#' in the URL does a real %%select (i.e. this may
    select many tunes),
  - if the ABC sequences contain the characters '<', '>' or '&',
    either these sequences must be enclosed in a XML comment, or the characters
    must be replaced by their XML counterparts ('&amp;lt;', '&amp;gt;' or '&amp;amp;').
  
- `abcdoc-1.js`
- `abcdoc-1.js`   
  This script is also to be used in (X)HTML pages with the core.  
  Mainly used for ABC documentation, it lets the ABC source sequences
  in the page before the SVG images.  
  See the source of
  [abcm2ps/abc2svg features](http://moinejf.free.fr/abcm2ps-doc/features.xhtml)
  for an example.

- `play-1.js`
- `play-1.js`   
  This script may be used with `abcemb-1.js` for playing the
  rendered ABC music.  
  See [this page](http://moinejf.free.fr/abcm2ps-doc/au_clair.xhtml)
  for an example.

- `follow-1.js`
- `follow-1.js`   
  This script may be used after `play-1.js` for highlighting the notes
  while playing.
  while playing.   
  See [this page](http://moinejf.free.fr/abcm2ps-doc/tabac.xhtml)
  for an example.

- `edit-1.xhtml`
- `edit-1.xhtml`   
  This is a simple web ABC editor/player.

When looking at a ABC file in a web browser, you may also use
this
<a href="javascript:(function(){d=document;b=d.body;b.innerHTML=%22\n%25abc-2.2\n%25%3c!--\n%22+b.textContent+%22%25--%3e\n%22;function%20f(u){s=d.createElement('script');s.setAttribute('src',u);b.appendChild(s);};f('http://moinejf.free.fr/js/abc2svg-1.js');f('http://moinejf.free.fr/js/abcemb-1.js');f('http://moinejf.free.fr/js/play-1.js');function%20t(){if(typeof%20dom_loaded=='function'){dom_loaded()}else{setTimeout(t,200)}};setTimeout(t,200)})();void(0)">bookmarklet</a>
the following bookmarklet and render the music
and render the music
(create a bookmark and paste the following javascript code
into the address/location box).
(create a bookmark and copy the link location into the address/location box).

```
javascript:(function(){d=document;b=d.body;b.innerHTML="\n%25abc-2.2\n%25<!--\n"+b.textContent+"%25-->\n";function%20f(u){s=d.createElement('script');s.setAttribute('src',u);b.appendChild(s);};f('http://moinejf.free.fr/js/abc2svg-1.js');f('http://moinejf.free.fr/js/abcemb-1.js');f('http://moinejf.free.fr/js/play-1.js');function%20t(){if(typeof%20dom_loaded=="function"){dom_loaded()}else{setTimeout(t,200)}};setTimeout(t,200)})();void(0)
```

##### Notes:
- The music is rendered as SVG images. There is one image per
  music line / text block.  
  If you want to move these images to some other files,
  each one must contain the full CSS and defs. For that, insert
```
%%fullsvg x
```
  in the ABC file before rendering (see
  http://moinejf.free.fr/abcm2ps-doc/fullsvg.xhtml for more information).
  in the ABC file before rendering (see the
  [fullsvg documentation](http://moinejf.free.fr/abcm2ps-doc/fullsvg.xhtml)
  for more information).

- Playing uses the HTML5 audio and/or midi APIs.

- With the editor, if you want to render ABC files
  which contain `%%abc-include`, you must:
  - load the ABC file from the browse button
  - click in the include file name
  - load the include file by the same browse button  

  Then, you may edit and save both files.  
  Rendering/playing is always done from the first ABC file.  
  There may be only one included file.

- The editor comes with different ways to enter the music from the keyboard.  
  If you have a US keyboard, you may try these bookmarklets:

```
javascript:(function(){if(typeof%20loadjs=='function'){loadjs('abckbd-1.js')}else{alert('use%20with%20abc2svg%20editor')}})();void(0)
<a href="javascript:(function(){if(typeof%20loadjs=='function'){loadjs('abckbd-1.js')}else{alert('use%20with%20abc2svg%20editor')}})();void(0)">keyboard 1</a>
```

and
```
javascript:(function(){if(typeof%20loadjs=='function'){loadjs('abckbd2-1.js')}else{alert('use%20with%20abc2svg%20editor')}})();void(0)
<a href="javascript:(function(){if(typeof%20loadjs=='function'){loadjs('abckbd2-1.js')}else{alert('use%20with%20abc2svg%20editor')}})();void(0)">keyboard 2</a>
```

- The .js and .xhtml file names have a suffix which is the version of
  the core interface (actually `-1`).
  the core interface (actually '`-1`').

### nodeJS usage

Installed via **npm**, the **abc2svg** package comes with the
command line (batch) programs `abc2svg` and `abc2odt`.

These ones may be used as **abcm2ps** to generate XHTML or ODT files.   
︙
125
126
127
128
129
130
131
132
133
134





135
136

137

138
139
140
141
142
143
144
145
146
147
148
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







-
-
-
+
+
+
+
+


+
-
+


-
-







```
    abc2odt my_file.abc -o my_file.odt
```

### Build

If you want to build the **abc2svg** scripts in your machine,
you must first get the files
from [github](https://github.com/moinejf/abc2svg),
either as a `tar.gz` or `.zip` file, or by cloning the repository:
you must first get the files from
[chisel](https://chiselapp.com/user/moinejf/repository/abc2svg),
either as a tarball or a Zip archive
(click `Timeline` and then in the top commit),
or by cloning the repository in some directory:

```
    fossil clone https://chiselapp.com/user/moinejf/repository/abc2svg abc2svg.fossil
    git clone http://github.com/moinejf/abc2svg
    fossil open abc2svg.fossil
```

(you may use `--depth=1` if you don't want the full `git` history)

Then, building is done using the tool [ninja](https://ninja-build.org/)
or [samurai](https://github.com/michaelforney/samurai).  
You may do it:

- without minification  
  This is interesting for debug purpose, the scripts being more human friendly.

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








+
+
+







+














-
-
+
+
-
-
-
+
-







-
+
-
-
-
+
-








-
+
-
-
-
+
-
file `font/abc2svg.sfd`. In this case, you will need both `base64` and `fontforge`,
and run

```
    samu -v font.js
```

If you cannot or don't want to install `ninja` or `samurai`, you may build
the abc2svg files by `./build` which is a shell script.

### Batch

After building the **abc2svg** scripts, you will be able to generate music
sheets from the command line as you did with `abcm2ps`, thanks to the
following shell scripts (the result goes to stdout):  

- `abcjs24` with `js24` (Mozilla JavaScript shell - Spidermonkey)
- `abcjs52` with `js52` (Mozilla JavaScript shell - Spidermonkey)
- `abcjsc` with `jsc-1` (webkitgtk2)
- `abcnode` with `node` (nodeJS)
- `abcv8` with `d8` (Google libv8)

#### backend scripts

By default, the batch scripts generate (XHTML+SVG) files.   
This output may be modified by backend scripts. These ones must appear
just after the command.   
There are:

- `toabc.js`   
  This script outputs back the (selected) ABC tunes of the ABC source file.   
  Transposition is applied.   
  The resulting file does not contain the formatting parameters.
  Example:
  The resulting file does not contain the formatting parameters.   
  Example:   

```
	abcjs24 toabc.js my_file.abc --select X:2 > tune_2.abc
  `abcjs52 toabc.js my_file.abc --select X:2 > tune_2.abc`
```

- `toabw.js`   
  This script outputs a Abiword file (ABW+SVG) which may be read by some
  word processors (abiword, libreoffice...) and converted to many other
  formats by the batch function of abiword.   
  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:
  Example:   

```
	abcv8 toabw.js my_file.abc > my_file.abw
  `abcv8 toabw.js my_file.abc > my_file.abw`
```

- `toodt.js`   
  This script creates an Open Document (ODT+SVG) which may be read by most
  word processors (abiword, libreoffice...).   
  It runs only with the npm script `abc2svg` and asks for the npm module
  `jszip` to be installed.   
  The output ODT document may be specified by the command line argument `-o`
  (default `abc.odt`).   
  Example:
  Example:   

```
	abc2svg toodt.js my_file.abc -o my_file.odt
  `abc2svg toodt.js my_file.abc -o my_file.odt`
```
Added abc2svg.ttf.

cannot compute difference between binary files

Added abcjs52.

























































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#!/usr/bin/env js52
// abc2svg with js52 (Mozilla JavaScript shell - Spidermonkey
//		packages: debian: libmozjs-52-dev, voidlinux: mozjs52)

loadRelativeToScript("abc2svg-1.js")

// interpreter specific functions
abc2svg.print = function(str) {
	print(str)
}
abc2svg.printErr = function(str) {
	printErr(str)
}

abc2svg.quit = function() {
	quit(1)
}
abc2svg.readFile = function(fname) {
	return read(fname)
}
abc2svg.loadjs = function(fn, relay, onerror) {
	try {
		loadRelativeToScript(fn)
		if (relay)
			relay()
	} catch(e) {
		if (onerror)
			onerror()
		else
			printErr('Cannot read file ' + fn)
	}
} // loadjs()

loadRelativeToScript("cmdline.js")

// main
	var	args = scriptArgs

	if (/\.js$/.test(args[0])) {
		load(args[0])
		args.shift()
	}
	if (typeof abc2svg.abc_init != 'function')
		loadRelativeToScript("toxhtml.js")
	if (!args[0]) {
		printErr('ABC translator with js52 (SpiderMonkey)\
 and abc2svg-' + abc2svg.version + ' ' + abc2svg.vdate + '\n\
Usage:\n\
  abcjs52 [script.js] [g_options] ABC_file [f_options] [ABC_file [f_options]]*\n\
Arguments:\n\
  script.js  generation script to load - default: toxhtml.js (XHTML+SVG)\n\
  g_options  global ABC options\n\
  ABC_file   ABC file\n\
  f_options  file options')
		quit()
	}
	abc_cmd("abcjs52", args)
Changes to abcjsc.
1
2

3
4
5

6
7
8
9
10
11
12
1

2
3
4

5
6
7
8
9
10
11
12

-
+


-
+







#!/bin/sh
# abc2svg with jsc-1 (webkitgtk2)
# abc2svg with jsc (webkit2gtk)
progdir=`dirname $0`

exec jsc-1 -e "var progdir='${progdir}/'
exec jsc -e "var progdir='${progdir}/'

// function to do utf-8 work...
// uncommenting this function asks for also uncommenting its call in cmdline.js
//function utf_convert(fin) {
//	var	b1, b2,
//		fout = ''
//	for (var i = 0; i < fin.length; i++) {
︙
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
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







-
-
-

-
+










+
+


+
+
+



load(progdir + 'cmdline.js')

function main(args) {
	if (/\.js$/.test(args[0])) {
		load(args[0])
		args.shift()
	}
	if (typeof(abc2svg.abc_init) != 'function')
		load(progdir + 'toxhtml.js')
	}
	if (!args[0]) {
		print('ABC translator with jsc-1 (webkitgtk2)\
		print('ABC translator with jsc (webkit2gtk)\
 and abc2svg-' + abc2svg.version + ' ' + abc2svg.vdate + '\n\
Usage:\n\
  abcjsc [script.js] [g_options] ABC_file [f_options] [ABC_file [f_options]]*\n\
Arguments:\n\
  script.js  script to load - default: toxhtml.js (XHTML+SVG generation)\n\
  g_options  global ABC options\n\
  ABC_file   ABC file\n\
  f_options  file options')
		quit()
	}
	if (typeof(abc2svg.abc_init) != 'function')
		load(progdir + 'toxhtml.js')
	abc_cmd('abcjsc', args)
}

if (typeof arguments == 'undefined')
	var arguments = ''

main(arguments)
" -- "$@"
Changes to abcnode.
1
2
3
4
5

6
7
8
9
10
11
12

13
14
15
16
17
18
19
1
2
3
4

5
6
7
8
9
10
11

12
13
14
15
16
17
18
19




-
+






-
+







#!/bin/sh
# abc2svg with raw nodeJS
progdir=`dirname $0`

cat ${progdir}/abc2svg-1.js ${progdir}/cmdline.js > /tmp/toto.js
cat ${progdir}/abc2svg-1.js > /tmp/toto.js
case $1 in
	*.js)
		cat $1 >> /tmp/toto.js
		shift
		;;
esac
if ! grep 'abc2svg.abc_init =' $1 > /dev/null; then
if ! grep 'abc2svg.abc_init =' "$1" > /dev/null; then
	cat ${progdir}/toxhtml.js >> /tmp/toto.js
fi

cat <<EOF >> /tmp/toto.js
    var	progdir='${progdir}/'

// interpreter specific functions
︙
45
46
47
48
49
50
51

52



53
54
55
56
57
58
59
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63







+

+
+
+







			abc2svg.printErr('Cannot read file ' + fn)
	}
}

// (this file is wrapped)
global.Abc = Abc
global.abc2svg = abc2svg
EOF

cat ${progdir}/cmdline.js >> /tmp/toto.js

cat <<EOF >> /tmp/toto.js
// main
	var args = process.argv
	if (!args[2]) {
		abc2svg.print('ABC translator with nodeJS\
 and abc2svg-' + abc2svg.version + ' ' + abc2svg.vdate + '\n\
Usage:\n\
  abcnode [script.js] [g_options] ABC_file [f_options] [ABC_file [f_options]]*\n\
︙
Added build.
















































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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#!/bin/sh
# simple build of abc2svg as a shell script

MAJOR=1

out=abc2svg-$MAJOR.js
VERSION=`grep '"version"' package.json|cut -d'"' -f4`
DATE=`date '+%Y-%m-%d' -r package.json`
cp core/license $out
cat 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 >> $out
 echo "abc2svg.version=\"$VERSION\";abc2svg.vdate=\"$DATE\"" >> $out

cp modules/ambitus.js ambitus-$MAJOR.js
cp modules/break.js break-$MAJOR.js
cp modules/capo.js capo-$MAJOR.js
cp modules/clip.js clip-$MAJOR.js
cp modules/combine.js combine-$MAJOR.js
cp modules/diag.js diag-$MAJOR.js
cp modules/equalbars.js equalbars-$MAJOR.js
cp modules/grid.js grid-$MAJOR.js
cp modules/grid2.js grid2-$MAJOR.js
cp modules/MIDI.js MIDI-$MAJOR.js
cp modules/page.js page-$MAJOR.js
cp modules/perc.js perc-$MAJOR.js
cat modules/wps.js modules/psvg.js > psvg-$MAJOR.js
cp modules/soloffs.js soloffs-$MAJOR.js
cp modules/sth.js sth-$MAJOR.js
cp modules/temper.js temper-$MAJOR.js

cp editor/edit.css edit-$MAJOR.css

cp util/abcdoc.js abcdoc-$MAJOR.js
cp util/abcemb.js abcemb-$MAJOR.js
cp util/abcemb2.js abcemb2-$MAJOR.js
cp util/follow.js follow-$MAJOR.js
cp util/json.js json-$MAJOR.js
cp util/midi.js setmidi-$MAJOR.js
cp util/toaudio.js toaudio-$MAJOR.js
cat util/play.js util/toaudio.js util/toaudio5.js\
 util/sf2-parser.js util/tomidi5.js > play-$MAJOR.js

sed "s+@MAJOR@+$MAJOR+" editor/edit.xhtml > edit-$MAJOR.xhtml
sed "s+@MAJOR@+$MAJOR+" editor/abckbd.js > abckbd-$MAJOR.js
sed "s+@MAJOR@+$MAJOR+" editor/abckbd2.js > abckbd2-$MAJOR.js
sed "s+@MAJOR@+$MAJOR+" editor/edit.js > edit-$MAJOR.js
Changes to build.ninja.
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
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







+
+
+




-
+





-
+




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


-
-
+

-
+

-
+
+


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

-
+




-
+

-
+






-
-
-
+
+
+

-
-
-
-
-
+
+
+
+
+










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



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

-
+
-


-
-
-
+
+
+


-
-
+
+

-
-
-
+
+
+




-
+
-


-
-
-
-
+
+
+
+


# rules for ninja (ninja-build)

# 'uglifyjs' may be disabled running
#	NOMIN=1 ninja -v

MAJOR=1

# ninja tool
tool=samu

rule cp
  command = cp $in $out

rule cpm
  command = sed "s+@MAJOR@+$MAJOR+"  $in > $out
  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/font-ttf;base64,\\" >> font.js;$
   echo "var musicfont = 'url(\"data:application/x-font-ttf;base64,\\" >> font.js;$
   base64 abc2svg.ttf | sed 's/$$/\\/' >> font.js;$
   echo "\")'" >> font.js

rule jsc
  command = VERSION=`grep '"version"' package.json|cut -d'"' -f4`;$
   type fossil &> /dev/null;$
  command = if [ -x /usr/bin/git -a -d .git ]; then$
	VERSION=`git describe`;$
	VERSION=$${VERSION#v};$
	DATE=`git log -1 --pretty=format:%ci HEAD | cut -d' ' -f1`;$
   else$
	VERSION=`grep '"version"' package.json|cut -d'"' -f4`;$
   if [ $$? -eq 0 ]; then $
	c=`fossil info | grep checkout:`;$
	t=`fossil info | grep tags: | awk '{print $$NF}'`;$
	if [ "$${t#v}" != "$$VERSION" ]; then $
		VERSION="$${VERSION}-$$(echo $$c | cut -d' ' -f2 | cut -c1-10)";$
	fi;$
	DATE=`echo $$c | cut -d' ' -f3`;$
   else $
	DATE=`date '+%Y-%m-%d' -r package.json`;$
	DATE=`stat --printf=%y build.ninja | cut -d' ' -f1`;$
   fi;$
   cp core/license $out;$
   echo "var abc2svg={version:\"$$VERSION\",vdate:\"$$DATE\"}" >> $out;$
   if [ "x$$NOMIN" = "x" ]; then$
   if [ "x$$NOMIN" = "x" ]; then $
	cat $in | uglifyjs >> $out;$
   else$
   else $
	cat $in >> $out;$
   fi
   fi;$
   echo "abc2svg.version=\"$$VERSION\";abc2svg.vdate=\"$$DATE\"" >> $out

rule jscu
  command = if [ -x /usr/bin/git -a -d .git ]; then$
	VERSION=`git describe`;$
	VERSION=$${VERSION#v};$
	DATE=`git log -1 --pretty=format:%ci HEAD | cut -d' ' -f1`;$
   else$
	VERSION=`grep '"version"' package.json|cut -d'"' -f4`;$
	DATE=`stat --printf=%y build.ninja | cut -d' ' -f1`;$
   fi;$
   cp core/license $out;$
  command = cp core/license $out;$
   echo "// $out for abc2svg-$$VERSION ($$DATE)" >> $out;$
   if [ "x$$NOMIN" = "x" ]; then$
   if [ "x$$NOMIN" = "x" ]; then $
	uglifyjs $in >> $out;$
   else$
   else $
	cat $in >> $out;$
   fi

rule edit
  command = if [ "x$$NOMIN" = "x" ]; then$
  command = if [ "x$$NOMIN" = "x" ]; then $
	sed "s+@MAJOR@+$MAJOR+" $in | uglifyjs > $out;$
   else$
   else $
	sed "s+@MAJOR@+$MAJOR+" $in > $out;$
   fi

# generate all Scc1t2/n.js from sf2-Scc1t2/n.sf2
rule sf
  command = for f in sf2-Scc1t2/*.sf2; do $
   instr=`basename $$f`; $
   o=$${f#sf2-}; $
   o=$${o%.sf2}.js; $
   instr=`basename $$f`;$
   o=$${f#sf2-};$
   o=$${o%.sf2}.js;$
   if [ ! -r $$o -o $$f -nt $$o ]; then $
   echo '// abc2svg sound font' > $$o; $
   echo "abcsf2[$${instr%.sf2}] = '\\" >> $$o; $
   base64 $$f | sed 's/$$/\\/' >> $$o; $
   echo "'" >> $$o; $
   fi; $
   echo '// abc2svg sound font' > $$o;$
   echo "abcsf2[$${instr%.sf2}] = '\\" >> $$o;$
   base64 $$f | sed 's/$$/\\/' >> $$o;$
   echo "'" >> $$o;$
   fi;$
   done

build font: font | font/abc2svg.sfd
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 | package.json
build break-$MAJOR.js: jscu modules/break.js | package.json
build capo-$MAJOR.js: jscu modules/capo.js | package.json
build clip-$MAJOR.js: jscu modules/clip.js | package.json
build combine-$MAJOR.js: jscu modules/combine.js | package.json
build diag-$MAJOR.js: jscu modules/diag.js | package.json
build grid-$MAJOR.js: jscu modules/grid.js | package.json
build grid2-$MAJOR.js: jscu modules/grid2.js | package.json
build MIDI-$MAJOR.js: jscu modules/MIDI.js | package.json
build perc-$MAJOR.js: jscu modules/perc.js | package.json
build psvg-$MAJOR.js: jscu modules/wps.js modules/psvg.js | package.json
build sth-$MAJOR.js: jscu modules/sth.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 clip-$MAJOR.js: jscu modules/clip.js
build combine-$MAJOR.js: jscu modules/combine.js
build diag-$MAJOR.js: jscu modules/diag.js
build equalbars-$MAJOR.js: jscu modules/equalbars.js
build grid-$MAJOR.js: jscu modules/grid.js
build grid2-$MAJOR.js: jscu modules/grid2.js
build MIDI-$MAJOR.js: jscu modules/MIDI.js
build page-$MAJOR.js: jscu modules/page.js
build perc-$MAJOR.js: jscu modules/perc.js
build psvg-$MAJOR.js: jscu modules/wps.js modules/psvg.js
build soloffs-$MAJOR.js: jscu modules/soloffs.js
build sth-$MAJOR.js: jscu modules/sth.js
build temper-$MAJOR.js: jscu modules/temper.js

build edit-$MAJOR.css: cp editor/edit.css

build abcdoc-$MAJOR.js: jscu util/abcdoc.js | package.json
build abcemb-$MAJOR.js: jscu util/abcemb.js | package.json
build follow-$MAJOR.js: jscu util/follow.js | package.json
build json-$MAJOR.js: jscu util/json.js | package.json
build setmidi-$MAJOR.js: jscu util/midi.js | package.json
build abcdoc-$MAJOR.js: jscu util/abcdoc.js
build abcemb-$MAJOR.js: jscu util/abcemb.js
build abcemb2-$MAJOR.js: jscu util/abcemb2.js
build follow-$MAJOR.js: jscu util/follow.js
build json-$MAJOR.js: jscu util/json.js
build setmidi-$MAJOR.js: jscu util/midi.js
build toaudio-$MAJOR.js: jscu util/toaudio.js
build play-$MAJOR.js: jscu util/play.js util/toaudio.js $
 util/toaudio5.js util/sf2-parser.js util/tomidi5.js | package.json
 util/toaudio5.js util/sf2-parser.js util/tomidi5.js
build toaudio-$MAJOR.js: jscu util/toaudio.js | package.json

build edit-$MAJOR.xhtml: cpm editor/edit.xhtml
build abckbd-$MAJOR.js: edit editor/abckbd.js | package.json
build abckbd2-$MAJOR.js: edit editor/abckbd2.js | package.json
build edit-$MAJOR.js: edit editor/edit.js | package.json
build abckbd-$MAJOR.js: edit editor/abckbd.js
build abckbd2-$MAJOR.js: edit editor/abckbd2.js
build edit-$MAJOR.js: edit editor/edit.js

build all: phony abc2svg-$MAJOR.js abcdoc-$MAJOR.js $
 abcemb-$MAJOR.js json-$MAJOR.js setmidi-$MAJOR.js $
 play-$MAJOR.js toaudio-$MAJOR.js psvg-$MAJOR.js $
 abcemb-$MAJOR.js abcemb2-$MAJOR.js json-$MAJOR.js setmidi-$MAJOR.js $
 toaudio-$MAJOR.js play-$MAJOR.js psvg-$MAJOR.js $
 ambitus-$MAJOR.js break-$MAJOR.js capo-$MAJOR.js clip-$MAJOR.js $
 combine-$MAJOR.js diag-$MAJOR.js grid-$MAJOR.js grid2-$MAJOR.js $
 MIDI-$MAJOR.js perc-$MAJOR.js sth-$MAJOR.js $
 edit-$MAJOR.css edit-$MAJOR.js edit-$MAJOR.xhtml $
 combine-$MAJOR.js diag-$MAJOR.js equalbars-$MAJOR.js grid-$MAJOR.js grid2-$MAJOR.js $
 MIDI-$MAJOR.js page-$MAJOR.js perc-$MAJOR.js soloffs-$MAJOR.js sth-$MAJOR.js $
 temper-$MAJOR.js edit-$MAJOR.css edit-$MAJOR.js edit-$MAJOR.xhtml $
 abckbd-$MAJOR.js abckbd2-$MAJOR.js follow-$MAJOR.js

default all

# npm/git new release
# npm/fossil new release
# (needs 'npm set git-tag-version false')
rule version
  command = npm version $out;$
	tag=`grep '"version"' package.json|cut -d'"' -f4`;$
	echo "New release v$$tag" | git commit -F- package.json;$
	git tag -a v$$tag;$
	echo "*** Don't forget: git push --follow-tags; ninja; npm publish"
	tag=`ag '"version"' package.json|cut -d'"' -f4`;$
	fossil commit -m "New release v$$tag" -tag v$$tag;$
	$tool -v;$
	npm publish
build minor: version
build patch: version
Changes to cmdline.js.
︙
69
70
71
72
73
74
75



76
77
78

79
80
81
82
83
84
85
86
87
88
89
90
91
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







+
+
+



+




-
-







		abc2svg.abort(e)
	}
} // do_file()

function abc_cmd(cmd, args) {
	var	arg, parm, fn;

	// initialize the backend
	abc2svg.abc_init(args)

	// load 'default.abc'
	try {
		arg = user.read_file('default.abc');
		abc2svg.modules.load(arg)
		abc.tosvg(cmd, arg)
	} catch (e) {
	}

	// initialize the backend
	abc2svg.abc_init(args)
	while (1) {
		arg = args.shift()
		if (!arg)
			break
		if (arg[0] == "-") {
			if (arg[1] == "-") {
				parm = args.shift();
︙
Changes to core/abc2svg.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
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


-
+
















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

-
+


+
+
+






-
-

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

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

-
+













-



















+
-
+

-
+







// abc2svg - abc2svg.js
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-2019 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/>.

// start of the abc2svg object
var abc2svg = {

// constants
    C: {
	BLEN: 1536,

	// symbol types
	BAR: 0,
	CLEF: 1,
	CUSTOS: 2,
	GRACE: 4,
	KEY: 5,
	METER: 6,
	MREST: 7,
	NOTE: 8,
	PART: 9,
	REST: 10,
	SPACE: 11,
	STAVES: 12,
	STBRK: 13,
	TEMPO: 14,
	BLOCK: 16,
	REMARK: 17,

	// note heads
	FULL: 0,
	EMPTY: 1,
	OVAL: 2,
	OVALBARS: 3,
	SQUARE: 4,

	// slur/tie types (3 + 1 bits)
	SL_ABOVE: 0x01,
	SL_BELOW: 0x02,
	SL_AUTO: 0x03,
	SL_HIDDEN: 0x04,
	SL_DOTTED: 0x08		// (modifier bit)
    },

// start of the Abc object
abc2svg.Abc = function(user) {
  Abc: function(user) {
	"use strict";

    // constants
    var	C = abc2svg.C;

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

	this.user = user

// -- constants --
// symbol types
var	BAR = 0,
	CLEF = 1,
	CUSTOS = 2,
//	FORMAT = 3,
	GRACE = 4,
	KEY = 5,
	METER = 6,
	MREST = 7,
	NOTE = 8,
	PART = 9,
	REST = 10,
	SPACE = 11,
	STAVES = 12,
	STBRK = 13,
	TEMPO = 14,
//	TUPLET = 15,
	BLOCK = 16,
	REMARK = 17,

// note heads
	FULL = 0,
	EMPTY = 1,
	OVAL = 2,
	OVALBARS = 3,
	SQUARE = 4,

/* slur/tie types (3 + 1 bits) */
	SL_ABOVE = 0x01,
	SL_BELOW = 0x02,
	SL_AUTO = 0x03,
	SL_HIDDEN = 0x04,
	SL_DOTTED = 0x08,		/* (modifier bit) */

// staff system
	OPEN_BRACE = 0x01,
var	OPEN_BRACE = 0x01,
	CLOSE_BRACE = 0x02,
	OPEN_BRACKET = 0x04,
	CLOSE_BRACKET = 0x08,
	OPEN_PARENTH = 0x10,
	CLOSE_PARENTH = 0x20,
	STOP_BAR = 0x40,
	FL_VOICE = 0x80,
	OPEN_BRACE2 = 0x0100,
	CLOSE_BRACE2 = 0x0200,
	OPEN_BRACKET2 = 0x0400,
	CLOSE_BRACKET2 = 0x0800,
	MASTER_VOICE = 0x1000,

	BASE_LEN = 1536,
	IN = 96,		// resolution 96 PPI
	CM = 37.8,		// 1 inch = 2.54 centimeter
	YSTEP = 256		/* number of steps for y offsets */

// error texts
var errs = {
	bad_char: "Bad character '$1'",
	bad_val: "Bad value in $1",
	bar_grace: "Cannot have a bar in grace notes",
	ignored: "$1: inside tune - ignored",
	misplaced: "Misplaced '$1' in %%staves",
	must_note: "!$1! must be on a note",
	must_note_rest: "!$1! must be on a note or a rest",
	nonote_vo: "No note in voice overlay",
	not_enough_n: 'Not enough notes/rests for %%repeat',
	not_enough_m: 'Not enough measures for %%repeat',
	not_ascii: "Not an ASCII character"
}

    var	self = this,				// needed for modules
var	glovar = {
	glovar = {
		meter: {
			type: METER,		// meter in tune header
			type: C.METER,		// meter in tune header
			wmeasure: 1,		// no M:
			a_meter: []		// default: none
		}
	},
	info = {},			// information fields
	mac = {},			// macros (m:)
	maci = new Int8Array(128),	// first letter of macros
︙
Changes to core/deco.js.
1
2
3

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

22
23
24
25
26
27
28
29
1
2

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

21

22
23
24
25
26
27
28


-
+

















-
+
-







// abc2svg - deco.js - decorations
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-2019 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	dd_tb = {},		// definition of the decorations
	a_de,			// array of the decoration elements
	a_de			// array of the decoration elements
	od		// ottava: index = type + staff, value = counter + voice number

// decorations - populate with standard decorations
var decos = {
	dot: "0 stc 5 1 1",
	tenuto: "0 emb 5 3 3",
	slide: "1 sld 3 7 0",
	arpeggio: "2 arp 12 10 0",
︙
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
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







-
-
+
+








-
-
+
+








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

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







	"1": "3 fng 8 3 3 1",
	"2": "3 fng 8 3 3 2",
	"3": "3 fng 8 3 3 3",
	"4": "3 fng 8 3 3 4",
	"5": "3 fng 8 3 3 5",
	plus: "3 dplus 7 3 3",
	"+": "3 dplus 7 3 3",
	accent: "3 accent 6 4 4",
	">": "3 accent 6 4 4",
	accent: "3 accent 7 4 4",
	">": "3 accent 7 4 4",
	marcato: "3 marcato 9 3 3",
	"^": "3 marcato 9 3 3",
	mordent: "3 lmrd 10 5 5",
	open: "3 opend 10 3 3",
	snap: "3 snap 14 3 3",
	thumb: "3 thumb 14 3 3",
	dacapo: "3 dacs 16 20 20 Da Capo",
	dacoda: "3 dacs 16 20 20 Da Coda",
	"D.C.": "3 dacs 16 10 10 D.C.",
	"D.S.": "3 dacs 16 10 10 D.S.",
	"D.C.": "3 dcap 16 10 10",
	"D.S.": "3 dsgn 16 10 10",
	"D.C.alcoda": "3 dacs 16 38 38 D.C. al Coda",
	"D.S.alcoda": "3 dacs 16 38 38 D.S. al Coda",
	"D.C.alfine": "3 dacs 16 38 38 D.C. al Fine",
	"D.S.alfine": "3 dacs 16 38 38 D.S. al Fine",
	fine: "3 dacs 16 10 10 Fine",
	turn: "3 turn 10 0 5",
	"trill(": "3 ltr 8 0 0",
	"trill)": "3 ltr 8 0 0",
	f: "6 pf 18 1 7",
	ff: "6 pf 18 2 10",
	fff: "6 pf 18 4 13",
	ffff: "6 pf 18 6 16",
	mf: "6 pf 18 6 13",
	mp: "6 pf 18 6 16",
	p: "6 pf 18 2 8",
	pp: "6 pf 18 5 14",
	ppp: "6 pf 18 8 20",
	pppp: "6 pf 18 10 25",
	f: "6 f 18 1 7",
	ff: "6 ff 18 2 10",
	fff: "6 fff 18 4 13",
	ffff: "6 ffff 18 6 16",
	mf: "6 mf 18 6 13",
	mp: "6 mp 18 6 16",
	p: "6 p 18 2 8",
	pp: "6 pp 18 5 14",
	ppp: "6 ppp 18 8 20",
	pppp: "6 pppp 18 10 25",
	pralltriller: "3 umrd 10 5 5",
	sfz: '6 sfz 18 4 10 ""',
	ped: "4 ped 20 0 0",
	"ped-up": "4 pedoff 20 0 0",
	"crescendo(": "7 cresc 18 0 0",
	"crescendo)": "7 cresc 18 0 0",
	"<(": "7 cresc 18 0 0",
	"<)": "7 cresc 18 0 0",
	"diminuendo(": "7 dim 18 0 0",
	"diminuendo)": "7 dim 18 0 0",
	">(": "7 dim 18 0 0",
	">)": "7 dim 18 0 0",
	sfz: "6 sfz 18 4 10",
	ped: "4 ped 18 8 8",
	"ped-up": "4 pedoff 18 8 8",
	"ped(": "4 lped 20 1 1",
	"ped)": "4 lped 20 1 1",
	"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",
	"8va(": "3 8va 10 0 0",
	"8va)": "3 8va 10 0 0",
	"8vb(": "4 8vb 10 0 0",
︙
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
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







-
+

-
+








-
+










-
+






-
+


-
-
+
+




















-
+







		}
	}
}

/* -- get the staff position of the dynamic and volume marks -- */
function up_p(s, pos) {
	switch (pos) {
	case SL_ABOVE:
	case C.SL_ABOVE:
		return true
	case SL_BELOW:
	case C.SL_BELOW:
		return false
	}
	if (s.multi && s.multi != 0)
		return s.multi > 0
	if (!s.p_v.have_ly)
		return false

	/* above if the lyrics are below the staff */
	return s.pos.voc != SL_ABOVE
	return s.pos.voc != C.SL_ABOVE
}

/* -- drawing functions -- */
/* 2: special case for arpeggio */
function d_arp(de) {
	var	m, h, dx,
		s = de.s,
		dd = de.dd,
		xc = 5

	if (s.type == NOTE) {
	if (s.type == C.NOTE) {
		for (m = 0; m <= s.nhd; m++) {
			if (s.notes[m].acc) {
				dx = 5 + s.notes[m].shac
			} else {
				dx = 6 - s.notes[m].shhd
				switch (s.head) {
				case SQUARE:
				case C.SQUARE:
					dx += 3.5
					break
				case OVALBARS:
				case OVAL:
				case C.OVALBARS:
				case C.OVAL:
					dx += 2
					break
				}
			}
			if (dx > xc)
				xc = dx
		}
	}
	h = 3 * (s.notes[s.nhd].pit - s.notes[0].pit) + 4;
	m = dd.h			/* minimum height */
	if (h < m)
		h = m;

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

/* 7: special case for crescendo/diminuendo */
// special case for long dynamic decorations
function d_cresc(de) {
	if (de.ldst)			// skip start of deco
		return
	var	s, dd, dd2, up, x, dx, x2, i,
		s2 = de.s,
		de2 = de.start,		/* start of the deco */
		de2_prev, de_next;
︙
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
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







-
+















-
+



+
+
+
+
+
+
+
+







	}
	if (up)
		s.ymx = y + dd.h
	else
		s.ymn = y;
	de.y = y
//	de.x = s.x + s.notes[s.stem >= 0 ? 0 : s.nhd].shhd
	if (s.type == NOTE)
	if (s.type == C.NOTE)
		de.x += s.notes[s.stem >= 0 ? 0 : s.nhd].shhd
	if (dd.name[0] == 'd'			/* if dot decoration */
	 && s.nflags >= -1) {			/* on stem */
		if (up) {
			if (s.stem > 0)
				de.x += 3.5	// stem_xoff
		} else {
			if (s.stem < 0)
				de.x -= 3.5
		}
	}
}

/* 6: dynamic marks */
function d_pf(de) {
	var	dd2, x2, str, x, up,
	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.start) {			// if long decoration
		d_cresc(de)
		return
	}

	de.val = dd.wl + dd.wr;
	up = up_p(s, s.pos.vol)
	if (up)
		de.up = true;
	x = s.x - dd.wl
	if (de.ix > 0) {
︙
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
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







-
+


-
-
+
+












-
+



-
+
+











-
-
+
+

















-
+








	for (m = 0; m <= s.nhd; m++) {
		if (s.notes[m].acc) {
			dx = 4 + s.notes[m].shac
		} else {
			dx = 5 - s.notes[m].shhd
			switch (s.head) {
			case SQUARE:
			case C.SQUARE:
				dx += 3.5
				break
			case OVALBARS:
			case OVAL:
			case C.OVALBARS:
			case C.OVAL:
				dx += 2
				break
			}
		}
		if (s.notes[m].pit <= yc + 3 && dx > xc)
			xc = dx
	}
//	de.x = s.x - xc;
	de.x -= xc;
	de.y = 3 * (yc - 18)
}

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

	if (de.prev) {			// hack 'tr~~~~~'
		x = de.prev.x + 10;
		y = de.prev.y
	}
	de.st = st

	if (de.dd.func != 4) {		// if not below
		switch (de.dd.glyph) {
	if (dd.func != 4) {		// if not below
		switch (dd.glyph) {
		case "8va":
		case "15ma":
			up = 1
			break
		default:
			up = s2.multi >= 0
			break
		}
	}
	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 == NOTE)
		if (s2.type == C.NOTE)
			w -= 6
		if (w < 20) {
			x -= (20 - w) * .5;
			w = 20
		}
	}
	dd = de.dd;
︙
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
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
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







-
+


-
+












-
+







-
+














-
+

-
+







-
+





-
+







	if (s.nhd)
		x += s.notes[s.stem >= 0 ? 0 : s.nhd].shhd;
	up = -1
	if (dd.func == 4) {		// below
		up = 0
	} else if (s.pos) {
		switch (s.pos.orn) {
		case SL_ABOVE:
		case C.SL_ABOVE:
			up = 1
			break
		case SL_BELOW:
		case C.SL_BELOW:
			up = 0
			break
		}
	}

	switch (dd.glyph) {
	case "accent":
	case "roll":
		if (!up
		 || (up < 0
		  && (s.multi < 0
		   || (!s.multi && s.stem > 0)))) {
			yc = y_get(s.st, false, s.x - dd.wl, w)
			yc = y_get(s.st, false, s.x - dd.wl, w) - 2
			if (yc > staffb)
				yc = staffb;
			yc -= dd.h;
			y_set(s.st, false, s.x, 0, yc);
			inv = true;
			s.ymn = yc
		} else {
			yc = y_get(s.st, true, s.x, 0)
			yc = y_get(s.st, true, s.x - dd.wl, w) + 2
			if (yc < stafft)
				yc = stafft;
			y_set(s.st, true, s.x - dd.wl, w, yc + dd.h);
			s.ymx = yc + dd.h
		}
		break
	case "brth":
	case "lphr":
	case "mphr":
	case "sphr":
		yc = stafft + 1
		if (dd.glyph == "brth" && yc < s.ymx)
			yc = s.ymx
		for (s = s.ts_next; s; s = s.ts_next)
			if (s.shrink)
			if (s.seqst)
				break
		x += ((s ? s.x : realwidth) - x) * .4
		x += ((s ? s.x : realwidth) - x) * .45
		break
	default:
		if (dd.name.indexOf("invert") == 0)
			inv = true
		if (dd.name != "invertedfermata"
		 && (up > 0
		  || (up < 0 && s.multi >= 0))) {
			yc = y_get(s.st, true, s.x - dd.wl, w)
			yc = y_get(s.st, true, s.x - dd.wl, w) + 2
			if (yc < stafft)
				yc = stafft;
			y_set(s.st, true, s.x - dd.wl, w, yc + dd.h);
			s.ymx = yc + dd.h
		} else {
			yc = y_get(s.st, false, s.x - dd.wl, w)
			yc = y_get(s.st, false, s.x - dd.wl, w) - 2
			if (yc > staffb)
				yc = staffb;
			yc -= dd.h;
			y_set(s.st, false, s.x - dd.wl, w, yc)
			if (dd.name == "fermata")
				inv = true;
			s.ymn = yc
︙
646
647
648
649
650
651
652





653
654
655
656
657
658
659
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674







+
+
+
+
+







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

	if (h < 0 || wl < 0 || wr < 0) {
		error(1, null, "%%deco: cannot have a negative value '$1'", text)
		return //undefined
	}
	if (h > 50 || wl > 80 || wr > 80) {
		error(1, null, "%%deco: abnormal h/wl/wr value '$1'", text)
		return //undefined
︙
685
686
687
688
689
690
691

692
693
694
695
696
697
698
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714







+







	if (dd.func == 6 && dd.str == undefined)
		dd.str = dd.name

	// link the start and end of long decorations
	c = dd.name.slice(-1)
	if (c == '(' ||
	    (c == ')' && dd.name.indexOf('(') < 0)) {
		dd.str = null;			// (no string)
		name2 = dd.name.slice(0, -1) + (c == '(' ? ')' : '(');
		dd2 = dd_tb[name2]
		if (dd2) {
			if (c == '(') {
				dd.dd_en = dd2;
				dd2.dd_st = dd
			} else {
︙
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
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







-
+






-
+







-
+







			if (!dd)
				continue
		}

		/* special decorations */
		switch (dd.func) {
		case 0:			// near
			if (s.type == BAR && dd.name == "dot") {
			if (s.type == C.BAR && dd.name == "dot") {
				s.bar_dotted = true
				break
			}
			// fall thru
		case 1:			// slide
		case 2:			// arp
//			if (s.type != NOTE && s.type != REST) {
//			if (s.type != C.NOTE && s.type != C.REST) {
			if (!s.notes) {
				error(1, s,
					errs.must_note_rest, dd.name)
				continue
			}
			break
		case 8:			// gliss
			if (s.type != NOTE) {
			if (s.type != C.NOTE) {
				error(1, s,
					errs.must_note, dd.name)
				continue
			}
			note = s.notes[s.nhd] // move to the upper note of the chord
			if (!note.a_dcn)
				note.a_dcn = []
︙
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
860
861
862
863
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
860
861







-
+






-
+

-
-
+
+








-



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






-
+




-


-
+












-
+





-
-
-
-


-
+







				s.color = dd.name
			}
			continue
		case 32:		/* invisible */
			s.invis = true
			continue
		case 33:		/* beamon */
			if (s.type != BAR) {
			if (s.type != C.BAR) {
				error(1, s, "!beamon! must be on a bar")
				continue
			}
			s.beam_on = true
			continue
		case 34:		/* trem1..trem4 */
			if (s.type != NOTE
			if (s.type != C.NOTE
			 || !prev
			 || prev.type != NOTE
			 || s.nflags != prev.nflags) {
			 || prev.type != C.NOTE
			 || s.dur != prev.dur) {
				error(1, s,
					"!$1! must be on the last of a couple of notes",
					dd.name)
				continue
			}
			s.trem2 = true;
			s.beam_end = true;
//			s.beam_st = false;
			prev.trem2 = true;
			prev.beam_st = true;
//			prev.beam_end = false;
			s.ntrem = prev.ntrem = Number(dd.name[4]);
			prev.nflags = --s.nflags;
			prev.head = ++s.head
			if (s.nflags > 0) {
				s.nflags += s.ntrem;
			} else {
				if (s.nflags <= -2) {
					s.stemless = true;
					prev.stemless = true
				}
				s.nflags = s.ntrem;
			}
			prev.nflags = s.nflags
			for (j = 0; j <= s.nhd; j++)
				s.notes[j].dur *= 2;
			for (j = 0; j <= prev.nhd; j++)
				prev.notes[j].dur *= 2
			continue
		case 35:		/* xstem */
			if (s.type != NOTE) {
			if (s.type != C.NOTE) {
				error(1, s, "!xstem! must be on a note")
				continue
			}
			s.xstem = true;
			s.nflags = 0		// beam break
			continue
		case 36:		/* beambr1 / beambr2 */
			if (s.type != NOTE) {
			if (s.type != C.NOTE) {
				error(1, s, errs.must_note, dd.name)
				continue
			}
			if (dd.name[6] == '1')
				s.beam_br1 = true
			else
				s.beam_br2 = true
			continue
		case 37:		/* rbstop */
			s.rbstop = 1	// open
			continue
		case 38:		/* /, // and /// = tremolo */
			if (s.type != NOTE) {
			if (s.type != C.NOTE) {
				error(1, s, errs.must_note, dd.name)
				continue
			}
			s.trem1 = true;
			s.ntrem = dd.name.length	/* 1, 2 or 3 */
			if (s.nflags > 0)
				s.nflags += s.ntrem
			else
				s.nflags = s.ntrem
			continue
		case 39:		/* beam-accel/beam-rall */
			if (s.type != NOTE) {
			if (s.type != C.NOTE) {
				error(1, s, errs.must_note, dd.name)
				continue
			}
			s.feathered_beam = dd.name[5] == 'a' ? 1 : -1;
			continue
		case 40:		/* stemless */
			s.stemless = true
︙
901
902
903
904
905
906
907









908
909
910





911
912
913
914
915
916
917
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







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







			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
		}
	}
	if (wl != 0 && s.prev && s.prev.type == BAR)
			}
			break
		}
	}
	if (wl != 0 && s.prev && s.prev.type == C.BAR)
		wl -= 3
	return wl
}

/* -- draw the decorations -- */
/* (the staves are defined) */
function draw_all_deco() {
︙
1009
1010
1011
1012
1013
1014
1015
1016

1017
1018
1019
1020
1021
1022
1023
1018
1019
1020
1021
1022
1023
1024

1025
1026
1027
1028
1029
1030
1031
1032







-
+







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

		// check if user PS definition
		if (psdeco(f, x, y, de))
		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
︙
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1069
1070
1071
1072
1073
1074
1075


1076
1077
1078
1079
1080
1081
1082







-
-







	a_de = new_de
}

/* -- create the decorations and define the ones near the notes -- */
/* (the staves are not yet defined) */
/* (delayed output) */
/* this function must be called first as it builds the deco element table */
    var	ottava = {"8va(":1, "8va)":1, "15ma(":1, "15ma)":1,
		"8vb(":1, "8vb)":1, "15mb(":1, "15mb)":1}
function draw_deco_near() {
    var	s, g

	// update starting old decorations
	function ldeco_update(s) {
		var	i, de,
//			x = s.ts_prev.x + s.ts_prev.wr
︙
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
1103
1104
1105
1106
1107
1108
1109


















1110
1111
1112
1113
1114
1115
1116
1117
1118

1119
1120
1121
1122
1123
1124
1125
1126







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









-
+







			/* check if hidden */
			switch (dd.func) {
			default:
				pos = 0
				break
			case 3:				/* d_upstaff */
			case 4:
//fixme:trill does not work yet
			case 5:				/* trill */
				if (ottava[dd.name]) {	// only one ottava per staff
					x = dd.name.slice(0, -1) + s.st.toString()
					if (od[x]) {
						if (dd.name[dd.name.length - 1] == '(') {
							od[x]++
							continue
						}
						od[x]--
						if (s.v + 1 != od[x] >> 8
						 || !od[x])
							continue
						od[x] &= 0xff
					} else if (dd.name[dd.name.length - 1] == '(') {
						od[x] = 1 + ((s.v + 1) << 8)
					}
				}
				pos = s.pos.orn
				break
			case 6:				/* d_pf */
				pos = s.pos.vol
				break
			case 7:				/* d_cresc */
				pos = s.pos.dyn
				break
			}
			if (pos == SL_HIDDEN)
			if (pos == C.SL_HIDDEN)
				continue

			de = {
				s: s,
				dd: dd,
				st: s.st,
				ix: a_de.length,
︙
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
1344
1345
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
1332
1333
1334







-
-
-
+
+
+









-
-
-
-
-
+
+
+
+
+

-
+







			de2.start = de
		}
	} // ll_deco

	// update the long decorations started in the previous line
	for (s = tsfirst ; s; s = s.ts_next) {
		switch (s.type) {
		case CLEF:
		case KEY:
		case METER:
		case C.CLEF:
		case C.KEY:
		case C.METER:
			continue
		}
		break
	}
	if (a_de.length != 0)
		ldeco_update(s)

	for ( ; s; s = s.ts_next) {
		switch (s.type) {
		case BAR:
		case MREST:
		case NOTE:
		case REST:
		case SPACE:
		case C.BAR:
		case C.MREST:
		case C.NOTE:
		case C.REST:
		case C.SPACE:
			break
		case GRACE:
		case C.GRACE:
			for (g = s.extra; g; g = g.next)
				create_all(g)
		default:
			continue
		}
		create_all(s)
	}
︙
1378
1379
1380
1381
1382
1383
1384
1385

1386
1387
1388
1389
1390
1391
1392
1367
1368
1369
1370
1371
1372
1373

1374
1375
1376
1377
1378
1379
1380
1381







-
+







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

		/* search the max y offset */
		y = staff_tb[p_voice.st].topbar + 25	// 20 (vert bar) + 5 (room)
		for (s = p_voice.sym; s; s = s.next) {
			if (s.type != BAR)
			if (s.type != C.BAR)
				continue
			if (!s.rbstart || s.norepbra)
				continue
/*fixme: line cut on repeat!*/
			if (!s.next)
				break
			if (!first_repeat) {
︙
1435
1436
1437
1438
1439
1440
1441
1442

1443
1444
1445
1446
1447
1448
1449
1424
1425
1426
1427
1428
1429
1430

1431
1432
1433
1434
1435
1436
1437
1438







-
+







					break
			}
			if (s1 == s)
				break
			x = s1.x
//			if (s1.bar_type[0] == ":")
//				x -= 4;
			if (s.type != BAR) {
			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 != "[]")
				|| s.bar_type == "]") {
//				if (s.bar_type == "]")
//					s.invis = true
//fixme:%%staves: cur_sy moved?
︙
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
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







-
-
+
+










-
+







			}
			w = (s.x - x - w)	// / staff_tb[p_voice.st].staffscale;

			if (!s.next		// 2nd ending at end of line
			 && !s.rbstop
			 && !p_voice.bar_start) { // continue on next line
				p_voice.bar_start = clone(s);
				p_voice.bar_start.type = BAR;
				p_voice.bar_start.bar_type = "["
				p_voice.bar_start.type = C.BAR;
				p_voice.bar_start.bar_type = ""
				delete p_voice.bar_start.text;
				p_voice.bar_start.rbstart = 1
				delete p_voice.bar_start.a_gch
			}
			if (s1.text)
				xy_str(x + 4, y2 - gene.curfont.size - 3,
					s1.text);
			xypath(x, y2);
			if (s1.rbstart == 2)
				output += 'm0 20v-20';
			output+= 'h' + w.toFixed(2)
			output+= 'h' + w.toFixed(1)
			if (s.rbstop == 2)
				output += 'v20';
			output += '"/>\n';
			y_set(s1.st, true, x, w, y + 2)

			if (s.rbstart)
				s = s.prev
︙
1580
1581
1582
1583
1584
1585
1586
1587

1588
1589
1590
1591

1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607

1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625

1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
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
1739
1740
1741
1569
1570
1571
1572
1573
1574
1575

1576
1577
1578
1579

1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595

1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624




1625
1626
1627
1628

1629




1630

1631
1632
1633
1634
1635
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







-
+



-
+















-
+


















+









-
-
-
-
+



-
+
-
-
-
-

-






-
-
-
+
+
+


-
+


-
+





-
-
+
+


-
-










-
+





-
+



-
+








-
+
+



-
+


-
-


-
-
-
+
+
+









-
+
-


-
-

+

+
+







			bot = staff_tb[i].botbar;
			if (minmax[i].ymin > bot - 4)
				minmax[i].ymin = bot - 4
			top = staff_tb[i].topbar;
			if (minmax[i].ymax < top + 4)
				minmax[i].ymax = top + 4
		}
		set_sscale(-1)		/* restore the scale parameters */
		set_dscale(-1)		/* restore the scale parameters */
		for (s = first_gchord; s; s = s.ts_next) {
			if (!s.a_gch)
				continue
			draw_gchord(s, minmax[s.st].ymin, minmax[s.st].ymax)
			self.draw_gchord(s, minmax[s.st].ymin, minmax[s.st].ymax)
		}
	}

	/* draw the repeat brackets */
	for (v = 0; v < voice_tb.length; v++) {
		p_voice = voice_tb[v]
		if (p_voice.second || !p_voice.sym)
			continue
		draw_repbra(p_voice)
	}
}

/* -- draw the measure bar numbers -- */
/* (scaled delayed output) */
function draw_measnb() {
	var	s, st, bar_num, x, y, w, any_nb, font_size,
	var	s, st, bar_num, x, y, w, any_nb, font_size, w0,
		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)

	/* leave the measure numbers as unscaled */
	if (staff_tb[st].staffscale != 1) {
		font_size = get_font("measure").size;
		param_set_font("measurefont", "* " +
			(font_size / staff_tb[st].staffscale).toString())
	}
	set_font("measure");
	w0 = cwidf('0');			// (greatest) width of a number

	s = tsfirst;				/* clef */
	bar_num = gene.nbar
	if (bar_num > 1) {
		if (cfmt.measurenb == 0) {
			any_nb = true;
			y = y_get(st, true, 0, 20)
			if (y < staff_tb[st].topbar + 14)
				y = staff_tb[st].topbar + 14;
			if (cfmt.measurebox)
				xy_str_b(0, y, bar_num.toString())
			else
				xy_str(0, y, bar_num.toString());
			xy_str(0, y, bar_num.toString());
			y_set(st, true, 0, 20, y + gene.curfont.size + 2)
		} else if (bar_num % cfmt.measurenb == 0) {
			for ( ; ; s = s.ts_next) {
				switch (s.type) {
				if (!s.dur)
				case METER:
				case CLEF:
				case KEY:
				case STBRK:
					continue
				}
				break
			}
			while (s.st != st)
				s = s.ts_next

			// don't display the number twice
		     if (s.type != BAR || !s.bar_num) {
			if (s.prev && s.prev.type != CLEF)
				s = s.prev;
		     if (s.type != C.BAR || !s.bar_num) {
//			if (s.prev && s.prev.type != C.CLEF)
//				s = s.prev;
			x = s.x - s.wl;
			any_nb = true;
			w = cwid('0') * gene.curfont.swfac
			w = w0
			if (bar_num >= 10)
				w *= bar_num >= 100 ? 3 : 2
			if (cfmt.measurebox)
			if (gene.curfont.box)
				w += 4;
			y = y_get(st, true, x, w)
			if (y < staff_tb[st].topbar + 6)
				y = staff_tb[st].topbar + 6;
			y += 2;
			if (cfmt.measurebox) {
				xy_str_b(x, y, bar_num.toString());
			xy_str(x, y, bar_num.toString())
			if (gene.curfont.box) {
				y += 2;
				w += 3
			} else {
				xy_str(x, y, bar_num.toString())
			}
			y += gene.curfont.size;
			y_set(st, true, x, w, y);
			s.ymx = y
		     }
		}
	}

	for ( ; s; s = s.ts_next) {
		switch (s.type) {
		case STAVES:
		case C.STAVES:
			sy = s.sy
			for (st = 0; st < nstaff; st++) {
				if (sy.st_print[st])
					break
			}
			set_sscale(st)
			set_dscale(st)
			continue
		default:
			continue
		case BAR:
		case C.BAR:
			if (!s.bar_num)
				continue
			break
		}

		bar_num = s.bar_num
		if (cfmt.measurenb == 0
		 || (bar_num % cfmt.measurenb) != 0
		 || !s.next)
		 || !s.next
		 || s.bar_mrep)
			continue
		if (!any_nb)
			any_nb = true;
		w = cwid('0') * gene.curfont.swfac
		w = w0
		if (bar_num >= 10)
			w *= bar_num >= 100 ? 3 : 2
		if (cfmt.measurebox)
			w += 4;
		x = s.x - w * .4;
		y = y_get(st, true, x, w)
		if (y < staff_tb[st].topbar + 6)
			y = staff_tb[st].topbar + 6
		if (s.next.type == NOTE) {
		if (y < staff_tb[st].topbar + 3)
			y = staff_tb[st].topbar + 3
		if (s.next.type == C.NOTE) {
			if (s.next.stem > 0) {
				if (y < s.next.ys - gene.curfont.size)
					y = s.next.ys - gene.curfont.size
			} else {
				if (y < s.next.y)
					y = s.next.y
			}
		}
		y += 2;
		if (cfmt.measurebox) {
		if (gene.curfont.box) {
			xy_str_b(x, y, bar_num.toString());
			y += 2;
			w += 3
		} else {
			xy_str(x, y, bar_num.toString())
		}
		xy_str(x, y, bar_num.toString())
		y += gene.curfont.size;
		if (gene.curfont.box)
			y += 2;
		y_set(st, true, x, w, y);
		s.ymx = y
	}
	gene.nbar = bar_num

	if (font_size)
		param_set_font("measurefont", "* " + font_size.toString());
︙
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
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
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958

1959
1960
1961
1962
1963
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
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







-
+

-
+


-
+













-
+


-
-
+
+


-
+










-
+
















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





-
+



+
+
+
+

-
-
+
+




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

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
















+
-
+

-
+




+
+











-
+









-
+

















-
+

-
+




-
+









+
+




-
+










-
-
-
-
+





//	// protection against end of container
//	if (stv_g.started) {
//		output += "</g>\n";
//		stv_g.started = false
//	}

	out_XYAB('<g transform="translate(X,Y) scale(F)">\n',
		x + 4, y + 5, sc)
		x + 4, y + 4, sc)
	switch (head) {
	case OVAL:
	case C.OVAL:
		p = "HD"
		break
	case EMPTY:
	case C.EMPTY:
		p = "Hd"
		break
	default:
		p = "hd"
		break
	}
	xygl(-posx, posy, p);
	dx = 4
	if (dots) {
		dotx = 9
		if (nflags > 0)
			dotx += 4
		switch (head) {
		case SQUARE:
		case C.SQUARE:
			dotx += 3
			break
		case OVALBARS:
		case OVAL:
		case C.OVALBARS:
		case C.OVAL:
			dotx += 2
			break
		case EMPTY:
		case C.EMPTY:
			dotx += 1
			break
		}
		dx = dotx * dots;
		dotx -= posx
		while (--dots >= 0) {
			xygl(dotx, posy, "dot");
			dotx += 3.5
		}
	}
	if (dur < BASE_LEN) {
	if (dur < C.BLEN) {
		if (nflags <= 0) {
			out_stem(-posx, posy, 21)		// stem height
		} else {
			out_stem(-posx, posy, 21, false, nflags)
			if (dx < 6)
				dx = 6
		}
	}
	output += '</g>\n'
	return (dx + 15) * sc
}

/* -- estimate the tempo width -- */
function tempo_width(s) {
	var	w = 0;

	set_font("tempo")
	if (s.tempo_str1)
	if (s.tempo_wh1)
		w = strwh(s.tempo_str1)[0]
	if (s.tempo_ca)
		w = s.tempo_wh1[0]
		w += strwh(s.tempo_ca)[0]
	if (s.tempo_notes)
		w += 10 * s.tempo_notes.length +
	if (s.tempo_wh0)
		w += s.tempo_wh0[0]
			6 + cwid(' ') * gene.curfont.swfac * 6 + 10
	if (s.tempo_str2)
		w += strwh(s.tempo_str2)[0]
	if (s.tempo_wh2)
		w += s.tempo_wh2[0]
	return w
}

/* - output a tempo --*/
function write_tempo(s, x, y) {
	var	j, dx,
	var	j, dx, bx, bh,
		sc = .6 * gene.curfont.size / 15.0; //fixme: 15.0 = initial tempofont

	set_font("tempo")
	if (gene.curfont.box) {
		gene.curfont.box = false
		bx = x
	}
	if (s.tempo_str1) {
		xy_str(x, y, s.tempo_str1);
		x += strwh(s.tempo_str1)[0] + 3
		xy_str(x, y, s.tempo_str1, null, null, s.tempo_wh1);
		x += s.tempo_wh1[0] + 3
	}
	if (s.tempo_notes) {
		for (j = 0; j < s.tempo_notes.length; j++)
			x += draw_notempo(s, x, y, s.tempo_notes[j], sc);
		xy_str(x, y, "=");
		x += strwh("= ")[0]
		if (s.tempo_ca) {
			xy_str(x, y, s.tempo_ca);
		xy_str(x, y, s.tempo_str0, null, null, s.tempo_wh0);
			x += strwh(s.tempo_ca)[0]
		}
		if (s.tempo) {
		x += s.tempo_wh0[0]
			xy_str(x, y, s.tempo.toString());
			dx = cwid('0') * gene.curfont.swfac;
			x += dx + 5
			if (s.tempo >= 10) {
				x += dx
		if (s.tempo)
			x += 5
				if (s.tempo >= 100)
					x += dx
			}
		} else {
		else
			x += draw_notempo(s, x, y, s.new_beat, sc)
		}
	}
	if (s.tempo_str2)
		xy_str(x, y, s.tempo_str2)
	}
	if (s.tempo_str2)
		xy_str(x, y, s.tempo_str2, null, null, s.tempo_wh2)

	if (bx) {
		gene.curfont.box = true
		if (s.tempo_str2)
			x += s.tempo_wh2[0] + 3;
		bh = gene.curfont.size + 4;
		output += '<rect class="stroke" x="';
		out_sxsy(bx - 2, '" y="', y + bh - 1);
		output += '" width="' + (x - bx + 2).toFixed(1) +
			'" height="' + bh.toFixed(1) +
			'"/>\n'
	}

	// don't display anymore
	s.del = true
}

/* -- draw the parts and the tempo information -- */
/* (the staves are being defined) */
function draw_partempo(st, top) {
	var	s, 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)
		x = 0

	for (s = tsfirst; s; s = s.ts_next) {
		if (s.type != TEMPO || s.del)
		if (s.type != C.TEMPO || s.del)
			continue
		if (!some_tempo)
			some_tempo = s;
		w = tempo_width(s);
		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 + 2 + 2;
		ht = gene.curfont.size + 2;
		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 != TEMPO
			if (s.type != C.TEMPO
			 || s.del)		// (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)
			}
			write_tempo(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 + 8
	ymin = staff_tb[st].topbar + 6
	for (s = tsfirst; s; s = s.ts_next) {
		if (s.type != PART)
		if (s.type != C.PART)
			continue
		if (!some_part) {
			some_part = s;
			set_font("parts");
			h = gene.curfont.size + 2 + 2
			h = gene.curfont.size + 2
						/* + cfmt.partsspace ?? */
		}
		w = strwh(s.text)[0];
		y = y_get(st, true, s.x - 10, w + 3)
		if (ymin < y)
			ymin = y
	}
	if (some_part) {
		set_sscale(-1)
		if (gene.curfont.box)
			h += 2
		if (top < ymin + h + ht)
			dy = ymin + h + ht - top

		for (s = some_part; s; s = s.ts_next) {
			if (s.type != PART)
			if (s.type != C.PART)
				continue
			s.x -= 10;
			if (user.anno_start || user.anno_stop) {
				w = strwh(s.text)[0];
				s.wl = 0;
				s.wr = w;
				s.ymn = -ht - h;
				s.ymx = s.ymn + h;
				anno_start(s)
			}
			if (cfmt.partsbox)
				xy_str_b(s.x, 2 - ht - h, s.text)
			else
				xy_str(s.x, 2 - ht - h, s.text)
			xy_str(s.x, 2 - ht - h, s.text);
			anno_stop(s)
		}
	}
	return dy
}
Changes to core/draw.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - draw.js - draw functions
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-2019 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.
︙
89
90
91
92
93
94
95

96
97

98
99
100
101
102
103
104
89
90
91
92
93
94
95
96
97

98
99
100
101
102
103
104
105







+

-
+







var min_tb = [
	[STEM_MIN, STEM_MIN,
		STEM_MIN2, STEM_MIN3, STEM_MIN4, STEM_MIN4],
	[STEM_CH_MIN, STEM_CH_MIN,
		STEM_CH_MIN2, STEM_CH_MIN3, STEM_CH_MIN4, STEM_CH_MIN4]
]

// (possible hook)
function calculate_beam(bm, s1) {
	var	s, s2, notes, nflags, st, v, two_staves, two_dir,
    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);
︙
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
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







-
+















-
+







	/* search last note in beam */
	notes = nflags = 0;	/* set x positions, count notes and flags */
	two_staves = two_dir = false;
	st = s1.st;
	v = s1.v;
	stem_xoff = s1.grace ? GSTEM_XOFF : 3.5
	for (s2 = s1;  ;s2 = s2.next) {
		if (s2.type == NOTE) {
		if (s2.type == C.NOTE) {
			if (s2.nflags > nflags)
				nflags = s2.nflags;
			notes++
			if (s2.st != st)
				two_staves = true
			if (s2.stem != s1.stem)
				two_dir = true
			if (!visible && !s2.invis
			 && (!s2.stemless || s2.trem2))
				visible = true
			if (s2.beam_end)
				break
		}
		if (!s2.next) {		/* beam towards next music line */
			for (; ; s2 = s2.prev) {
				if (s2.type == NOTE)
				if (s2.type == C.NOTE)
					break
			}
			s = sym_dup(s2);
			s.next = s2.next
			if (s.next)
				s.next.prev = s;
			s2.next = s;
︙
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
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







-
+










-
+







	if (staff_tb[st].y == 0) {	/* staves not defined */
		if (two_staves)
			return false
	} else {			/* staves defined */
//		if (!two_staves && !s1.grace) {
		if (!two_staves) {
			bm.s1 = s1;	/* beam already calculated */
			bm.a = (s1.ys- s2.ys) / (s1.xs - s2.xs);
			bm.a = (s1.ys - s2.ys) / (s1.xs - s2.xs);
			bm.b = s1.ys - s1.xs * bm.a + staff_tb[st].y;
			bm.nflags = nflags
			return true
		}
	}

	s_closest = s1;
	p_min = 100;
	p_max = 0
	for (s = s1; ; s = s.next) {
		if (s.type != NOTE)
		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;
︙
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
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







+
-
+










-
+

-
-
+




-
+





-
+







	if (a != 0) {
		if (a > 0)
			a = BEAM_SLOPE * a / (BEAM_SLOPE + a) // max steepness for beam
		else
			a = BEAM_SLOPE * a / (BEAM_SLOPE - a);
	}

	// pivot around the middle of the beam
	b = y - a * s1.xs;
	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.stem != s2.stem && s1.nflags < s2.nflags)
			ys *= s2.stem
			b += ys * s2.stem
		else
			ys *= s1.stem;
		b += ys
			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 == NOTE
		    && s.ts_prev.type == C.NOTE
		    && s.ts_prev.time == s.time
		    && s.ts_prev.x > s1.xs)
			s = s.ts_prev

		for (; s && s.time <= s2.time; s = s.ts_next) {
			if (s.type != NOTE
			if (s.type != C.NOTE
			 || s.invis
			 || (s.st != st
			  && s.v != v)) {
				continue
			}
			x = s.v == v ? s.xs : s.x;
			ys = a * x + b - staff_tb[s.st].y
︙
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
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







-

-
+


-
+




-
+



-
+















-
+







	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) {
		var g
		switch (s.type) {
		case REST:		/* cannot move rests in multi-voices */
		case C.REST:		/* cannot move rests in multi-voices */
			g = s.ts_next
			if (!g || g.st != st
			 || (g.type != NOTE && g.type != REST))
			 || (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 BAR:
		case C.BAR:
			if (s.invis)
				break
			/*fall thru*/
		case CLEF:
		case C.CLEF:
			y = a * s.x + b
			if (s1.stem > 0) {
				y = s.ymx - y
					+ BEAM_DEPTH + BEAM_SHIFT * (nflags - 1)
					+ 2
				if (y > 0)
					b += y
			} else {
				y = s.ymn - y
					- BEAM_DEPTH - BEAM_SHIFT * (nflags - 1)
					- 2
				if (y < 0)
					b += y
			}
			break
		case GRACE:
		case C.GRACE:
			for (g = s.extra; g; g = g.next) {
				y = a * g.x + b
				if (s1.stem > 0) {
					y = g.ymx - y
						+ BEAM_DEPTH + BEAM_SHIFT * (nflags - 1)
						+ 2
					if (y > 0)
︙
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
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







-
+

















-
+


-
+













-
+








	if (a == 0)		/* shift flat beams onto staff lines */
		b += b_pos(s1.grace, s1.stem, nflags, b - staff_tb[st].y)

	/* adjust final stems and rests under beam */
	for (s = s1; ; s = s.next) {
		switch (s.type) {
		case NOTE:
		case C.NOTE:
			s.ys = a * s.xs + b - staff_tb[s.st].y
			if (s.stem > 0) {
				s.ymx = s.ys + 2.5
//fixme: hack
				if (s.ts_prev
				 && s.ts_prev.stem > 0
				 && s.ts_prev.st == s.st
				 && s.ts_prev.ymn < s.ymx
				 && s.ts_prev.x == s.x
				 && s.notes[0].shhd == 0) {
					s.ts_prev.x -= 3;	/* fix stem clash */
					s.ts_prev.xs -= 3
				}
			} else {
				s.ymn = s.ys - 2.5
			}
			break
		case REST:
		case C.REST:
			y = a * s.x + b - staff_tb[s.st].y
			dy = BEAM_DEPTH + BEAM_SHIFT * (nflags - 1)
				+ (s.head != FULL ? 4 : 9)
				+ (s.head != C.FULL ? 4 : 9)
			if (s1.stem > 0) {
				y -= dy
				if (s1.multi == 0 && y > 12)
					y = 12
				if (s.y <= y)
					break
			} else {
				y += dy
				if (s1.multi == 0 && y < 12)
					y = 12
				if (s.y >= y)
					break
			}
			if (s.head != FULL)
			if (s.head != C.FULL)
				y = (((y + 3 + 12) / 6) | 0) * 6 - 12;
			s.y = y
			break
		}
		if (s == s2)
			break
	}
︙
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
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







-
+


-
+











-
-
-
+
+
+







		var	y1, dy2,
			s = bm.s1,
			nflags = s.nflags

		if (s.ntrem)
			nflags -= s.ntrem
		if (s.trem2 && n > nflags) {
			if (s.dur >= BASE_LEN / 2) {
			if (s.dur >= C.BLEN / 2) {
				x1 = s.x + 6;
				x2 = bm.s2.x - 6
			} else if (s.dur < BASE_LEN / 4) {
			} else if (s.dur < C.BLEN / 4) {
				x1 += 5;
				x2 -= 6
			}
		}

		y1 = bm.a * x1 + bm.b - dy;
		x2 -= x1;
	//--fixme: scale (bm.a already scaled!)
		x2 /= stv_g.scale;
		dy2 = bm.a * x2 * stv_g.scale;
		xypath(x1, y1, true);
		output += 'l' + x2.toFixed(2) + ' ' + (-dy2).toFixed(2) +
			'v' + h.toFixed(2) +
			'l' + (-x2).toFixed(2) + ' ' + dy2.toFixed(2) +
		output += 'l' + x2.toFixed(1) + ' ' + (-dy2).toFixed(1) +
			'v' + h.toFixed(1) +
			'l' + (-x2).toFixed(1) + ' ' + dy2.toFixed(1) +
			'z"/>\n'
	} // draw_beam()

	anno_start(s1, 'beam')
/*fixme: KO if many staves with different scales*/
//	set_scale(s1)
	if (!s1.grace) {
︙
515
516
517
518
519
520
521
522

523
524
525
526
527
528
529
515
516
517
518
519
520
521

522
523
524
525
526
527
528
529







-
+







	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
	for (s = s1; ; s = s.next) {
		if (s.type == NOTE
		if (s.type == C.NOTE
		 && s.stem != beam_dir)
			s.ys = bm.a * s.xs + bm.b
				- staff_tb[s.st].y
				+ bshift * (s.nflags - 1) * s.stem
				- bh
		if (s == s2)
			break
︙
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
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







-
+







-
+












-
+













-
+













-
+






-
+







	/* other beams with two or more flags */
	shift = 0
	for (i = 2; i <= bm.nflags; i++) {
		shift += bshift
		if (da != 0)
			bm.a += da
		for (s = s1; ; s = s.next) {
			if (s.type != NOTE
			if (s.type != C.NOTE
			 || s.nflags < i) {
				if (s == s2)
					break
				continue
			}
			if (s.trem1
			 && i > s.nflags - s.ntrem) {
				x1 = (s.dur >= BASE_LEN / 2) ? s.x : s.xs;
				x1 = (s.dur >= C.BLEN / 2) ? s.x : s.xs;
				draw_beam(x1 - 5, x1 + 5,
					  (shift + 2.5) * beam_dir,
					  bh, bm, i)
				if (s == s2)
					break
				continue
			}
			k1 = s
			while (1) {
				if (s == s2)
					break
				k = s.next
				if (k.type == NOTE || k.type == REST) {
				if (k.type == C.NOTE || k.type == C.REST) {
					if (k.trem1){
						if (k.nflags - k.ntrem < i)
							break
					} else if (k.nflags < i) {
						break
					}
				}
				if (k.beam_br1
				 || (k.beam_br2 && i > 2))
					break
				s = k
			}
			k2 = s
			while (k2.type != NOTE)
			while (k2.type != C.NOTE)
				k2 = k2.prev;
			x1 = k1.xs
			if (k1 == k2) {
				if (k1 == s1) {
					x1 += bstub
				} else if (k1 == s2) {
					x1 -= bstub
				} else if (k1.beam_br1
				        || (k1.beam_br2
					 && i > 2)) {
					x1 += bstub
				} else {
					k = k1.next
					while (k.type != NOTE)
					while (k.type != C.NOTE)
						k = k.next
					if (k.beam_br1
					 || (k.beam_br2 && i > 2)) {
						x1 -= bstub
					} else {
						k1 = k1.prev
						while (k1.type != NOTE)
						while (k1.type != C.NOTE)
							k1 = k1.prev
						if (k1.nflags < k.nflags
						 || (k1.nflags == k.nflags
						  && k1.dots < k.dots))
							x1 += bstub
						else
							x1 -= bstub
︙
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
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







-
+
















-
+









-
-
+
-



-
+
-
-
-
-
-
+


-
+

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

-
+
-
-
+
-
-
-







			break
	}
	if (i == j && l == 0)
		return
	yb = staff_tb[j].y + staff_tb[j].botbar * staff_tb[j].staffscale;
	h = staff_tb[i].y + staff_tb[i].topbar * staff_tb[i].staffscale - yb;
	xypath(x, yb);
	output += "v" + (-h).toFixed(2) + '"/>\n'
	output += "v" + (-h).toFixed(1) + '"/>\n'
	for (i = 0; i <= nst; i++) {
		if (cur_sy.staves[i].flags & OPEN_BRACE)
			draw_sysbra(x, i, CLOSE_BRACE)
		if (cur_sy.staves[i].flags & OPEN_BRACKET)
			draw_sysbra(x, i, CLOSE_BRACKET)
		if (cur_sy.staves[i].flags & OPEN_BRACE2)
			draw_sysbra(x - 6, i, CLOSE_BRACE2)
		if (cur_sy.staves[i].flags & OPEN_BRACKET2)
			draw_sysbra(x - 6, i, CLOSE_BRACKET2)
	}
}

/* -- draw the time signature -- */
function draw_meter(x, s) {
	if (!s.a_meter)
		return
	var	dx, i, j, tmp1, tmp2,
    var	dx, i, j, meter,
		st = s.st,
		p_staff = staff_tb[st],
		y = p_staff.y;

	// adjust the vertical offset according to the staff definition
	if (p_staff.stafflines != '|||||')
		y += (p_staff.topbar + p_staff.botbar) / 2 - 12	// bottom

	for (i = 0; i < s.a_meter.length; i++) {
		var	f,
			meter = s.a_meter[i]
		meter = s.a_meter[i];

		x = s.x + s.x_meter[i]

		if (meter.bot) {
			tmp1 = tmp2 = ''
			out_XYAB('\
			for (j = 0; j < meter.top.length; j++)
				tmp1 += tgls["meter" + meter.top[j]].c
			for (j = 0; j < meter.bot.length; j++)
				tmp2 += tgls["meter" + meter.bot[j]].c;
			out_XYAB('<g transform="translate(X,Y)" text-anchor="middle">\n\
<g transform="translate(X,Y)" text-anchor="middle">\n\
	<text y="-12">A</text>\n\
	<text>B</text>\n\
</g>\n', x, y + 6, tmp1, tmp2)
</g>\n', x, y + 6, m_gl(meter.top), m_gl(meter.bot))
		} else {
			switch (meter.top[0]) {
			case 'C':
				f = meter.top[1] != '|' ? "csig" : "ctsig";
				x -= 5;
				y += 12
				break
			case 'c':
				f = meter.top[1] != '.' ? "imsig" : "iMsig"
				break
			case 'o':
				f = meter.top[1] != '.' ? "pmsig" : "pMsig"
				break
			default:
				tmp1 = ''
				for (j = 0; j < meter.top.length; j++)
					tmp1 += tgls["meter" + meter.top[j]].c;
				out_XYAB('\
			out_XYAB('\
<text x="X" y="Y" text-anchor="middle">A</text>\n',
					x, y + 12, tmp1)
				x, y + 12, m_gl(meter.top))
				break
			}
		}
		}
		if (f)
			xygl(x, y, f)
	}
}

/* -- draw an accidental -- */
function draw_acc(x, y, acc,
			micro_n,
			micro_d) {
︙
810
811
812
813
814
815
816
817

818
819
820
821

822
823
824
825
826
827
828
784
785
786
787
788
789
790

791
792
793
794

795
796
797
798
799
800
801
802







-
+



-
+







var	sharp_cl = new Int8Array([24, 9, 15, 21, 6, 12, 18]),
	flat_cl = new Int8Array([12, 18, 24, 9, 15, 21, 6]),
	sharp1 = new Int8Array([-9, 12, -9, -9, 12, -9]),
	sharp2 = new Int8Array([12, -9, 12, -9, 12, -9]),
	flat1 = new Int8Array([9, -12, 9, -12, 9, -12]),
	flat2 = new Int8Array([-12, 9, -12, 9, -12, 9])

function draw_keysig(p_voice, x, s) {
function draw_keysig(x, s) {
	if (s.k_none)
		return
	var	old_sf = s.k_old_sf,
		st = p_voice.st,
		st = s.st,
		staffb = staff_tb[st].y,
		i, shift, p_seq,
		clef_ix = s.k_y_clef

	if (clef_ix & 1)
		clef_ix += 7;
	clef_ix /= 2
︙
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
1019
1020
1021
1022
1023
1024

1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
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







-
-




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








-
+


-
-
-
-
-







		return "[" + bar_type		/* |::: -> [|::: */
	case ":|":
	case "::|":
	case ":::|":
		return bar_type + "]"		/* :..| -> :..|] */
	case "::":
		return cfmt.dblrepbar		/* :: -> double repeat bar */
	case '||:':
		return '[|:'
	}
	return bar_type
}

/* -- draw a measure bar -- */
function draw_bar(s, bot, h) {
	var	i, s2, yb, bar_type,
		st = s.st,
		x = s.x

	bar_type = bar_cnv(s.bar_type)
	if (!bar_type)
		return				/* invisible */

	/* don't put a line between the staves if there is no bar above */
	if (st != 0
	 && s.ts_prev
//fixme: 's.ts_prev.st != st - 1' when floating voice in lower staff
//	 && (s.ts_prev.type != BAR || s.ts_prev.st != st - 1))
	 && s.ts_prev.type != BAR)
		h = staff_tb[st].topbar * staff_tb[st].staffscale;

	s.ymx = s.ymn + h;
	set_sscale(-1);
	anno_start(s)

	/* if measure repeat, draw the '%' like glyphs */
	if (s.bar_mrep) {
		yb = staff_tb[st].y + 12;
		set_sscale(st)
		if (s.bar_mrep == 1) {
			for (s2 = s.prev; s2.type != REST; s2 = s2.prev)
				;
			xygl(s2.x, yb, "mrep")
		} else {
			xygl(x, yb, "mrep2")
			if (s.v == cur_sy.top_voice) {
				set_font("annotation");
				xy_str(x, yb + staff_tb[st].topbar - 9,
						s.bar_mrep.toString(), "c")
			}
		}
	}

	for (i = bar_type.length; --i >= 0; ) {
		switch (bar_type[i]) {
		case "|":
			set_sscale(-1);
			out_bar(x, bot, h, s.bar_dotted)
			break
		default:
//		case "[":
//		case "]":
			x -= 3;
			set_sscale(-1);
			out_thbar(x, bot, h)
			break
		case ":":
			x -= 2;
			set_sscale(st);
			xygl(x + 1, bot, "rdots")
			break
		}
		x -= 3
	}
	set_sscale(-1);
	anno_stop(s)
}

/* -- draw a rest -- */
/* (the staves are defined) */
var rest_tb = [
	"r128", "r64", "r32", "r16", "r8",
	"r4",
	"r2", "r1", "r0", "r00"]

function draw_rest(s) {
	var	s2, i, j, x, y, dotx, staffb, yb, yt, head,
	var	s2, i, j, x, y, dotx, yb, yt, head, bx,
		p_staff = staff_tb[s.st]

	/* don't display the rests of invisible staves */
	/* (must do this here for voices out of their normal staff) */
	if (!p_staff.topbar)
		return

	/* if rest alone in the measure or measure repeat, center */
	if (s.dur == s.p_v.meter.wmeasure
	 || (s.rep_nb && s.rep_nb >= 0)) {

		/* don't use next/prev: there is no bar in voice overlay */
		s2 = s.ts_next
		while (s2 && s2.time != s.time + s.dur)
︙
1052
1053
1054
1055
1056
1057
1058
1059

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
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
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
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
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057

1058
1059
1060
1061
1062
1063
1064
1065







-
+




+
-
+
+
+

-
+

-
+


+
+
+
+
-
+

+
+

















-
+











-
+


















-
+



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















-
+







		x = s.x
		if (s.notes[0].shhd)
			x += s.notes[0].shhd * stv_g.scale
	}
	if (s.invis)
		return

	staffb = p_staff.y			/* bottom of staff */
	yb = p_staff.y			// bottom of staff

	if (s.rep_nb) {
		set_sscale(s.st);
		anno_start(s);
		if (p_staff.stafflines == '|||||')
		staffb += 12
			yb += 12
		else
			yb += (p_staff.topbar + p_staff.botbar) / 2
		if (s.rep_nb < 0) {
			xygl(x, staffb, "srep")
			xygl(x, yb, "srep")
		} else {
			xygl(x, staffb, "mrep")
			xygl(x, yb, "mrep")
			if (s.rep_nb > 2 && s.v == cur_sy.top_voice) {
				set_font("annotation");
				if (gene.curfont.box) {
					gene.curfont.box = false;
					bx = true
				}	
				xy_str(x, staffb + p_staff.topbar - 9,
				xy_str(x, yb + p_staff.topbar - 9,
					s.rep_nb.toString(), "c")
				if (bx)
					gene.curfont.box = true
			}
		}
		anno_stop(s)
		return
	}

	set_scale(s);
	anno_start(s);

	y = s.y;

	i = 5 - s.nflags		/* rest_tb index (5 = C_XFLAGS) */
	if (i == 7 && y == 12
	 && p_staff.stafflines.length <= 2)
		y -= 6				/* semibreve a bit lower */

	// draw the rest
	xygl(x, y + staffb, s.notes[0].head ? s.notes[0].head : rest_tb[i])
	xygl(x, y + yb, s.notes[0].head ? s.notes[0].head : rest_tb[i])

	/* output ledger line(s) when greater than minim */
	if (i >= 6) {
		j = y / 6
		switch (i) {
		default:
			switch (p_staff.stafflines[j + 1]) {
			case '|':
			case '[':
				break
			default:
				xygl(x, y + 6 + staffb, "hl1")
				xygl(x, y + 6 + yb, "hl1")
				break
			}
			if (i == 9) {			/* longa */
				y -= 6;
				j--
			}
			break
		case 7:					/* semibreve */
			y += 6;
			j++
		case 6:					/* minim */
			break
		}
		switch (p_staff.stafflines[j]) {
		case '|':
		case '[':
			break
		default:
			xygl(x, y + staffb, "hl1")
			xygl(x, y + yb, "hl1")
			break
		}
	}
	if (s.dots) {
	x += 8;
	y += staffb + 3
	for (i = 0; i < s.dots; i++) {
		xygl(x, y, "dot");
		x += 3.5
		x += 8;
		y += yb + 3
		for (i = 0; i < s.dots; i++) {
			xygl(x, y, "dot");
			x += 3.5
		}
	}
	anno_stop(s)
}

/* -- draw grace notes -- */
/* (the staves are defined) */
function draw_gracenotes(s) {
	var	yy, x0, y0, x1, y1, x2, y2, x3, y3, bet1, bet2,
		dy1, dy2, g, last, note,
		bm = {}

	/* draw the notes */
//	bm.s2 = undefined			/* (draw flags) */
	for (g = s.extra; g; g = g.next) {
		if (g.beam_st && !g.beam_end) {
			if (calculate_beam(bm, g))
			if (self.calculate_beam(bm, g))
				draw_beams(bm)
		}
		anno_start(g);
		draw_note(g, !bm.s2)
		if (g == bm.s2)
			bm.s2 = null			/* (draw flags again) */
		anno_stop(g)
︙
1175
1176
1177
1178
1179
1180
1181
1182

1183
1184
1185
1186
1187
1188
1189
1088
1089
1090
1091
1092
1093
1094

1095
1096
1097
1098
1099
1100
1101
1102







-
+








	/* slur */
//fixme: have a full key symbol in voice
	if (s.p_v.key.k_bagpipe			/* no slur when bagpipe */
	 || !cfmt.graceslurs
	 || s.slur_start			/* explicit slur */
	 || !s.next
	 || s.next.type != NOTE)
	 || s.next.type != C.NOTE)
		return
	last = g
	if (last.stem >= 0) {
		yy = 127
		for (g = s.extra; g; g = g.next) {
			if (g.y < yy) {
				yy = g.y;
︙
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272



1273
1274
1275
1276
1277
1278
1279
1176
1177
1178
1179
1180
1181
1182



1183
1184
1185
1186
1187
1188
1189
1190
1191
1192







-
-
-
+
+
+







	x1 = bet1 * x3 + (1 - bet1) * x0 - x0;
	y1 = bet1 * y3 + (1 - bet1) * y0 - dy1 - y0;
	x2 = bet2 * x3 + (1 - bet2) * x0 - x0;
	y2 = bet2 * y3 + (1 - bet2) * y0 - dy2 - y0;

	anno_start(s, 'slur');
	xypath(x0, y0 + staff_tb[s.st].y);
	output += 'c' + x1.toFixed(2) + ' ' + (-y1).toFixed(2) +
		' ' + x2.toFixed(2) + ' ' + (-y2).toFixed(2) +
		' ' + (x3 - x0).toFixed(2) + ' ' + (-y3 + y0).toFixed(2) + '"/>\n';
	output += 'c' + x1.toFixed(1) + ' ' + (-y1).toFixed(1) +
		' ' + x2.toFixed(1) + ' ' + (-y2).toFixed(1) +
		' ' + (x3 - x0).toFixed(1) + ' ' + (-y3 + y0).toFixed(1) + '"/>\n';
	anno_stop(s, 'slur')
}

/* -- set the y offset of the dots -- */
function setdoty(s, y_tb) {
	var m, m1, y

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







-
+









-
+







		}
	}
}

// get the x and y position of a note head
// (when the staves are defined)
function x_head(s, note) {
	return s.x + note.shhd
	return s.x + note.shhd * stv_g.scale
}
function y_head(s, note) {
	return staff_tb[s.st].y + 3 * (note.pit - 18)
}

/* -- draw m-th head with accidentals and dots -- */
/* (the staves are defined) */
// sets {x,y}_note
function draw_basic_note(x, s, m, y_tb) {
	var	i, k, p, yy, dotx, doty,
	var	i, k, p, yy, dotx, doty, inv,
		old_color = false,
		note = s.notes[m],
		staffb = staff_tb[s.st].y,	/* bottom of staff */
		y = 3 * (note.pit - 18),	/* note height on staff */
		shhd = note.shhd * stv_g.scale,
		x_note = x + shhd,
		y_note = y + staffb
︙
1372
1373
1374
1375
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
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
1332
1333
1334

1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345







-
+



-
+


-
-
+
+




-
-
+
+
+
+
+
+
+



-
+


-
+







-
+




+
+
+
+
-
+

+
+







		i = p.indexOf('/')
		if (i >= 0) {			// stem dependant
			if (s.stem >= 0)
				p = p.slice(0, i)
			else
				p = p.slice(i + 1)
		}
	} else if (s.type == CUSTOS) {
	} else if (s.type == C.CUSTOS) {
		p = "custos"
	} else {
		switch (head) {
		case OVAL:
		case C.OVAL:
			p = "HD"
			break
		case OVALBARS:
			if (s.head != SQUARE) {
		case C.OVALBARS:
			if (s.head != C.SQUARE) {
				p = "HDD"
				break
			}
			// fall thru
		case SQUARE:
			p = note.dur < BASE_LEN * 4 ? "breve" : "longa"
		case C.SQUARE:
			if (nflags > -4) {
				p = "breve"
			} else {
				p =  "longa"
				inv = s.stem > 0
			}

			/* don't display dots on last note of the tune */
			if (!tsnext && s.next
			 && s.next.type == BAR && !s.next.next)
			 && s.next.type == C.BAR && !s.next.next)
				dots = 0
			break
		case EMPTY:
		case C.EMPTY:
			p = "Hd"		// white note
			break
		default:			// black note
			p = "hd"
			break
		}
	}
	if (note.color)
	if (note.color != undefined)
		old_color = set_color(note.color)
	else if (note.map && note.map[2])
		old_color = set_color(note.map[2])
	if (p) {
		if (inv) {
			g_open(x_note, y_note, 0, 1, -1);
			x_note = y_note = 0
		}
		if (!psxygl(x_note, y_note, p))
		if (!self.psxygl(x_note, y_note, p))
			xygl(x_note, y_note, p)
		if (inv)
			g_close()
	}

	/* draw the dots */
/*fixme: to see for grace notes*/
	if (dots) {
		dotx = x + (7.7 + s.xmx) * stv_g.scale
		if (y_tb[m] == undefined) {
︙
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
1371
1372
1373
1374
1375
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







-
+






-
+






-
-
-
-
-
-
+
+
+
+
+


-
-
+
+
+



-
+







}

/* -- draw a note or a chord -- */
/* (the staves are defined) */
function draw_note(s,
		   fl) {		// draw flags
	var	s2, i, m, y, staffb, slen, c, hltype, nflags,
		x, y, note,
		x, y, note, x_hl,
		y_tb = new Array(s.nhd + 1)

	if (s.dots)
		setdoty(s, y_tb)

	note = s.notes[s.stem < 0 ? s.nhd : 0];	// master note head
	x = x_head(s, note);
	x_hl = x = x_head(s, note);
	staffb = staff_tb[s.st].y

	/* output the ledger lines */
	if (s.grace) {
		hltype = "ghl"
	} else {
		switch (s.head) {
		default:
			hltype = "hl"
			break
		case OVAL:
		case OVALBARS:
		hltype = "hl"
		switch (s.head) {
		case C.OVALBARS:
		case C.OVAL:
			x_hl = x - .3;
			hltype = "hl1"
			break
		case SQUARE:
			hltype = "hl2"
		case C.SQUARE:
			x_hl = x - 2;
			hltype = "hl1"
			break
		}
	}
	draw_hl(x, 3 * (s.notes[0].pit - 18), 3 * (s.notes[s.nhd].pit - 18),
	draw_hl(x_hl, 3 * (s.notes[0].pit - 18), 3 * (s.notes[s.nhd].pit - 18),
		s.st, hltype)

	/* draw the stem and flags */
	y = y_head(s, note)
	if (!s.stemless) {
		slen = s.ys - s.y;
		nflags = s.nflags
︙
1510
1511
1512
1513
1514
1515
1516
1517

1518
1519
1520
1521
1522
1523
1524
1434
1435
1436
1437
1438
1439
1440

1441
1442
1443
1444
1445
1446
1447
1448







-
+







	}

	/* draw the tremolo bars */
	if (fl && s.trem1) {
		var	ntrem = s.ntrem || 0,
			x1 = x;
		slen = 3 * (s.notes[s.stem > 0 ? s.nhd : 0].pit - 18)
		if (s.head == FULL || s.head == EMPTY) {
		if (s.head == C.FULL || s.head == C.EMPTY) {
			x1 += (s.grace ? GSTEM_XOFF : 3.5) * s.stem
			if (s.stem > 0)
				slen += 6 + 5.4 * ntrem
			else
				slen -= 6 + 5.4
		} else {
			if (s.stem > 0)
︙
1554
1555
1556
1557
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
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







-
+

-
+

-
+












-
+







		s = s.prev
		if (s.rbstart)
			return s
	}

	/* return a symbol of any voice starting before the start of the voice */
	s = s.p_v.sym
	while (s.type != CLEF)
	while (s.type != C.CLEF)
		s = s.ts_prev		/* search a main voice */
	if (s.next && s.next.type == KEY)
	if (s.next && s.next.type == C.KEY)
		s = s.next
	if (s.next && s.next.type == METER)
	if (s.next && s.next.type == C.METER)
		return s.next
	return s
}

/* -- decide whether a slur goes up or down -- */
function slur_direction(k1, k2) {
	var s, some_upstem, low

	if (k1.grace && k1.stem > 0)
		return -1

	for (s = k1; ; s = s.next) {
		if (s.type == NOTE) {
		if (s.type == C.NOTE) {
			if (!s.stemless) {
				if (s.stem < 0)
					return 1
				some_upstem = true
			}
			if (s.notes[0].pit < 22)	/* if under middle staff */
				low = true
︙
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
1570
1571
1572
1573
1574
1575
1576






1577
1578
1579
1580
1581
1582
1583
1584
1585







1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599







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



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







	var scale_y = stv_g.v ? stv_g.scale : 1
	if (!dotted)
		output += '<path class="fill" d="M'
	else
		output += '<path class="stroke" stroke-dasharray="5,5" d="M';
	out_sxsy(x1, ' ', y1);
	output += 'c' +
		((xx1 - x1) / stv_g.scale).toFixed(2) + ' ' +
		((y1 - yy1) / scale_y).toFixed(2) + ' ' +
		((xx2 - x1) / stv_g.scale).toFixed(2) + ' ' +
		((y1 - yy2) / scale_y).toFixed(2) + ' ' +
		((x2 - x1) / stv_g.scale).toFixed(2) + ' ' +
		((y1 - y2) / scale_y).toFixed(2)
		((xx1 - x1) / stv_g.scale).toFixed(1) + ' ' +
		((y1 - yy1) / scale_y).toFixed(1) + ' ' +
		((xx2 - x1) / stv_g.scale).toFixed(1) + ' ' +
		((y1 - yy2) / scale_y).toFixed(1) + ' ' +
		((x2 - x1) / stv_g.scale).toFixed(1) + ' ' +
		((y1 - y2) / scale_y).toFixed(1)

	if (!dotted)
		output += '\n\tv' +
			(-dz).toFixed(2) + 'c' +
			((xx2 - dx - x2) / stv_g.scale).toFixed(2) + ' ' +
			((y2 + dz - yy2 - dy) / scale_y).toFixed(2) + ' ' +
			((xx1 + dx - x2) / stv_g.scale).toFixed(2) + ' ' +
			((y2 + dz - yy1 - dy) / scale_y).toFixed(2) + ' ' +
			((x1 - x2) / stv_g.scale).toFixed(2) + ' ' +
			((y2 + dz - y1) / scale_y).toFixed(2);
			(-dz).toFixed(1) + 'c' +
			((xx2 - dx - x2) / stv_g.scale).toFixed(1) + ' ' +
			((y2 + dz - yy2 - dy) / scale_y).toFixed(1) + ' ' +
			((xx1 + dx - x2) / stv_g.scale).toFixed(1) + ' ' +
			((y2 + dz - yy1 - dy) / scale_y).toFixed(1) + ' ' +
			((x1 - x2) / stv_g.scale).toFixed(1) + ' ' +
			((y2 + dz - y1) / scale_y).toFixed(1);
	output += '"/>\n'
}

/* -- check if slur sequence in a multi-voice staff -- */
function slur_multi(k1, k2) {
	while (1) {
		if (k1.multi)		/* if multi voice */
︙
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
1615
1616
1617
1618
1619
1620
1621


1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638

1639
1640
1641
1642
1643
1644
1645
1646







-
-
+
+











+



-
+







		k, g, x1, y1, x2, y2, height, addy,
		a, y, z, h, dx, dy, dir

	while (k1.v != k2.v)
		k1 = k1.ts_next
/*fixme: if two staves, may have upper or lower slur*/
	switch (slur_type & 0x07) {	/* (ignore dotted flag) */
	case SL_ABOVE: dir = 1; break
	case SL_BELOW: dir = -1; break
	case C.SL_ABOVE: dir = 1; break
	case C.SL_BELOW: dir = -1; break
	default:
		dir = slur_multi(k1, k2)
		if (!dir)
			dir = slur_direction(k1, k2)
		break
	}

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

	set_dscale(k1.st)
	if (k1 != k2) {
		k = k1.next
		while (1) {
			if (k.type == NOTE || k.type == REST) {
			if (k.type == C.NOTE || k.type == C.REST) {
				nn++
				if (k.st != upstaff) {
					two_staves = true
					if (k.st < upstaff)
						upstaff = k.st
				}
			}
︙
1734
1735
1736
1737
1738
1739
1740
1741

1742
1743
1744
1745
1746
1747
1748
1749
1750

1751
1752
1753
1754
1755
1756
1757
1659
1660
1661
1662
1663
1664
1665

1666
1667
1668
1669
1670
1671
1672
1673
1674

1675
1676
1677
1678
1679
1680
1681
1682







-
+








-
+







	if (k1_o != k2) {
		x2 = k2.x
		if (k2.notes)
			x2 += k2.notes[0].shhd
	} else {		/* (the slur starts on last note of the line) */
		for (k = k2.ts_next; k; k = k.ts_next)
//fixme: must check if the staff continues
			if (k.type == STAVES)
			if (k.type == C.STAVES)
				break
		x2 = k ? k.x : realwidth
	}

	if (m1 >= 0) {
		y1 = 3 * (k1.notes[m1].pit - 18) + 5 * dir
	} else {
		y1 = dir > 0 ? k1.ymx + 2 : k1.ymn - 2
		if (k1.type == NOTE) {
		if (k1.type == C.NOTE) {
			if (dir > 0) {
				if (k1.stem > 0) {
					x1 += 5
					if (k1.beam_end
					 && k1.nflags >= -1	/* if with a stem */
//fixme: check if at end of tuplet
					 && !k1.in_tuplet) {
︙
1793
1794
1795
1796
1797
1798
1799
1800

1801
1802
1803
1804
1805
1806
1807
1718
1719
1720
1721
1722
1723
1724

1725
1726
1727
1728
1729
1730
1731
1732







-
+







			}
		}
	}
	if (m2 >= 0) {
		y2 = 3 * (k2.notes[m2].pit - 18) + 5 * dir
	} else {
		y2 = dir > 0 ? k2.ymx + 2 : k2.ymn - 2
		if (k2.type == NOTE) {
		if (k2.type == C.NOTE) {
			if (dir > 0) {
				if (k2.stem > 0) {
					x2 += 1
					if (k2.beam_st
					 && k2.nflags >= -1
					 && !k2.in_tuplet)
//						|| k2.ys > y2 - 3))
︙
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
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







-
+






-
-
+
+








-
+












-
+







//				} else {
//					y2 = k2.y - 8
				}
			}
		}
	}

	if (k1.type != NOTE) {
	if (k1.type != C.NOTE) {
		y1 = y2 + 1.2 * dir;
		x1 = k1.x + k1.wr * .5
		if (x1 > x2 - 12)
			x1 = x2 - 12
	}

	if (k2.type != NOTE) {
		if (k1.type == NOTE)
	if (k2.type != C.NOTE) {
		if (k1.type == C.NOTE)
			y2 = y1 + 1.2 * dir
		else
			y2 = y1
		if (k1 != k2)
			x2 = k2.x - k2.wl * .3
	}

	if (nn >= 3) {
		if (k1.next.type != BAR
		if (k1.next.type != C.BAR
		 && k1.next.x < x1 + 48) {
			if (dir > 0) {
				y = k1.next.ymx - 2
				if (y1 < y)
					y1 = y
			} else {
				y = k1.next.ymn + 2
				if (y1 > y)
					y1 = y
			}
		}
		if (k2.prev
		 && k2.prev.type != BAR
		 && k2.prev.type != C.BAR
		 && k2.prev.x > x2 - 48) {
			if (dir > 0) {
				y = k2.prev.ymx - 2
				if (y2 < y)
					y2 = y
			} else {
				y = k2.prev.ymn + 2
︙
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
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







-
-
+
+
















-
+







	if (k1 != k2
	 && k1.v == k2.v) {
	    addy = y1 - a * x1
	    for (k = k1.next; k != k2 ; k = k.next) {
		if (k.st != upstaff)
			continue
		switch (k.type) {
		case NOTE:
		case REST:
		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;
				y -= a * k.x + addy
				if (y > h)
					h = y
			} else {
				y = 3 * (k.notes[0].pit - 18) - 6
				if (y > k.ymn)
					y = k.ymn;
				y -= a * k.x + addy
				if (y < h)
					h = y
			}
			break
		case GRACE:
		case C.GRACE:
			for (g = k.extra; g; g = g.next) {
				if (dir > 0) {
					y = 3 * (g.notes[g.nhd].pit - 18) + 6
					if (y < g.ymx)
						y = g.ymx;
					y -= a * g.x + addy
					if (y > h)
︙
1984
1985
1986
1987
1988
1989
1990
1991

1992
1993
1994
1995
1996
1997
1998
1909
1910
1911
1912
1913
1914
1915

1916
1917
1918
1919
1920
1921
1922
1923







-
+







	} else {
		if (height > -.8 * y)
			height = -.8 * y
	}
	height *= cfmt.slurheight;

//	anno_start(k1_o, 'slur');
	slur_out(x1, y1, x2, y2, dir, height, slur_type & SL_DOTTED);
	slur_out(x1, y1, x2, y2, dir, height, slur_type & C.SL_DOTTED);
//	anno_stop(k1_o, 'slur');

	/* have room for other symbols */
	dx = x2 - x1;
	a = (y2 - y1) / dx;
/*fixme: it seems to work with .4, but why?*/
	addy = y1 - a * x1 + .4 * height
︙
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
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







-
+















-
+




-
-
+
+




















-
+




-
+







-
-
+
+














-
+







			dx = k.next.x
		}
		if (k != k1)
			x1 = k.x;
		dx -= x1;
		y_set(upstaff, dir > 0, x1, dx, y)
	}
	return (dir > 0 ? SL_ABOVE : SL_BELOW) | (slur_type & SL_DOTTED)
	return (dir > 0 ? C.SL_ABOVE : C.SL_BELOW) | (slur_type & C.SL_DOTTED)
}

/* -- draw the slurs between 2 symbols --*/
function draw_slurs(first, last) {
	var	s1, k, gr1, gr2, i, m1, m2, slur_type, cont,
		s = first

	while (1) {
		if (!s || s == last) {
			if (!gr1
			 || !(s = gr1.next)
			 || s == last)
				break
			gr1 = null
		}
		if (s.type == GRACE) {
		if (s.type == C.GRACE) {
			gr1 = s;
			s = s.extra
			continue
		}
		if ((s.type != NOTE && s.type != REST
		  && s.type != SPACE)
		if ((s.type != C.NOTE && s.type != C.REST
		  && s.type != C.SPACE)
		 || (!s.slur_start && !s.sl1)) {
			s = s.next
			continue
		}
		k = null;		/* find matching slur end */
		s1 = s.next
		var gr1_out = false
		while (1) {
			if (!s1) {
				if (gr2) {
					s1 = gr2.next;
					gr2 = null
					continue
				}
				if (!gr1 || gr1_out)
					break
				s1 = gr1.next;
				gr1_out = true
				continue
			}
			if (s1.type == GRACE) {
			if (s1.type == C.GRACE) {
				gr2 = s1;
				s1 = s1.extra
				continue
			}
			if (s1.type == BAR
			if (s1.type == C.BAR
			 && (s1.bar_type[0] == ':'
			  || s1.bar_type == "|]"
			  || s1.bar_type == "[|"
			  || (s1.text && s1.text[0] != '1'))) {
				k = s1
				break
			}
			if (s1.type != NOTE && s1.type != REST
			 && s1.type != SPACE) {
			if (s1.type != C.NOTE && s1.type != C.REST
			 && s1.type != C.SPACE) {
				s1 = s1.next
				continue
			}
			if (s1.slur_end || s1.sl2) {
				k = s1
				break
			}
			if (s1.slur_start || s1.sl1) {
				if (gr2) {	/* if in grace note sequence */
					for (k = s1; k.next; k = k.next)
						;
					k.next = gr2.next
					if (gr2.next)
						gr2.next.prev = k;
//					gr2.slur_start = SL_AUTO
//					gr2.slur_start = C.SL_AUTO
					k = null
				}
				draw_slurs(s1, last)
				if (gr2
				 && gr2.next) {
					gr2.next.prev.next = null;
					gr2.next.prev = gr2
︙
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
2155

2156
2157
2158
2159
2160
2161
2162
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







-
+




-
+















-
+











-
+







		/* if slur in grace note sequence, change the linkages */
		if (gr1) {
			for (s1 = s; s1.next; s1 = s1.next)
				;
			s1.next = gr1.next
			if (gr1.next)
				gr1.next.prev = s1;
			gr1.slur_start = SL_AUTO
			gr1.slur_start = C.SL_AUTO
		}
		if (gr2) {
			gr2.prev.next = gr2.extra;
			gr2.extra.prev = gr2.prev;
			gr2.slur_start = SL_AUTO
			gr2.slur_start = C.SL_AUTO
		}
		if (s.slur_start) {
			slur_type = s.slur_start & 0x0f;
			s.slur_start >>= 4;
			m1 = -1
		} else {
			for (m1 = 0; m1 <= s.nhd; m1++)
				if (s.notes[m1].sl1)
					break
			slur_type = s.notes[m1].sl1 & 0x0f;
			s.notes[m1].sl1 >>= 4;
			s.sl1--
		}
		m2 = -1;
		cont = 0
		if ((k.type == NOTE || k.type == REST || k.type == SPACE) &&
		if ((k.type == C.NOTE || k.type == C.REST || k.type == C.SPACE) &&
		    (k.slur_end || k.sl2)) {
			if (k.slur_end) {
				k.slur_end--
			} else {
				for (m2 = 0; m2 <= k.nhd; m2++)
					if (k.notes[m2].sl2)
						break
				k.notes[m2].sl2--;
				k.sl2--
			}
		} else {
			if (k.type != BAR
			if (k.type != C.BAR
			 || (k.bar_type[0] != ':'
			  && k.bar_type != "|]"
			  && k.bar_type != "[|"
			  && (!k.text || k.text[0] == '1')))
				cont = 1
		}
		slur_type = draw_slur(s, k, m1, m2, slur_type)
︙
2195
2196
2197
2198
2199
2200
2201

2202
2203
2204


2205
2206
2207
2208
2209
2210
2211
2120
2121
2122
2123
2124
2125
2126
2127
2128


2129
2130
2131
2132
2133
2134
2135
2136
2137







+

-
-
+
+







			lvl) {	// nesting level
	var	s2, s3, g, upstaff, nb_only, some_slur,
		x1, x2, y1, y2, xm, ym, a, s0, yy, yx, dy, a, b, dir,
		p, q, r

	// check if some slurs and treat the nested tuplets
	upstaff = s1.st
	set_dscale(s1.st)
	for (s2 = s1; s2; s2 = s2.next) {
		if (s2.type != NOTE && s2.type != REST) {
			if (s2.type == GRACE) {
		if (s2.type != C.NOTE && s2.type != C.REST) {
			if (s2.type == C.GRACE) {
				for (g = s2.extra; g; g = g.next) {
					if (g.slur_start || g.sl1)
						some_slur = true
				}
			}
			continue
		}
︙
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
2310
2311
2312
2313
2314


2315
2316
2317
2318
2319
2320
2321
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
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







-
+

-
+










-
+




-
-
-
-
+
+
+
+
















-
-
+
+








-
-
+
+







		s1.tp1 = 0
		q = s1.tq1
	}

	if (s1.tf[0] == 1)			/* if 'when' == never */
		return

	dir = s1.tf[3]				/* 'where' (SL_xxx) */
	dir = s1.tf[3]				/* 'where' (C.SL_xxx) */
	if (!dir)
		dir = s1.stem > 0 ? SL_ABOVE : SL_BELOW
		dir = s1.stem > 0 ? C.SL_ABOVE : C.SL_BELOW

	if (s1 == s2) {				/* tuplet with 1 note (!) */
		nb_only = true
	} else if (s1.tf[1] == 1) {			/* 'what' == slur */
		nb_only = true;
		draw_slur(s1, s2, -1, -1, dir)
	} else {

		/* search if a bracket is needed */
		if (s1.tf[0] == 2		/* if 'when' == always */
		 || s1.type != NOTE || s2.type != NOTE) {
		 || s1.type != C.NOTE || s2.type != C.NOTE) {
			nb_only = false
		} else {
			nb_only = true
			for (s3 = s1; ; s3 = s3.next) {
				if (s3.type != NOTE
				 && s3.type != REST) {
					if (s3.type == GRACE
					 || s3.type == SPACE)
				if (s3.type != C.NOTE
				 && s3.type != C.REST) {
					if (s3.type == C.GRACE
					 || s3.type == C.SPACE)
						continue
					nb_only = false
					break
				}
				if (s3 == s2)
					break
				if (s3.beam_end) {
					nb_only = false
					break
				}
			}
			if (nb_only
			 && !s1.beam_st
			 && !s1.beam_br1
			 && !s1.beam_br2) {
				for (s3 = s1.prev; s3; s3 = s3.prev) {
					if (s3.type == NOTE
					 || s3.type == REST) {
					if (s3.type == C.NOTE
					 || s3.type == C.REST) {
						if (s3.nflags >= s1.nflags)
							nb_only = false
						break
					}
				}
			}
			if (nb_only && !s2.beam_end) {
				for (s3 = s2.next; s3; s3 = s3.next) {
					if (s3.type == NOTE
					 || s3.type == REST) {
					if (s3.type == C.NOTE
					 || s3.type == C.REST) {
						if (!s3.beam_br1
						 && !s3.beam_br2
						 && s3.nflags >= s2.nflags)
							nb_only = false
						break
					}
				}
︙
2330
2331
2332
2333
2334
2335
2336
2337

2338
2339
2340
2341
2342
2343
2344
2256
2257
2258
2259
2260
2261
2262

2263
2264
2265
2266
2267
2268
2269
2270







-
+







		xm = (s2.x + s1.x) / 2
		if (s1 == s2)			/* tuplet with 1 note */
			a = 0
		else
			a = (s2.ys - s1.ys) / (s2.x - s1.x);
		b = s1.ys - a * s1.x;
		yy = a * xm + b
		if (dir == SL_ABOVE) {
		if (dir == C.SL_ABOVE) {
			ym = y_get(upstaff, 1, xm - 4, 8)
			if (ym > yy)
				b += ym - yy;
			b += 2
		} else {
			ym = y_get(upstaff, 0, xm - 4, 8)
			if (ym < yy)
︙
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
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







-
+



















-
-
+
+







				xm -= 1.5
		}
		ym = a * xm + b
		if (s1.tf[2] == 0)		/* if 'which' == number */
			out_bnum(xm, ym, p)
		else
			out_bnum(xm, ym, p + ':' +  q)
		if (dir == SL_ABOVE) {
		if (dir == C.SL_ABOVE) {
			ym += 10
			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
	}

	if (s1.tf[1] != 0)				/* if 'what' != square */
		error(2, s1, "'what' value of %%tuplets not yet coded")

/*fixme: two staves not treated*/
/*fixme: to optimize*/
	dir = s1.tf[3]				// 'where'
	if (!dir)
		dir = s1.multi >= 0 ? SL_ABOVE : SL_BELOW
    if (dir == SL_ABOVE) {
		dir = s1.multi >= 0 ? C.SL_ABOVE : C.SL_BELOW
    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 + 4
	} else {
		y1 = s1.ymx;
		y2 = s2.ymx
︙
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
2593
2594
2595
2596

2597
2598
2599
2600
2601
2602
2603
2493
2494
2495
2496
2497
2498
2499

2500
2501
2502

2503
2504
2505
2506

2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521

2522
2523
2524
2525
2526
2527
2528
2529







-
+


-
+



-
+














-
+







		}
		if (s3 == s2)
			break
	}
    } /* lower voice */

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

	yy = .5 * (y1 + y2)
	if (dir == SL_ABOVE)
	if (dir == C.SL_ABOVE)
		y_set(upstaff, true, xm - 3, 6, yy + 9)
	else
		y_set(upstaff, false, xm - 3, 6, yy)
}

/* -- draw the ties between two notes/chords -- */
function draw_note_ties(k1, k2, mhead1, mhead2, job) {
	var i, dir, m1, m2, p, p2, y, st, k, x1, x2, h, sh, time

	for (i = 0; i < mhead1.length; i++) {
		m1 = mhead1[i];
		p = k1.notes[m1].pit;
		m2 = mhead2[i];
		p2 = job != 2 ? k2.notes[m2].pit : p;
		dir = (k1.notes[m1].ti1 & 0x07) == SL_ABOVE ? 1 : -1;
		dir = (k1.notes[m1].ti1 & 0x07) == C.SL_ABOVE ? 1 : -1;

		x1 = k1.x;
		sh = k1.notes[m1].shhd		/* head shift */
		if (dir > 0) {
			if (m1 < k1.nhd && p + 1 == k1.notes[m1 + 1].pit)
				if (k1.notes[m1 + 1].shhd > sh)
					sh = k1.notes[m1 + 1].shhd
︙
2639
2640
2641
2642
2643
2644
2645
2646

2647
2648
2649
2650
2651
2652
2653
2565
2566
2567
2568
2569
2570
2571

2572
2573
2574
2575
2576
2577
2578
2579







-
+







			p = p2;
			st = k2.st
			break
/*		case 2:				 * no ending note */
		default:
			if (k1 != k2) {
				x2 -= k2.wl
				if (k2.type == BAR)
				if (k2.type == C.BAR)
					x2 += 5
			} else {
				time = k1.time + k1.dur
				for (k = k1.ts_next; k; k = k.ts_next)
//(fixme: must check if the staff continues??)
					if (k.time > time)
						break
︙
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
2588
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







-
-
-
-
-
-
-
-
-





-
+










-
+







			x2 -= 3.5
		} else {
			x1 += 1.5;
			x2 -= 1.5
		}

		y = 3 * (p - 18)
//fixme: clash when 2 ties on second interval chord
//		if (p & 1)
//			y += 2 * dir
		if (job != 1 && job != 3) {
			if (dir > 0) {
				if (!(p & 1) && k1.dots)
					y = 3 * (p - 18) + 6
			}
		}

		h = (.04 * (x2 - x1) + 10) * dir;
//		anno_start(k1, 'slur');
		slur_out(x1, staff_tb[st].y + y,
			 x2, staff_tb[st].y + y,
			 dir, h, k1.notes[m1].ti1 & SL_DOTTED)
			 dir, h, k1.notes[m1].ti1 & C.SL_DOTTED)
//		anno_stop(k1, 'slur')
	}
}

/* -- draw ties between neighboring notes/chords -- */
function draw_ties(k1, k2,
			job) {	// 0: normal
				// 1: no starting note
				// 2: no ending note
				// 3: no start for clef or staff change
	var	k3, i, j, m1, pit, tie2,
	var	k3, i, j, m1, pit, pit2, tie2,
		mhead1 = [],
		mhead2 = [],
		mhead3 = [],
		nh1 = k1.nhd,
		time = k1.time + k1.dur

	/* half ties from last note in line or before new repeat */
︙
2709
2710
2711
2712
2713
2714
2715
2716

2717
2718


2719
2720
2721
2722
2723
2724
2725
2626
2627
2628
2629
2630
2631
2632

2633
2634

2635
2636
2637
2638
2639
2640
2641
2642
2643







-
+

-
+
+







	}

	/* set up list of ties to draw */
	for (i = 0; i <= nh1; i++) {
		if (!k1.notes[i].ti1)
			continue
		tie2 = -1;
		pit = k1.notes[i].apit
		pit = k1.notes[i].opit || k1.notes[i].pit
		for (m1 = k2.nhd; m1 >= 0; m1--) {
			switch (k2.notes[m1].apit - pit) {
			pit2 = k2.notes[m1].opit || k2.notes[m1].pit
			switch (pit2 - pit) {
			case 1:			/* maybe ^c - _d */
			case -1:		/* _d - ^c */
				if (k1.notes[i].acc != k2.notes[m1].acc)
					tie2 = m1
			default:
				continue
			case 0:
︙
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
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







-
+








-
+

+
-
+







	if (!mhead3.length)
		return				/* no bad tie */

	k3 = k1.ts_next
	while (k3 && k3.time < time)
		k3 = k3.ts_next
	while (k3 && k3.time == time) {
		if (k3.type != NOTE
		if (k3.type != C.NOTE
		 || k3.st != k1.st) {
			k3 = k3.ts_next
			continue
		}
		mhead1.length = 0;
		mhead2.length = 0
		for (i = mhead3.length; --i >= 0; ) {
			j = mhead3[i];
			pit = k1.notes[j].apit
			pit = k1.notes[j].opit || k1.notes[j].pit
			for (m1 = k3.nhd; m1 >= 0; m1--) {
				pit2 = k3.notes[m1].opit || k3.notes[m1].pit
				if (k3.notes[m1].apit == pit) {
				if (pit2 == pit) {
					mhead1.push(j);
					mhead2.push(m1);
					mhead3[i] = mhead3.pop()
					break
				}
			}
		}
︙
2786
2787
2788
2789
2790
2791
2792
2793

2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810

2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824



2825
2826
2827
2828
2829
2830
2831
2832

2833
2834

2835
2836
2837
2838
2839
2840
2841
2705
2706
2707
2708
2709
2710
2711

2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728

2729
2730
2731
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







-
+
















-
+











-
-
-
+
+
+







-
+

-
+








	time = s.time + s.dur;
	st = s.st
	for (s1 = s.ts_next; s1; s1 = s1.ts_next) {
		if (s1.st != st)
			continue
		if (s1.time == time) {
			if (s1.type == NOTE)
			if (s1.type == C.NOTE)
				return s1
			continue
		}
		if (s1.time > time)
			return s		// bad tie
	}
	return //null				// no ending tie
}

/* -- draw all ties between neighboring notes -- */
function draw_all_ties(p_voice) {
	var s1, s2, s3, clef_chg, time, s_rtie, s_tie, x, dx

	function draw_ties_g(s1, s2, job) {
		var g

		if (s1.type == GRACE) {
		if (s1.type == C.GRACE) {
			for (g = s1.extra; g; g = g.next) {
				if (g.ti1)
					draw_ties(g, s2, job)
			}
		} else {
			draw_ties(s1, s2, job)
		}
	} // draw_ties_g()

	for (s1 = p_voice.sym; s1; s1 = s1.next) {
		switch (s1.type) {
		case CLEF:
		case KEY:
		case METER:
		case C.CLEF:
		case C.KEY:
		case C.METER:
			continue
		}
		break
	}
	s_rtie = p_voice.s_rtie			/* tie from 1st repeat bar */
	for (s2 = s1; s2; s2 = s2.next) {
		if (s2.dur
		 || s2.type == GRACE)
		 || s2.type == C.GRACE)
			break
		if (s2.type != BAR
		if (s2.type != C.BAR
		 || !s2.text)			// not a repeat bar
			continue
		if (s2.text[0] == '1')		/* 1st repeat bar */
			s_rtie = p_voice.s_tie
		else
			p_voice.s_tie = s_rtie
	}
︙
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
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







-
+









-
+







//	clef_chg = false
	while (1) {
		for (s1 = s2; s1; s1 = s1.next) {
			if (s1.ti1)
				break
			if (!s_rtie)
				continue
			if (s1.type != BAR
			if (s1.type != C.BAR
			 || !s1.text)			// not a repeat bar
				continue
			if (s1.text[0] == '1') {	/* 1st repeat bar */
				s_rtie = null
				continue
			}
			if (s1.bar_type == '|')
				continue		// not a repeat
			for (s2 = s1.next; s2; s2 = s2.next)
				if (s2.type == NOTE)
				if (s2.type == C.NOTE)
					break
			if (!s2) {
				s1 = null
				break
			}
			s_tie = clone(s_rtie);
			s_tie.x = s1.x;
︙
2887
2888
2889
2890
2891
2892
2893
2894

2895
2896
2897
2898
2899
2900
2901
2806
2807
2808
2809
2810
2811
2812

2813
2814
2815
2816
2817
2818
2819
2820







-
+








		/* search the end of the tie
		 * and notice the clef changes (may occur in an other voice) */
		time = s1.time + s1.dur
		for (s2 = s1.next; s2; s2 = s2.next) {
			if (s2.dur)
				break
			if (s2.text) {			// repeat bar
			if (s2.type == C.BAR && s2.text) {	// repeat bar
				if (s2.text[0] != '1')
					break
				s_rtie = s1		/* 1st repeat bar */
			}
		}
		if (!s2) {
			for (s2 = s1.ts_next; s2; s2 = s2.ts_next) {
︙
2912
2913
2914
2915
2916
2917
2918
2919
2920


2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938

2939
2940
2941
2942
2943
2944
2945
2831
2832
2833
2834
2835
2836
2837


2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856

2857
2858
2859
2860
2861
2862
2863
2864







-
-
+
+

















-
+







			}
			if (!s2) {
				draw_ties_g(s1, null, 2);
				p_voice.s_tie = s1
				break
			}
		} else {
			if (s2.type != NOTE
			 && s2.type != BAR) {
			if (s2.type != C.NOTE
			 && s2.type != C.BAR) {
				error(1, s1, "Bad tie")
				continue
			}
			if (s2.time != time) {
				s3 = tie_comb(s1)
				if (s3 == s1) {
					error(1, s1, "Bad tie")
					continue
				}
				s2 = s3
			}
		}
		for (s3 = s1.ts_next; s3; s3 = s3.ts_next) {
			if (s3.st != s1.st)
				continue
			if (s3.time > time)
				break
			if (s3.type == CLEF) {
			if (s3.type == C.CLEF) {
				clef_chg = true
				continue
			}
		}

		/* ties with clef or staff change */
		if (clef_chg || s1.st != s2.st) {
︙
2955
2956
2957
2958
2959
2960
2961
2962

2963
2964
2965
2966
2967
2968
2969
2874
2875
2876
2877
2878
2879
2880

2881
2882
2883
2884
2885
2886
2887
2888







-
+







			s1.x += dx
			if (s1.x < s2.x - 24.)
				s1.x = s2.x - 24.;
			draw_ties(s1, s2, 3);
			s1.x = x
			continue
		}
		draw_ties_g(s1, s2, s2.type == NOTE ? 0 : 2)
		draw_ties_g(s1, s2, s2.type == C.NOTE ? 0 : 2)
	}
	p_voice.s_rtie = s_rtie
}

/* -- draw all phrasing slurs for one staff -- */
/* (the staves are not yet defined) */
function draw_all_slurs(p_voice) {
︙
3000
3001
3002
3003
3004
3005
3006
3007

3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021

3022
3023
3024
3025
3026
3027
3028
2919
2920
2921
2922
2923
2924
2925

2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939

2940
2941
2942
2943
2944
2945
2946
2947







-
+













-
+







						break
				s.notes[m2].sl2--;
				s.sl2--
			}
			slur_type = slur_st & 0x0f;
			k = prev_scut(s);
			draw_slur(k, s, -1, m2, slur_type)
			if (k.type != BAR
			if (k.type != C.BAR
			 || (k.bar_type[0] != ':'
			  && k.bar_type != "|]"
			  && k.bar_type != "[|"
			  && (!k.text || k.text[0] == '1')))
				slur_st >>= 4
		}
	}
	s = p_voice.sym
	while (slur_st != 0) {
		slur_type = slur_st & 0x0f;
		slur_st >>= 4;
		k = next_scut(s);
		draw_slur(s, k, -1, -1, slur_type)
		if (k.type != BAR
		if (k.type != C.BAR
		 || (k.bar_type[0] != ':'
		  && k.bar_type != "|]"
		  && k.bar_type != "[|"
		  && (!k.text || k.text[0] == '1'))) {
			if (!p_voice.slur_start)
				p_voice.slur_start = 0;
			p_voice.slur_start <<= 4;
︙
3038
3039
3040
3041
3042
3043
3044
3045

3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065

3066
3067
3068

3069
3070
3071

3072
3073
3074
3075

3076
3077
3078
3079
3080
3081
3082
2957
2958
2959
2960
2961
2962
2963

2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983

2984
2985
2986

2987
2988
2989

2990
2991
2992
2993

2994
2995
2996
2997
2998
2999
3000
3001







-
+



















-
+


-
+


-
+



-
+







 *   - beams
 *   - decorations near the notes
 *   - measure bar numbers
 *   - n-plets
 *   - decorations tied to the notes
 *   - slurs
 * - not scaled
 *   - guitar chords
 *   - chord symbols
 *   - staff decorations
 *   - lyrics
 *   - measure numbers
 * 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, output_sav;

	output_sav = output;
	output = ""

	/* calculate the beams but don't draw them (the staves are not yet defined) */
	for (v = 0; v < voice_tb.length; v++) {
		var	bm = {},
			first_note = true;

		p_voice = voice_tb[v]
		for (s = p_voice.sym; s; s = s.next) {
			switch (s.type) {
			case GRACE:
			case C.GRACE:
				for (g = s.extra; g; g = g.next) {
					if (g.beam_st && !g.beam_end)
						calculate_beam(bm, g)
						self.calculate_beam(bm, g)
				}
				break
			case NOTE:
			case C.NOTE:
				if ((s.beam_st && !s.beam_end)
				 || (first_note && !s.beam_st)) {
					first_note = false;
					calculate_beam(bm, s)
					self.calculate_beam(bm, s)
				}
				break
			}
		}
	}

	/* initialize the min/max vertical offsets */
︙
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
3017
3018
3019
3020
3021
3022
3023

3024
3025
3026
3027
3028
3029

3030
3031
3032
3033
3034
3035
3036

3037
3038
3039
3040
3041
3042
3043
3044
3045

3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059

3060
3061
3062
3063
3064
3065
3066
3067







-
+





-
+






-
+





+
+
+
-
+










+
+
+
-
+







	draw_deco_near()

	/* set the min/max vertical offsets */
	for (s = tsfirst; s; s = s.ts_next) {
		if (s.invis)
			continue
		switch (s.type) {
		case GRACE:
		case C.GRACE:
			for (g = s.extra; g; g = g.next) {
				y_set(s.st, true, g.x - 2, 4, g.ymx + 1);
				y_set(s.st, false, g.x - 2, 4, g.ymn - 1)
			}
			continue
		case MREST:
		case C.MREST:
			y_set(s.st, true, s.x + 16, 32, s.ymx + 2)
			continue
		default:
			y_set(s.st, true, s.x - s.wl, s.wl + s.wr, s.ymx + 2);
			y_set(s.st, false, s.x - s.wl, s.wl + s.wr, s.ymn - 2)
			continue
		case NOTE:
		case C.NOTE:
			break
		}

		// (permit closer staves)
		if (s.stem > 0) {
			if (s.stemless) {
				dx = -5;
				w = 10
			if (s.beam_st) {
			} else if (s.beam_st) {
				dx = 3;
				w = s.beam_end ? 4 : 10
			} else {
				dx = -8;
				w = s.beam_end ? 11 : 16
			}
			y_set(s.st, true, s.x + dx, w, s.ymx);
			y_set(s.st, false, s.x - s.wl, s.wl + s.wr, s.ymn)
		} else {
			y_set(s.st, true, s.x - s.wl, s.wl + s.wr, s.ymx);
			if (s.stemless) {
				dx = -5;
				w = 10
			if (s.beam_st) {
			} else if (s.beam_st) {
				dx = -6;
				w = s.beam_end ? 4 : 10
			} else {
				dx = -8;
				w = s.beam_end ? 5 : 16
			}
			dx += s.notes[0].shhd;
︙
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3095
3096
3097
3098
3099
3100
3101

3102
3103
3104
3105
3106
3107
3108







-







			continue
		set_color(s.color);
		st = p_voice.st;
//  if (st == undefined) {
//error(1, s, "BUG: no staff for voice " + p_voice.id)
//    continue
//  }
		set_dscale(st)

		/* draw the tuplets near the notes */
		for ( ; s; s = s.next) {
			if (s.tp0)
				draw_tuplet(s, 0)
		}
		draw_all_slurs(p_voice)
︙
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
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







-
+

+
+













-
-
-







			if (top > p_st.top[i])
				p_st.top[i] = top
			if (bot < p_st.bot[i])
				p_st.bot[i] = bot
		}
	}

	set_color(undefined);
	set_color();
	draw_deco_note()
	if (cfmt.measurenb >= 0)
		draw_measnb();
	draw_deco_staff();

	/* if any lyric, draw them now as unscaled */
	set_dscale(-1)
//	set_sscale(-1)
	for (v = 0; v < voice_tb.length; v++) {
		p_voice = voice_tb[v]
		if (p_voice.have_ly) {
			draw_all_lyrics()
			break
		}
	}

	if (cfmt.measurenb >= 0)
		draw_measnb();

	set_dscale(-1);
	output = output_sav
}

/* -- draw the name/subname of the voices -- */
function draw_vname(indent) {
	var	p_voice, n, st, v, a_p, p, y, name_type,
︙
3410
3411
3412
3413
3414
3415
3416
3417

3418
3419
3420
3421
3422
3423
3424
3333
3334
3335
3336
3337
3338
3339

3340
3341
3342
3343
3344
3345
3346
3347







-
+







	/* output the staff offsets */
	for (st = 0; st <= nstaff; st++) {
		p_staff = staff_tb[st];
		dy = p_staff.y
		if (p_staff.staffscale != 1) {
			p_staff.scale_str =
				'transform="translate(0,' +
					(posy - dy).toFixed(2) + ') ' +
					(posy - dy).toFixed(1) + ') ' +
				'scale(' + p_staff.staffscale.toFixed(2) + ')"'
		}
	}

	if (mbot == 0) {
		for (st = nstaff; st >= 0; st--) {
			if (gene.st_print[st])
︙
3437
3438
3439
3440
3441
3442
3443
3444

3445
3446
3447
3448






3449
3450
3451
3452
3453
3454
3455
3360
3361
3362
3363
3364
3365
3366

3367
3368
3369
3370

3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383







-
+



-
+
+
+
+
+
+








	// return the height of the whole staff system
	return y + dy
}

/* -- draw the staff systems and the measure bars -- */
function draw_systems(indent) {
	var	s, s2, st, x, x2, res,
	var	s, s2, st, x, x2, res, sy,
		staves_bar, bar_force,
		xstaff = [],
		bar_bot = [],
		bar_height = []
		bar_height = [],
		sb = [],
		db = [],
		thb = [],
		gl = [],
		rn = []

	/* -- set the bottom and height of the measure bars -- */
	function bar_set() {
		var	st, staffscale, top, bot,
			dy = 0

		for (st = 0; st <= cur_sy.nstaff; st++) {
︙
3470
3471
3472
3473
3474
3475
3476
3477

3478
3479
3480
3481
3482
3483
3484
3398
3399
3400
3401
3402
3403
3404

3405
3406
3407
3408
3409
3410
3411
3412







-
+







	} // bar_set()

	/* -- draw a staff -- */
	function draw_staff(st, x1, x2) {
		var	w, ws, i, dy, ty,
			y = 0,
			ln = "",
			stafflines = staff_tb[st].stafflines,
			stafflines = cur_sy.staves[st].stafflines,
			l = stafflines.length

		if (!/[\[|]/.test(stafflines))
			return				// no line
		w = x2 - x1;
		set_sscale(st);
		ws = w / stv_g.scale
︙
3494
3495
3496
3497
3498
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
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551



3552
3553
3554
3555
3556
3557
3558
3559




3560
3561
3562
3563
3564
3565
3566

3567

3568
3569
3570
3571
3572
3573



3574
3575
3576



3577
3578
3579
3580
3581
3582
3583
3584
3585


3586

3587
3588
3589

3590
3591

3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605

3606
3607
3608
3609

3610
3611

3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622

3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634

3635
3636
3637
3638
3639
3640
3641
3422
3423
3424
3425
3426
3427
3428

3429
3430

3431
3432
3433
3434
3435
3436
3437


3438
3439


3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
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
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608


3609
3610
3611
3612
3613
3614
3615




3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627

3628
3629
3630
3631



3632
3633
3634
3635
3636

3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
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







-
+

-
+






-
-
+
+
-
-
+



















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

















-
-
+
+
+




-
-
-
-
+
+
+
+







+
-
+



-
-
-
+
+
+


-
+
+
+









+
+

+


-
+
-
-
+

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

-
+










-
+











-
+







			dy = 0
			for (; i < l; i++, y -= 6, dy -= 6) {
				switch (stafflines[i]) {
				case '.':
				case '-':
					continue
				case ty:
					ln += 'm-' + ws.toFixed(2) +
					ln += 'm-' + ws.toFixed(1) +
						' ' + dy +
						'h' + ws.toFixed(2);
						'h' + ws.toFixed(1);
					dy = 0
					continue
				}
				if (ty != undefined)
					ln += '"/>\n';
				ty = stafflines[i]
				ln += '<path class="stroke"'
				if (ty == '[')
				ln += '<path class="stroke ' +
					(ty == '[' ? 'slthW' : 'slW') +
					ln += ' stroke-width="1.5"';
				ln += ' d="m0 ' + y + 'h' + ws.toFixed(2);
					'" d="m0 ' + y + 'h' + ws.toFixed(1);
				dy = 0
			}
			ln += '"/>\n'
		}
		y = staff_tb[st].y
		if (!cache
		 && w == get_lwidth()) {
			cache = {
				st_l: stafflines,
				st_ws: ws
			}
			i = 'stdef' + cfmt.fullsvg;
			glyphs[i] = '<g id="' + i + '">\n' + ln + '</g>';
			xygl(x1, y, i)
			return
		}
		out_XYAB('<g transform="translate(X, Y)">\n' + ln + '</g>\n', x1, y)
	} // draw_staff()

	// draw a measure bar
	function draw_bar(s, bot, h) {
	    var	i, s2, yb,
		bar_type = s.bar_type,
		st = s.st,
		p_staff = staff_tb[st],
		x = s.x

		// don't put a line between the staves if there is no bar above
		if (st != 0
		 && s.ts_prev
//fixme: 's.ts_prev.st != st - 1' when floating voice in lower staff
//	 && (s.ts_prev.type != C.BAR || s.ts_prev.st != st - 1))
		 && s.ts_prev.type != C.BAR)
			h = p_staff.topbar * p_staff.staffscale;

		s.ymx = s.ymn + h;
		set_sscale(-1);
		anno_start(s)

		// compute the middle vertical offset of the staff
		yb = p_staff.y + 12;
		if (p_staff.stafflines != '|||||')
			yb += (p_staff.topbar + p_staff.botbar) / 2 - 12 // bottom

		// if measure repeat, draw the '%' like glyphs
		if (s.bar_mrep) {
			set_sscale(st)
			if (s.bar_mrep == 1) {
				for (s2 = s.prev; s2.type != C.REST; s2 = s2.prev)
					;
				gl.push([s2.x, yb, st, "mrep"])
			} else {
				gl.push([x, yb, st, "mrep2"])
				if (s.v == cur_sy.top_voice)
					rn.push([x, yb + p_staff.topbar - 9,
						st, s.bar_mrep.toString()])
			}
		}

		if (bar_type == '||:')
			bar_type = '[|:'

		for (i = bar_type.length; --i >= 0; ) {
			switch (bar_type[i]) {
			case "|":
				if (s.bar_dotted)
					db.push(new Float32Array([x, bot, h,
						p_staff.staffscale]))
				else
					sb.push(new Float32Array([x, bot, h]))
				break
			default:
//			case "[":
//			case "]":
				x -= 3;
				thb.push(new Float32Array([x + 1.5, bot, h]))
				break
			case ":":
				x -= 2;
				gl.push([x + 1, yb - 12, st, "rdots"])
				break
			}
			x -= 3
		}
		set_sscale(-1);
		anno_stop(s)
	} // draw_bar()

	// output all the bars
	function out_bars() {
	    var	i, b, w, bx,
		l = sb.length;

		set_sscale(-1)
		if (l) {			// single bars [x, y, h]
			output += '<path class="stroke bW" d="'
			for (i = 0; i < l; i++) {
				b = sb[i];
				out_XYAB('MX Yv-F', b[0], b[1], b[2])
			}
			output += '"/>\n'
		}

		l = db.length
		if (l) {			// dotted bars [x, y, h, scale]
			for (i = 0; i < l; i++) {
				b = db[i];
				w = (5 * b[3]).toFixed(1);
				out_XYAB('<path class="stroke bW" ' +
					'stroke-dasharray="' + w + ',' + w + '" d="' +
					'MX Yv-F"/>\n', b[0], b[1], b[2])
			}
		}

		l = thb.length
		if (l) {			// thick bars [x, y, h]
			output += '<path class="stroke bthW" d="'
			for (i = 0; i < l; i++) {
				b = thb[i];
				out_XYAB('MX Yv-F', b[0], b[1], b[2])
			}
			output += '"/>\n'
		}

		l = gl.length
		if (l) {			// glyphs [x, y, staff, glyph]
			for (i = 0; i < l; i++) {
				b = gl[i];
				set_sscale(b[2]);
				xygl(b[0], b[1], b[3])
			}
		}
			
		l = rn.length
		if (l) {			// repeat number [x, y, staff, number]
			set_font("annotation");
			if (gene.curfont.box) {
				gene.curfont.box = false
				bx = true
			}
			for (i = 0; i < l; i++) {
				b = rn[i];
				set_sscale(b[2]);
				xy_str(b[0], b[1], b[3], "c")
			}
			if (bx)
				gene.curfont.box = true
		}
	} // out_bars()

	// draw_systems()
	draw_vname(indent)

	/* draw the staff, skipping the staff breaks */
	for (st = 0; st <= nstaff; st++)
		xstaff[st] = !cur_sy.st_print[st] ? -1 : 0;
	bar_set();
	draw_lstaff(0)
	for (s = tsfirst; s; s = s.ts_next) {
		if (bar_force && s.time != bar_force) {
			bar_force = 0
			for (st = 0; st <= nstaff; st++) {
				if (!cur_sy.st_print[st])
					xstaff[st] = -1
			}
			bar_set()
		}
		switch (s.type) {
		case STAVES:
			staves_bar = 0
		case C.STAVES:
			staves_bar = s.ts_prev.type == C.BAR ? s.ts_prev.x : 0
		    if (!staves_bar) {
			for (s2 = s.ts_next; s2; s2 = s2.ts_next) {
				if (s2.time != s.time)
					break
				switch (s2.type) {
				case BAR:
				case CLEF:
				case KEY:
				case METER:
				case C.BAR:
				case C.CLEF:
				case C.KEY:
				case C.METER:
					staves_bar = s2.x
					continue
				}
				break
			}
			if (!s2)
				staves_bar = realwidth;
		    }
			cur_sy = s.sy
			sy = s.sy
			for (st = 0; st <= nstaff; st++) {
				x = xstaff[st]
				if (x < 0) {		// no staff yet
					if (cur_sy.st_print[st])
						xstaff[st] = s.ts_next.type == BAR ?
							s.x : (s.x - s.wl - 2)
					if (sy.st_print[st])
						xstaff[st] = staves_bar ?
							staves_bar : (s.x - s.wl - 2)
					continue
				}
				if (cur_sy.st_print[st]) // if not staff stop
				if (sy.st_print[st]	// if not staff stop
				 && sy.staves[st].stafflines ==
						cur_sy.staves[st].stafflines)
					continue
				if (staves_bar) {
					x2 = staves_bar;
					bar_force = s.time
				} else {
					x2 = s.x - s.wl - 2;
					xstaff[st] = -1
				}
				draw_staff(st, x, x2)
				if (sy.st_print[st])
					xstaff[st] = x2
			}
			cur_sy = sy;
			bar_set()
			continue
		case BAR:
		case C.BAR:
			st = s.st
			if (s.second || s.invis)
			if (s.second || s.invis || !s.bar_type)
				break

			// if the bar is not in the current staff system
			// it may be in the next one
			if (xstaff[st] < 0) {
				for (s2 = s.ts_next;
				     s2 && s2.time == s.time;
				     s2 = s2.ts_next) {
					if (s2.type == STAVES)
						break
				}
				if (!s2 || s2.type != STAVES)
					break
				xstaff[st] = s.x;
			st = s.st;
				bar_set()
			}

			draw_bar(s, bar_bot[st], bar_height[st]);
			draw_bar(s, bar_bot[st], bar_height[st])
			break
		case STBRK:
		case C.STBRK:
			if (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].range > 0)
							nv++
					}
					for (s2 = s.ts_next; s2; s2 = s2.ts_next) {
						if (s2.type != STBRK)
						if (s2.type != C.STBRK)
							break
						nv--
					}
					if (nv == 0)
						draw_lstaff(s.x)
				}
			}
			s2 = s.prev
			if (!s2)
				break
			x2 = s2.x
			if (s2.type != BAR)
			if (s2.type != C.BAR)
				x2 += s2.wr;
			st = s.st;
			x = xstaff[st]
			if (x >= 0) {
				if (x >= x2)
					continue
				draw_staff(st, x, x2)
︙
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
3696
3697
3698
3699
3700
3701




3702
3703
3704

3705
3706

3707
3708

3709
3710
3711


3712
3713

3714
3715

3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732

3733
3734
3735
3736
3737
3738
3739
3740

3741
3742

3743
3744
3745
3746
3747

3748
3749
3750
3751
3752
3753

3754
3755

3756
3757
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
3786
3787
3788
3789





3790
3791
3792
3793
3794
3795
3796
3797
3798
3799

3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811

3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828

3829
3830
3831

3832
3833

3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851

3852
3853
3854
3855

3856
3857

3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869

3870
3871
3872
3873
3874
3875
3876

3877
3878

3879
3880

3881
3882

3883
3884
3885
3886
3887
3888

3889
3890
3891
3892
3893

3894
3895

3896
3897

3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916

3917
3918
3919
3920
3921
3922
3923
3924



3925
3926
3927
3928
3929
3930
3931
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715

3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728

3729
3730
3731
3732

3733
3734
3735
3736
3737
3738
3739
3740

3741
3742
3743
3744

3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755

3756
3757
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
3786
3787

3788
3789
3790
3791
3792
3793
3794
3795

3796
3797
3798
3799
3800
3801



3802
3803
3804
3805
3806
3807

3808
3809
3810
3811
3812
3813

3814
3815
3816

3817
3818
3819

3820
3821
3822
3823
3824

3825
3826
3827
3828
3829

3830
3831
3832
3833


3834
3835
3836

3837
3838
3839
3840





3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854

3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866

3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883

3884
3885
3886

3887
3888

3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906

3907
3908
3909
3910

3911
3912

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







+
+
+
-
+



+








-
+



-
+



+



-
+



-
+










-
+
+
+
+


-
+

-
+
-
-
+

-
-
+
+
-
-
+

-
+
















-
+







-
+


+


-
-
-
+





-
+


+


-
+


-
+


-
+




-
+




-
+



-
-
+
+

-
+



-
-
-
-
-
+
+
+
+
+









-
+











-
+
















-
+


-
+

-
+

















-
+



-
+

-
+











-
+






-
+

-
+

-
+

-
+





-
+




-
+

-
+

-
+


















-
+





-
-
-
+
+
+







		if (bar_force && !cur_sy.st_print[st])
			continue
		x = xstaff[st]
		if (x < 0 || x >= realwidth)
			continue
		draw_staff(st, x, realwidth)
	}

	// and the bars
	out_bars()
//	set_sscale(-1)
	set_sscale(-1)
}

/* -- draw remaining symbols when the staves are defined -- */
// (possible hook)
function draw_symbols(p_voice) {
	var	bm = {},
		s, g, x, y, st;

//	bm.s2 = undefined
	for (s = p_voice.sym; s; s = s.next) {
		if (s.invis) {
			switch (s.type) {
			case KEY:
			case C.KEY:
				p_voice.key = s
			default:
				continue
			case NOTE:	// (beams may start on invisible notes)
			case C.NOTE:	// (beams may start on invisible notes)
				break
			}
		}
		st = s.st
		x = s.x;
		set_color(s.color)
		switch (s.type) {
		case NOTE:
		case C.NOTE:
//--fixme: recall set_scale if different staff
			set_scale(s)
			if (s.beam_st && !s.beam_end) {
				if (calculate_beam(bm, s))
				if (self.calculate_beam(bm, s))
					draw_beams(bm)
			}
			if (!s.invis) {
				anno_start(s);
				draw_note(s, !bm.s2);
				anno_stop(s)
			}
			if (s == bm.s2)
				bm.s2 = null
			break
		case REST:
		case C.REST:
			if (s.invis
			 || !staff_tb[st].topbar)
				break
			draw_rest(s);
			break
		case BAR:
		case C.BAR:
			break			/* drawn in draw_systems */
		case CLEF:
		case C.CLEF:
			st = s.st
			if (s.time > staff_tb[st].clef.time)
			if (s.time >= staff_tb[st].clef.time)
				staff_tb[st].clef = s
			if (s.second)
/*			 || p_voice.st != st)	*/
			if (s.second
			 || s.invis
				break		/* only one clef per staff */
			if (!staff_tb[s.st].topbar)
			 || !staff_tb[st].topbar)
				break
			set_color(undefined);
			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)
			else if (!s.clef_small)
				xygl(x, y + s.y, s.clef_type + "clef")
			else
				xygl(x, y + s.y, "s" + s.clef_type + "clef")
			if (s.clef_octave) {
/*fixme:break the compatibility and avoid strange numbers*/
				if (s.clef_octave > 0) {
					y += s.ymx - 10
					if (s.clef_small)
						y -= 1
				} else {
					y += s.ymn + 2
					y += s.ymn + 6
					if (s.clef_small)
						y += 1
				}
				xygl(x - 2, y, "oct")
			}
			anno_stop(s)
			break
		case METER:
		case C.METER:
			p_voice.meter = s
			if (s.second
//			 || s.invis
			 || !staff_tb[s.st].topbar)
				break
			if (cfmt.alignbars && s.st != 0)
				break
			set_color(undefined);
			set_color();
			set_sscale(s.st);
			anno_start(s);
			draw_meter(x, s);
			anno_stop(s)
			break
		case KEY:
		case C.KEY:
			p_voice.key = s
			if (s.second
			 || s.invis
			 || !staff_tb[s.st].topbar)
				break
			set_color(undefined);
			set_color();
			set_sscale(s.st);
			anno_start(s);
			draw_keysig(p_voice, x, s);
			draw_keysig(x, s);
			anno_stop(s)
			break
		case MREST:
		case C.MREST:
			set_scale(s);
			x += 32;
			anno_start(s);
			xygl(x, staff_tb[s.st].y + 12, "mrest");
			out_XYAB('<text style="font-family:serif; font-weight:bold; font-size: 15px"\n\
			out_XYAB('<text style="font:bold 15px serif"\n\
	x ="X" y="Y" text-anchor="middle">A</text>\n',
				x, staff_tb[s.st].y + 28, s.nmes);
			anno_stop(s)
			break
		case GRACE:
		case C.GRACE:
			set_scale(s);
			draw_gracenotes(s)
			break
		case SPACE:
		case STBRK:
		case C.SPACE:
		case C.STBRK:
			break			/* nothing */
		case CUSTOS:
		case C.CUSTOS:
			set_scale(s);
			draw_note(s, 0)
			break
		case BLOCK:			// no width
		case PART:
		case REMARK:
		case STAVES:
		case TEMPO:
		case C.BLOCK:			// no width
		case C.PART:
		case C.REMARK:
		case C.STAVES:
		case C.TEMPO:
			break
		default:
			error(2, s, "draw_symbols - Cannot draw symbol " + s.type)
			break
		}
	}
	set_scale(p_voice.sym);
	draw_all_ties(p_voice);
// no need to reset the scale as in abcm2ps
	set_color(undefined)
	set_color()
}

/* -- 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)
			draw_symbols(p_voice)
			self.draw_symbols(p_voice)
	}

	draw_all_deco();
	set_sscale(-1)				/* restore the scale */
}

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

	for (s = sym; s; s = s.next) {
		if (!s.ti1)
			continue

		/* if other voice, set the ties in opposite direction */
		if (s.multi != 0) {
			dir = s.multi > 0 ? SL_ABOVE : SL_BELOW
			dir = s.multi > 0 ? C.SL_ABOVE : C.SL_BELOW
			for (i = 0; i <= s.nhd; i++) {
				ti = s.notes[i].ti1;
				if (!((ti & 0x07) == SL_AUTO))
				if (!((ti & 0x07) == C.SL_AUTO))
					continue
				s.notes[i].ti1 = (ti & SL_DOTTED) | dir
				s.notes[i].ti1 = (ti & C.SL_DOTTED) | dir
			}
			continue
		}

		/* if one note, set the direction according to the stem */
		sec = ntie = 0;
		pit = 128
		for (i = 0; i <= s.nhd; i++) {
			if (s.notes[i].ti1) {
				ntie++
				if (pit < 128
				 && s.notes[i].pit <= pit + 1)
					sec++;
				pit = s.notes[i].pit
			}
		}
		if (ntie <= 1) {
			dir = s.stem < 0 ? SL_ABOVE : SL_BELOW
			dir = s.stem < 0 ? C.SL_ABOVE : C.SL_BELOW
			for (i = 0; i <= s.nhd; i++) {
				ti = s.notes[i].ti1
				if (ti) {
					if ((ti & 0x07) == SL_AUTO)
					if ((ti & 0x07) == C.SL_AUTO)
						s.notes[i].ti1 =
							(ti & SL_DOTTED) | dir
							(ti & C.SL_DOTTED) | dir
					break
				}
			}
			continue
		}
		if (sec == 0) {
			if (ntie & 1) {
/* in chords with an odd number of notes, the outer noteheads are paired off
 * center notes are tied according to their position in relation to the
 * center line */
				ntie = (ntie - 1) / 2;
				dir = SL_BELOW
				dir = C.SL_BELOW
				for (i = 0; i <= s.nhd; i++) {
					ti = s.notes[i].ti1
					if (ti == 0)
						continue
					if (ntie == 0) {	/* central tie */
						if (s.notes[i].pit >= 22)
							dir = SL_ABOVE
							dir = C.SL_ABOVE
					}
					if ((ti & 0x07) == SL_AUTO)
					if ((ti & 0x07) == C.SL_AUTO)
						s.notes[i].ti1 =
							(ti & SL_DOTTED) | dir
							(ti & C.SL_DOTTED) | dir
					if (ntie-- == 0)
						dir = SL_ABOVE
						dir = C.SL_ABOVE
				}
				continue
			}
/* even number of notes, ties divided in opposite directions */
			ntie /= 2;
			dir = SL_BELOW
			dir = C.SL_BELOW
			for (i = 0; i <= s.nhd; i++) {
				ti = s.notes[i].ti1
				if (ti == 0)
					continue
				if ((ti & 0x07) == SL_AUTO)
				if ((ti & 0x07) == C.SL_AUTO)
					s.notes[i].ti1 =
						(ti & SL_DOTTED) | dir
						(ti & C.SL_DOTTED) | dir
				if (--ntie == 0)
					dir = SL_ABOVE
					dir = C.SL_ABOVE
			}
			continue
		}
/*fixme: treat more than one second */
/*		if (nsec == 1) {	*/
/* When a chord contains the interval of a second, tie those two notes in
 * opposition; then fill in the remaining notes of the chord accordingly */
			pit = 128
			for (i = 0; i <= s.nhd; i++) {
				if (s.notes[i].ti1) {
					if (pit < 128
					 && s.notes[i].pit <= pit + 1) {
						ntie = i
						break
					}
					pit = s.notes[i].pit
				}
			}
			dir = SL_BELOW
			dir = C.SL_BELOW
			for (i = 0; i <= s.nhd; i++) {
				ti = s.notes[i].ti1
				if (ti == 0)
					continue
				if (ntie == i)
					dir = SL_ABOVE
				if ((ti & 0x07) == SL_AUTO)
					s.notes[i].ti1 = (ti & SL_DOTTED) | dir
					dir = C.SL_ABOVE
				if ((ti & 0x07) == C.SL_AUTO)
					s.notes[i].ti1 = (ti & C.SL_DOTTED) | dir
			}
/*fixme..
			continue
		}
..*/
/* if a chord contains more than one pair of seconds, the pair farthest
 * from the center line receives the ties drawn in opposition */
︙
3945
3946
3947
3948
3949
3950
3951
3952

3953
3954
3955

3956
3957
3958
3959
3960

3961
3962
3963
3964
3965
3966
3967
4001
4002
4003
4004
4005
4006
4007

4008
4009
4010

4011
4012
4013
4014
4015

4016
4017
4018
4019
4020
4021
4022
4023







-
+


-
+




-
+







		if (!s)
			continue
		set_tie_dir(s)
		for ( ; s; s = s.next) {
			if (!s.ti1)
				continue
			if (s.notes[0].pit < 20
			 && (s.notes[0].ti1 & 0x07) == SL_BELOW)
			 && (s.notes[0].ti1 & 0x07) == C.SL_BELOW)
				;
			else if (s.notes[s.nhd].pit > 24
			      && (s.notes[s.nhd].ti1 & 0x07) == SL_ABOVE)
			      && (s.notes[s.nhd].ti1 & 0x07) == C.SL_ABOVE)
				;
			else
				continue
			s2 = s.next
			while (s2 && s2.type != NOTE)
			while (s2 && s2.type != C.NOTE)
				s2 = s2.next
			if (s2) {
				if (s2.st != s.st)
					continue
				dx = s2.x - s.x - 10
			} else {
				dx = realwidth - s.x - 10
︙
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
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
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


-
+
















-
-
+
-

-
-
-
-
+
+
+
+

-
+




+





+





+

+
-
+

+
+


+
















+



+













-
+




+






+


+
+


+







+

+


+









+
-
+





-
+




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




-
+








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


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


-
+
+
+
+
+

-
+
-
-
-



-
+
+
+



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

-

-
-
-







// abc2svg - format.js - formatting functions
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-2019 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	defined_font = {},
	font_tb = {},
var	font_tb = [],
	fid = 1,
	font_scale_tb = {
		serif: 1.05,
		serifBold: 1.05,
		'sans-serif': 1.1,
		'sans-serifBold': 1.1,
		serif: 1,
		serifBold: 1,
		'sans-serif': 1,
		'sans-serifBold': 1,
		Palatino: 1.1,
		Mono: 1.35
		monospace: 1.35
	},
	fmt_lock = {}

var cfmt = {
	annotationfont: { name: "sans-serif", size: 12 },
	aligncomposer: 1,
//	botmargin: .7 * IN,		// != 1.8 * CM,
	breaklimit: .7,
	breakoneoln: true,
	cancelkey: true,
	composerfont: { name: "serifItalic", size: 14 },
	composerspace: 6,
//	contbarnb: false,
	dblrepbar: ':][:',
	decoerr: true,
	dynalign: true,
	footerfont: { name: "serif", size: 16 },
	fullsvg: '',
	gchordfont: { name: "sans-serif", size: 12 },
	gracespace: [6.5, 8, 12],	/* left, inside, right */
	gracespace: new Float32Array([4, 8, 11]), // left, inside, right
	graceslurs: true,
	headerfont: { name: "serif", size: 16 },
	historyfont: { name: "serif", size: 16 },
	hyphencont: true,
	indent: 0,
	infofont: {name: "serifItalic", size: 14 },
	infoname: 'R "Rhythm: "\n\
B "Book: "\n\
S "Source: "\n\
D "Discography: "\n\
N "Notes: "\n\
Z "Transcription: "\n\
H "History: "',
	infospace: 0,
	keywarn: true,
	leftmargin: 1.4 * CM,
	lineskipfac: 1.1,
	linewarn: true,
	maxshrink: .65,
	maxstaffsep: 2000,
	maxsysstaffsep: 2000,
	measurefirst: 1,
	measurefont: {name: "serifItalic", size: 10},
	measurenb: -1,
	musicspace: 6,
//	notespacingfactor: 1.414,
	partsfont: {name: "serif", size: 15},
	parskipfac: .4,
	partsspace: 8,
//	pageheight: 29.7 * CM,
	pagewidth: 21 * CM,
//	pos: {
//		dyn: 0,
//		gch: 0,
//		gst: 0,
//		orn: 0,
//		stm: 0,
//		voc: 0,
//		vol: 0
//	},
	"printmargin": 0,
	printmargin: 0,
	rightmargin: 1.4 * CM,
	rbdbstop: true,
	rbmax: 4,
	rbmin: 2,
	repeatfont: {name: "serif", size: 13},
	scale: 1,
	slurheight: 1.0,
	staffsep: 46,
	stemheight: 21,			// one octave
	stretchlast: .25,
	stretchstaff: true,
	subtitlefont: {name: "serif", size: 16},
	subtitlespace: 3,
	sysstaffsep: 34,
	tempofont: {name: "serifBold", size: 15},
	textfont: {name: "serif", size: 16},
//	textoption: undefined,
	textspace: 14,
	titlefont: {name: "serif", size: 20},
//	titleleft: false,
	titlespace: 6,
	titletrim: true,
//	transp: 0,			// global transpose
//	topmargin: .7 * IN,
	topspace: 22,
	tuplets: [0, 0, 0, 0],
	vocalfont: {name: "serifBold", size: 13},
	vocalspace: 10,
	voicefont: {name: "serifBold", size: 13},
//	voicescale: 1,
	writefields: "CMOPQsTWw",
	wordsfont: {name: "serif", size: 16},
	wordsspace: 5
}

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

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

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

	if (isNaN(scale) || a <= 0) {
	if (isNaN(scale) || scale <= 0.5) {
		syntax(1, "Bad scale value in %%font")
		return
	}
	font_scale_tb[a[0]] = scale
}
	for (var fn in font_tb) {
		if (!font_tb.hasOwnProperty(fn))
			continue
		var font = font_tb[fn]
		if (font.name == a[0])
			font.swfac = font.size * scale

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

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

// %%xxxfont fontname|* [encoding] [size|*]
function param_set_font(xxxfont, param) {
	var font, fn, old_fn, n, a, new_name, new_fn, new_size, scale, cl
    var	font, old_fn, n, a, new_name, new_fn, new_size, scale

	// "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
	fn = cfmt[xxxfont]
	if (fn) {
		font = font_tb[fn]
		if (font) {
			old_fn = font.name + "." + font.size
			if (font.class)
	font = cfmt[xxxfont];
	if (!font) {			// set-font-<n> or new element
		font = {
			name: "sans-serif",
			size: 12
		}
	}
	font = Object.create(font);
	font.fid = font.used = undefined;
	cfmt[xxxfont] = font;
				old_fn += '.' + font.class
		}

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

	n = param.indexOf('class=')
	if (n >= 0) {
		n += 6;
		a = param.indexOf(' ', n)
		if (a > 0)
			cl = param.slice(n, a)
		else
			cl = param.slice(n);
		param = param.replace(new RegExp('class=' + cl), '').trim()
	a = param.match(/\s+class=(.*?)(\s|$)/)
	if (a) {
		font.class = a[1];
		param = param.replace(a[0], a[2])
	}
	a = param.match(/\s+wadj=(.*?)(\s|$)/)
	if (a) {
	    if (typeof document == "undefined")	// useless if in browser
		switch (a[1]) {
		case 'none':
			font.wadj = ''
			break
		case 'space':
			font.wadj = 'spacing'
			break
		case 'glyph':
			font.wadj = 'spacingAndGlyphs'
			break
		default:
			syntax(1, errs.bad_val, "%%" + xxxfont)
			break
		}
		param = param.replace(a[0], a[2])
	}

	a = param.split(/\s+/);
	a = info_split(param)
	if (!a) {
		syntax(1, errs.bad_val, "%%" + xxxfont)
		return
	}
	new_name = a[0]
	if (new_name == "*"
	if (new_name != "*") {
	 && font) {
		new_name = font.name
	} else {
		new_name = new_name.replace('Times-Roman', 'serif');
		new_name = new_name.replace('Times', 'serif');
		new_name = new_name.replace('Helvetica', 'sans-serif');
		new_name = new_name.replace('Courier', 'monospace')
		new_name = new_name.replace('Courier', 'monospace');
		font.name = new_name
		font.swfac = 0
	}
	if (a.length > 1) {
		new_size = a[a.length - 1]
		if (new_size == '*' && font)
			new_size = font.size
	} else if (font) {
		new_size = font.size
		if (new_size != '*') {
			new_size = Number(new_size)
			if (isNaN(new_size)) {
				syntax(1, errs.bad_val, "%%" + xxxfont)
			} else {
				font.size = new_size;
	}
	if (!new_size) {
		// error ?
		return
	}
				font.swfac = 0
			}
	new_fn = new_name + "." + new_size
	if (cl)
		new_fn += '.' + cl
	if (new_fn == old_fn)
		return
	font = font_tb[new_fn]
	if (!font) {
		scale = font_scale_tb[new_name]
		if (!scale)
			scale = 1.1;
		font = {
			name: new_name,
			size: Number(new_size),
			swfac: new_size * scale
		}
		font_tb[new_fn] = font
	}
	if (cl)
		font.class = cl;
	cfmt[xxxfont] = new_fn
}

// get a length with a unit - return the number of pixels
function get_unit(param) {
	var v = parseFloat(param)

	switch (param.slice(-2)) {
︙
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
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







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







-
+







}
function get_textopt(param) {
	return textopt[param]
}

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

/* -- set the position of elements in a voice -- */
function set_pos(k, v) {		// keyword, value
	k = k.slice(0, 3)
	if (k == "ste")
		k = "stm"
	set_v_param("pos", k + ' ' + v)
	self.set_v_param("pos", k + ' ' + v)
}

// set/unset the fields to write
function set_writefields(parm) {
	var	c, i,
		a = parm.split(/\s+/)

︙
301
302
303
304
305
306
307

308
309
310

311
312
313
314
315
316
317
330
331
332
333
334
335
336
337
338
339

340
341
342
343
344
345
346
347







+


-
+







			if (cfmt.writefields.indexOf(c) >= 0)
				cfmt.writefields = cfmt.writefields.replace(c, '')
		}
	}
}

// set a voice specific parameter
// (possible hook)
function set_v_param(k, v) {
	if (curvoice) {
		set_vp([k + '=', v])
		self.set_vp([k + '=', v])
		return
	}
	k = [k + '=', v];
	var vid = '*'
	if (!info.V)
		info.V = {}
	if (info.V[vid])
︙
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
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







+

-
+








-
-
-
-

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







		error(0, undefined, "Bad staff width");
		img.width = img.lm + img.rm + 150
	}
	set_posx()
} // set_page()

// set a format parameter
// (possible hook)
function set_format(cmd, param, lock) {
	var f, f2, v, box, i
	var f, f2, v, i

//fixme: should check the type and limits of the parameter values
	if (lock) {
		fmt_lock[cmd] = true
	} else if (fmt_lock[cmd])
		return

	if (/.+font(-[\d])?$/.test(cmd)) {
		if (param.slice(-4) == " box") {
			box = true;
			param = param.slice(0, -4)
		}
		param_set_font(cmd, param)
		switch (cmd) {
		case "gchordfont":
			cfmt.gchordbox = box
			break
//		case "annotationfont":
//			cfmt.annotationbox = box
//			break
		case "measurefont":
			cfmt.measurebox = box
			break
		case "partsfont":
			cfmt.partsbox = box
			break
		}
		return
	}

	switch (cmd) {
	case "aligncomposer":
	case "barsperstaff":
	case "infoline":
︙
391
392
393
394
395
396
397
398

399
400
401
402
403
404
405
404
405
406
407
408
409
410

411
412
413
414
415
416
417
418







-
+







		break
	case "microscale":
		f = parseInt(param)
		if (isNaN(f) || f < 4 || f > 256 || f % 1) {
			syntax(1, errs.bad_val, "%%" + cmd)
			break
		}
		set_v_param("uscale", f)
		self.set_v_param("uscale", f)
		break
	case "bgcolor":
	case "dblrepbar":
	case "titleformat":
		cfmt[cmd] = param
		break
	case "breaklimit":			// float values
︙
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
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







+
+
+
+
+
+
+








-





-
-



+







		case "pagescale":
			cmd = "scale";
			img.chg = true
			break
		}
		cfmt[cmd] = f
		break
	case "annotationbox":
	case "gchordbox":
	case "measurebox":
	case "partsbox":
		cfmt[cmd.replace("box", "font")]	// font
			.box = get_bool(param)
		break
	case "bstemdown":
	case "breakoneoln":
	case "cancelkey":
	case "contbarnb":
	case "custos":
	case "decoerr":
	case "dynalign":
	case "flatbeams":
	case "gchordbox":
	case "graceslurs":
	case "graceword":
	case "hyphencont":
	case "keywarn":
	case "linewarn":
	case "measurebox":
	case "partsbox":
	case "rbdbstop":
	case "singleline":
	case "squarebreve":
	case "splittune":
	case "straightflags":
	case "stretchstaff":
	case "timewarn":
	case "titlecaps":
	case "titleleft":
		cfmt[cmd] = get_bool(param)
		break
︙
495
496
497
498
499
500
501

502

503
504
505
506
507
508
509
513
514
515
516
517
518
519
520

521
522
523
524
525
526
527
528







+
-
+







			syntax(1, errs.bad_val, '%%' + cmd)
			break
		}
		cfmt[cmd] = f;
		img.chg = true
		break
	case "concert-score":
		if (cfmt.sound != "play")
		cfmt.sound = "concert"
			cfmt.sound = "concert"
		break
	case "writefields":
		set_writefields(param)
		break
	case "dynamic":
	case "gchord":
	case "gstemdir":
︙
521
522
523
524
525
526
527
528








529
530
531
532
533
534
535
540
541
542
543
544
545
546

547
548
549
550
551
552
553
554
555
556
557
558
559
560
561







-
+
+
+
+
+
+
+
+







			syntax(1, "Cannot have %%fullsvg inside a tune")
			break
		}
//fixme: should check only alpha, num and '_' characters
		cfmt[cmd] = param
		break
	case "gracespace":
		cfmt[cmd] = param.split(/\s+/)
		v = param.split(/\s+/)
		for (i = 0; i < 3; i++)
			if (isNaN(Number(v[i]))) {
				syntax(1, errs.bad_val, "%%gracespace")
				break
			}
		for (i = 0; i < 3; i++)
			cfmt[cmd][i] = Number(v[i])
		break
	case "tuplets":
		cfmt[cmd] = param.split(/\s+/);
		v = cfmt[cmd][3]
		if (v			// if 'where'
		 && (posval[v]))	// translate the keyword
			cfmt[cmd][3] = posval[v]
︙
560
561
562
563
564
565
566

567

568
569
570
571
572
573
574
586
587
588
589
590
591
592
593

594
595
596
597
598
599
600
601







+
-
+







		cfmt.sound = "play"		// without clef
		break
	case "pos":
		cmd = param.split(/\s+/);
		set_pos(cmd[0], cmd[1])
		break
	case "sounding-score":
		if (cfmt.sound != "play")
		cfmt.sound = "sounding"
			cfmt.sound = "sounding"
		break
	case "staffwidth":
		v = get_unit(param)
		if (isNaN(v)) {
			syntax(1, errs.bad_val, '%%' + cmd)
			break
		}
︙
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
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
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




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







-
+


-
+










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

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

-
+










-
-
-
-
-
-


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





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



		else
			cfmt[cmd] = v
		break
	case "combinevoices":
		syntax(1, "%%combinevoices is deprecated - use %%voicecombine instead")
		break
	case "voicemap":
		set_v_param("map", param)
		self.set_v_param("map", param)
		break
	case "voicescale":
		set_v_param("scale", param)
		self.set_v_param("scale", param)
		break
	default:		// memorize all global commands
		if (parse.state == 0)		// (needed for modules)
			cfmt[cmd] = param
		break
	}
}

// font stuff

// initialize the default fonts
function font_init() {
	param_set_font("annotationfont", "sans-serif 12");
	param_set_font("composerfont", "serifItalic 14");
	param_set_font("footerfont", "serif 16");
	param_set_font("gchordfont", "sans-serif 12");
	param_set_font("headerfont", "serif 16");
	param_set_font("historyfont", "serif 16");
	param_set_font("infofont", "serifItalic 14");
	param_set_font("measurefont", "serifItalic 14");
	param_set_font("partsfont", "serif 15");
	param_set_font("repeatfont", "serif 13");
	param_set_font("subtitlefont", "serif 16");
	param_set_font("tempofont", "serifBold 15");
	param_set_font("textfont", "serif 16");
	param_set_font("titlefont", "serif 20");
	param_set_font("vocalfont", "serifBold 13");
	param_set_font("voicefont", "serifBold 13");
	param_set_font("wordsfont", "serif 16")
}

// build a font style
function style_font(fn) {		// 'font_name'.'size'
function style_font(font) {
	var	r = fn.split('.'),
		sz = r[1],
		i = fn.indexOf("Italic"),
		j = 100,
		o = fn.indexOf("Oblique"),
		b = fn.indexOf("Bold");

	fn = r[0];
	r = ''
    var	fn = font.name,
	r = '',
	if (b > 0) {
		r += "font-weight:bold; ";
		j = b
	}
	a = fn.match(/-?[bB]old/)

	if (i > 0 || o > 0) {
		if (i > 0) {
			r += "font-style:italic; "
	if (a) {
		r += "bold ";
			if (i < j)
				j = i
		}
		if (o > 0) {
			r += "font-style:oblique; "
		fn = fn.replace(a[0], '')
	}
	a = fn.match(/-?[iI]talic/)
	if (a) {
		r += "italic ";
			if (o < j)
				j = o
		}
		fn = fn.replace(a[0], '')
	}
	}
	if (j != 100) {
		if (fn[j - 1] == '-')
	a = fn.match(/-?[oO]blique/)
	if (a) {
		r += "oblique ";
			j--;
		fn = fn.slice(0, j)
		fn = fn.replace(a[0], '')
	}
	return 'font-family:' + fn + '; ' + r + 'font-size:' + sz + 'px'
	return 'font:' + r + font.size.toFixed(1) + 'px ' + fn
}
Abc.prototype.style_font = style_font

// build a font class
function font_class(font) {
	if (font.class)
		return 'f' + font.fid + cfmt.fullsvg + ' ' + font.class
	return 'f' + font.fid + cfmt.fullsvg
}

// output a font style
function style_add_font(font) {
	font_style += "\n.f" + font.fid + cfmt.fullsvg +
			" {" + style_font(font.name + '.' + font.size) + "}"
}

// use the font
function use_font(font) {
	if (!defined_font[font.fid]) {
		defined_font[font.fid] = true;
		style_add_font(font)
	if (!font.used) {
		font.used = true;
		if (font.fid == undefined) {
			font.fid = font_tb.length;
			font_tb.push(font)
			if (!font.swfac)
				set_font_fac(font)
		}
		font_style += "\n.f" + font.fid + cfmt.fullsvg +
			" {" + style_font(font) + "}"
	}
}

// get the font of the 'xxxfont' parameter
function get_font(xxx) {
	xxx += "font"
	var	fn = cfmt[xxx],
		font = font_tb[fn]
    var	fn = xxx + "font",
	font = cfmt[fn];
	if (!font) {
		syntax(1, "Unknown font $1", xxx);
		font = gene.curfont
	}

	if (!font.fid)
		font.fid = fid++;
	use_font(font)
	return font
}
Changes to core/front.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - front.js - ABC parsing front-end
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-2019 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.
︙
175
176
177
178
179
180
181

182












183
184
185
186
187
188
189
175
176
177
178
179
180
181
182

183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201







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







				continue
			}
			break
		}
		dst += '\\' + c;
		j = i + 1
	}
	// cleanup for XML treatment
	return dst + src.slice(j)
	return (dst + src.slice(j)).replace(/<|>|  |&.*?;|&/g, function(c) {
			switch (c) {
			case '<': return "&lt;"
			case '>': return "&gt;"
			case '&': return "&amp;"
			case '  ': return '  '		// space + nbspace
			case "&lt;":
			case "&gt;":
			case "&amp;": return c
			}
			return "&amp;" + c.slice(1)
		})
}

// ABC include
var include = 0

function do_include(fn) {
	var file, parse_sav
︙
209
210
211
212
213
214
215
216

217
218
219
220
221
222
223
221
222
223
224
225
226
227

228
229
230
231
232
233
234
235







-
+







}

// parse ABC code
function tosvg(in_fname,		// file name
		file,			// file content
		bol, eof) {		// beginning/end of file
	var	i, c, bol, eol, end,
		ext, select,
		select,
		line0, line1,
		last_info, opt, text, a, b, s,
		cfmt_sav, info_sav, char_tb_sav, glovar_sav, maps_sav,
		mac_sav, maci_sav,
		pscom,
		txt_add = '\n'		// for "+:"

︙
241
242
243
244
245
246
247



248
249

250
251
252
253
254
255
256
253
254
255
256
257
258
259
260
261
262
263

264
265
266
267
268
269
270
271







+
+
+

-
+







		else
			eol = eof
		return false
	} // tune_selected()

	// remove the comment at end of text
	function uncomment(src, do_escape) {
	    var i
		if (!src)
			return src
		if (src.indexOf('%') >= 0)
			src = src.replace(/(.*[^\\])%.*/, '$1')
			src = src.replace(/([^\\])%.*/, '$1')
				 .replace(/\\%/g, '%');
		src = src.replace(/\s+$/, '')
		if (do_escape && src.indexOf('\\') >= 0)
			return cnv_escape(src)
		return src
	} // uncomment()

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







-
-



-
+


-
-
-
+














-
+














-
+



















-
+







				}
				break
			}
			text = file.slice(bol, eol)
			if (!text || text[0] == '%')
				continue
			a = text.split(/\s+/, 2)
			if (!a[0])
				a.shift()
			switch (a[0]) {
			case "abcm2ps":
			case "ss-pref":
				parse.prefix = a[1]
				parse.prefix = a[1]	// may contain a '%'
				continue
			case "abc-include":
				ext = a[1].match(/.*\.(.*)/)
				if (ext && ext[1] == "abc")
					do_include(a[1])
				do_include(uncomment(a[1]))
				continue
			}

			// beginxxx/endxxx
			if (a[0].slice(0, 5) == 'begin') {
				b = a[0].substr(5);
				end = '\n' + line0 + line1 + "end" + b;
				i = file.indexOf(end, eol)
				if (i < 0) {
					syntax(1, "No $1 after %%$2",
							end.slice(1), a[0]);
					parse.eol = eof
					continue
				}
				do_begin_end(b, a[1],
				self.do_begin_end(b, uncomment(a[1]),
					file.slice(eol + 1, i).replace(
						new RegExp('^' + line0 + line1, 'gm'),
										''));
				parse.eol = file.indexOf('\n', i + 6)
				if (parse.eol < 0)
					parse.eol = eof
				continue
			}
			switch (a[0]) {
			case "select":
				if (parse.state != 0) {
					syntax(1, "%%select ignored")
					continue
				}
				select = uncomment(text.slice(7), false)
				select = uncomment(text.slice(7))
				if (select[0] == '"')
					select = select.slice(1, -1);
				if (!select) {
					delete parse.select
					continue
				}
				select = select.replace(/\(/g, '\\(');
				select = select.replace(/\)/g, '\\)');
//				select = select.replace(/\|/g, '\\|');
				parse.select = new RegExp(select, 'm')
				continue
			case "tune":
				syntax(1, "%%tune not treated yet")
				continue
			case "voice":
				if (parse.state != 0) {
					syntax(1, "%%voice ignored")
					continue
				}
				select = uncomment(text.slice(6), false)
				select = uncomment(text.slice(6))

				/* if void %%voice, free all voice options */
				if (!select) {
					if (parse.cur_tune_opts)
						parse.cur_tune_opts.voice_opts = null
					else
						parse.voice_opts = null
︙
473
474
475
476
477
478
479
480

481
482
483
484
485

486
487
488
489
490
491
492
484
485
486
487
488
489
490

491
492
493
494
495

496
497
498
499
500
501
502
503







-
+




-
+







						break
					}
					break
				}
				parse.eol = bol - 1
				continue
			}
			do_pscom(uncomment(text, true))
			self.do_pscom(uncomment(text, true))
			continue
		}

		// music line (or free text)
		if (line1 != ':') {
		if (line1 != ':' || !/[A-Za-z+]/.test(line0)) {
			last_info = undefined;
			if (parse.state < 2)
				continue
			parse.line.buffer = uncomment(file.slice(bol, eol), true);
			parse_music_line()
			continue
		}
︙
610
611
612
613
614
615
616
617

618
619
620
621
622
623
624
621
622
623
624
625
626
627

628
629
630
631
632
633
634
635







-
+







		case '|':			// "|:" starts a music line
			if (parse.state < 2)
				continue
			parse.line.buffer = uncomment(file.slice(bol, eol), true);
			parse_music_line()
			continue
		default:
			if ("ABCDFGHOSZ".indexOf(line0) >= 0) {
			if ("ABCDFGHNOSZ".indexOf(line0) >= 0) {
				if (parse.state >= 2) {
					syntax(1, errs.ignored, line0)
					continue
				}
//				if (cfmt.writefields.indexOf(c) < 0)
//					break
				if (!info[line0])
︙
Changes to core/gchord.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - gchord.js - chord symbols
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-2019 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.
︙
57
58
59
60
61
62
63
64

65
66


67
68
69
70
71
72
73
57
58
59
60
61
62
63

64
65
66
67
68
69
70
71
72
73
74
75







-
+


+
+







				c = line.next_char()
			}
			text += c
		}
		iend = parse.bol + line.index + 1
	}

	if (curvoice.pos.gch == SL_HIDDEN)
	if (curvoice.pos.gch == C.SL_HIDDEN)
		return

	if (ann_font.box)
		h_ann += 3;
	i = 0;
	type = 'g'
	while (1) {
		c = text[i]
		if (!c)
			break
		gch = {
︙
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
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







+


















-
-
+
-
-
-


-
-
+
+
-


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


-
+
-
-
+
+













-
-
-
-
+










-
+















-
-
-
+
+
+




-
+



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




+





-
+




-







					case undefined:
					case '\\':
						break
					}
					break
				}
				if (c == ';') {
					i++;
					gch.text += c
					continue
				}
				break
			case ';':
				break
			}
			i++
			break
		}
		if (!a_gch)
			a_gch = []
		a_gch.push(gch)
	}
}

// transpose a chord symbol
var	note_names = "CDEFGAB",
	latin_names = [ "Do", "Re", "Mi", "Fa", "Sol", "La", "Si" ],
	acc_name = ["bb", "b", "", "#", "##"],
	acc_name = ["bb", "b", "", "#", "##"]
	note_pit = new Int8Array([0, 2, 4, 5, 7, 9, 11]),
	pit_note = new Int8Array([0, 0, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6]),
	pit_acc = new Int8Array([2, 3, 2, 1, 2, 2, 3, 2, 1, 2, 1, 2])

	function gch_tr1(p, i2) {
		var	new_txt, l,
			n, i1, i3, i4, ix, a, ip, ip2,
	    var	new_txt,
			n, i1, i3, i4, ix, a, ip, ip2
			latin = 0

		/* main chord */
		switch (p[0]) {
		n = note_names.indexOf(p[0])
		case 'A': n = 5; break
		case 'B': n = 6; break
		case 'C': n = 0; break
		case 'D':
			if (p[1] == 'o') {
		if (n < 0) {
				latin++;
				n = 0		/* Do */
				break
			}
			n = 1
			break
		case 'E': n = 2; break
		case 'F':
			if (p[1] == 'a')
			if (p[0] != '/')
				latin++;	/* Fa */
			n = 3
			break
		case 'G': n = 4; break
		case 'L':
			latin++;		/* La */
			n = 5
			break
		case 'M':
			latin++;		/* Mi */
			n = 2
			break
		case 'R':
			latin++
			n = 1			/* Re */
			break
		case 'S':
			latin++
			if (p[1] == 'o') {
				latin++;
				n = 4		/* Sol */
			} else {
				n = 6		/* Si */
			}
			break
		case '/':			// bass only
			latin--
			break
		default:
			return p
				return p
		}

		a = 0;
		ip = 1
		ip = latin + 1
		if (latin >= 0) {		// if some chord
		if (n >= 0) {		// if some chord
			a = 0
			while (p[ip] == '#') {
				a++;
				ip++
			}
			while (p[ip] == 'b') {
				a--;
				ip++
			}
//			if (p[ip] == '=')
//				ip++
			i3 = cde2fcg[n] + i2 + a * 7;
			i4 = cgd2cde[(i3 + 16 * 7) % 7];	// note
			i1 = ((((i3 + 22) / 7) | 0) + 159) % 5;	// accidental
			new_txt = (latin ? latin_names[i4] : note_names[i4]) +
					acc_name[i1]
		} else {
			new_txt = ''
			new_txt = note_names[i4] + acc_name[i1]
		}

		ip2 = p.indexOf('/', ip)	// skip 'm'/'dim'..
		if (ip2 < 0)
			return new_txt + p.slice(ip);

		/* bass */
		n = note_names.indexOf(p[++ip2])
		if (n < 0)
			return new_txt + p.slice(ip);
//fixme: latin names not treated

		new_txt += p.slice(ip, ip2);
		a = 0
		if (p[++ip2] == '#') {
			a++
			if (p[++ip2] == '#') {
				a++;
				ip2++
			}
		} else if (p[ip2] == 'b') {
			a--
			if (p[++ip2] == 'b') {
				a--;
				ip2++
			}
		}
		i3 = (note_pit[n] + a + i2 + 12) % 12;
		i4 = pit_note[i3];
		i1 = pit_acc[i3]
		i3 = cde2fcg[n] + i2 + a * 7;
		i4 = cgd2cde[(i3 + 16 * 7) % 7];	// note
		i1 = ((((i3 + 22) / 7) | 0) + 159) % 5;	// accidental
		return new_txt + note_names[i4] + acc_name[i1] + p.slice(ip2)
	} // get_tr1

function gch_transp(s) {
	var	gch, p, j,
    var	gch,
		i = 0,
		i2 = curvoice.ckey.k_sf - curvoice.okey.k_sf

	while (1) {
		gch = s.a_gch[i++]
	for (i = 0; i < s.a_gch.length; i++) {
		gch = s.a_gch[i]
		if (!gch)
			return
		if (gch.type != 'g')
		if (gch.type == 'g')
			continue
		p = gch.text;
		j = p.indexOf('\t')
		if (j >= 0) {
			j++;
			p = p.slice(0, j) + gch_tr1(p.slice(j), i2)
		}
		gch.text = gch_tr1(p, i2)
			gch.text = gch_tr1(gch.text, i2)
	}
}

// -- build the chord indications / annotations --
// (possible hook)
function gch_build(s) {

	/* split the chord indications / annotations
	 * and initialize their vertical offsets */
	var	gch, wh, xspc, ix,
		pos = curvoice.pos.gch == SL_BELOW ? -1 : 1,
		pos = curvoice.pos.gch == C.SL_BELOW ? -1 : 1,
		y_above = 0,
		y_below = 0,
		y_left = 0,
		y_right = 0,
		box = cfmt.gchordbox,
		GCHPRE = .4;		// portion of chord before note

	s.a_gch = a_gch;
	a_gch = null

	if (curvoice.vtransp)
		gch_transp(s)
︙
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
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







+
+


+
+

-
+
+

+



-
+

-
+
+
+







					case '##': return "&#x1d12a;"
					case '#': return "\u266f"
					case '=': return "\u266e"
					case 'b': return "\u266d"
					}
					return "&#x1d12b;"
				});
			if (gch.font.box)
				gch.box = true
		} else {
			gch.text = cnv_escape(gch.text);
			if (gch.font.box)
				gch.box = true
			if (gch.type == '@'
			 && !user.anno_start && !user.anno_stop)
			 && !user.anno_start && !user.anno_stop) {
				gch.wh = [0, 0]
				continue		/* no width */
			}
		}

		/* set the offsets and widths */
		gene.curfont = gch.font;
		set_font(gch.font);
		wh = strwh(gch.text);
		gch.w = wh[0]
		gch.wh = wh
		if (gch.box)
			wh[1] += 4
		switch (gch.type) {
		case '@':
			break
		case '^':			/* above */
			xspc = wh[0] * GCHPRE
			if (xspc > 8)
				xspc = 8;
︙
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
325
326
327
328
329
330
331

332
333
334
335
336
337
338




339
340
341




342
343
344
345
346
347
348







-







-
-
-
-



-
-
-
-







			break
		case '>':			/* right */
			gch.x = 6;
			y_right -= wh[1];
			gch.y = y_right + wh[1] / 2
			break
		default:			// chord symbol
			gch.box = box
			xspc = wh[0] * GCHPRE
			if (xspc > 8)
				xspc = 8;
			gch.x = -xspc;
			if (pos < 0) {		/* below */
				y_below -= wh[1];
				gch.y = y_below
				if (box) {
					y_below -= 2;
					gch.y -= 1
				}
			} else {
				y_above -= wh[1];
				gch.y = y_above
				if (box) {
					y_above -= 2;
					gch.y -= 1
				}
			}
			break
		}
	}

	/* move upwards the top and middle texts */
	y_left /= 2;
︙
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
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
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
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







+

-
+


-
-
-
+
+
-
-
+
+



-
-
-
-
+
-
+

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







+
-
+





-
+


-
-
+
+








+
-
-
+
+




-

-
+





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
















-
-
-
-
+





		}
	}
}

// -- draw the chord symbols and annotations
// (the staves are not yet defined)
// (unscaled delayed output)
// (possible hook)
function draw_gchord(s, gchy_min, gchy_max) {
	var	gch, gch2, text, ix, x, y, y2, i, j, hbox, h
    var	gch, text, ix, x, y, y2, hbox, h, y_above, y_below,

	// adjust the vertical offset according to the chord symbols
//fixme: w may be too small
	var	w = s.a_gch[0].w,
		y_above = y_get(s.st, 1, s.x - 2, w),
	w = 0,
		yav = s.dur ?
		y_below = y_get(s.st, 0, s.x - 2, w),
		yav = (((s.notes[s.nhd].pit + s.notes[0].pit) >> 1) - 18) * 3
			(((s.notes[s.nhd].pit + s.notes[0].pit) >> 1) - 18) * 3 :
			12		// fixed offset on measure bars

	for (ix = 0; ix < s.a_gch.length; ix++) {
		gch = s.a_gch[ix]
		if (gch.type != 'g')
			continue
		gch2 = gch		// chord symbol closest to the staff
		if (gch.y < 0)
		if (gch.wh[0] > w)
			break
			w = gch.wh[0]
	}
	if (gch2) {
		if (gch2.y >= 0) {
			if (y_above < gchy_max)
				y_above = gchy_max
	y_above = y_get(s.st, 1, s.x - 2, w);
	y_below = y_get(s.st, 0, s.x - 2, w)
	if (y_above < gchy_max)
		y_above = gchy_max
		} else {
			if (y_below > gchy_min)
				y_below = gchy_min
	if (y_below > gchy_min)
		y_below = gchy_min;
		}
	}

	set_dscale(s.st);
	for (ix = 0; ix < s.a_gch.length; ix++) {
		gch = s.a_gch[ix];
		use_font(gch.font);
		set_font(gch.font);
		h = gch.font.size;
		hbox = gch.box ? 2 : 0;
		w = gch.w;
		w = gch.wh[0];
		x = s.x + gch.x;
		text = gch.text
		switch (gch.type) {
		case '_':			/* below */
			y = gch.y + y_below;
			y_set(s.st, 0, x, w, y - h * .2 - 2)
			y_set(s.st, 0, x, w, y - hbox)
			break
		case '^':			/* above */
			y = gch.y + y_above;
			y_set(s.st, 1, x, w, y + h * .8 + 2)
			y = gch.y + y_above + hbox;
			y_set(s.st, 1, x, w, y + h + hbox)
			break
		case '<':			/* left */
/*fixme: what symbol space?*/
			if (s.notes[0].acc)
				x -= s.notes[0].shac;
			y = gch.y + yav - h / 2
			break
		case '>':			/* right */
			if (s.xmx)
			x += s.xmx
			if (s.dots > 0)
				x += s.xmx
			if (s.dots)
				x += 1.5 + 3.5 * s.dots;
			y = gch.y + yav - h / 2
			break
		default:			// chord symbol
			hbox = gch.box ? 3 : 2
			if (gch.y >= 0) {
				y = gch.y + y_above;
				y = gch.y + y_above + hbox;
				y_set(s.st, true, x, w, y + h + hbox)
			} else {
				y = gch.y + y_below;
				y_set(s.st, false, x, w, y - hbox)
			}
			i = text.indexOf('\t')

			// if some TAB: expand the chord symbol
			if (i >= 0) {
				x = realwidth
				for (var next = s.next; next; next = next.next) {
					switch (next.type) {
					default:
						continue
					case NOTE:
					case REST:
					case BAR:
						x = next.x
						break
					}
					break
				}
				j = 2
				for (;;) {
					i = text.indexOf('\t', i + 1)
					if (i < 0)
						break
					j++
				}
				var expdx = (x - s.x) / j;

				x = s.x;
				y *= staff_tb[s.st].staffscale
				if (user.anno_start)
					user.anno_start("gchord", gch.istart, gch.iend,
						x - 2, y + h + 2, w + 4, h + 4, s)
				i = 0;
				j = i;
				for (;;) {
					i = text.indexOf('\t', j)
					if (i < 0)
						break
					xy_str(x, y, text.slice(j, i), 'c');
					x += expdx;
					j = i + 1
				}
				xy_str(x, y, text.slice(j), 'c')
				if (user.anno_stop)
					user.anno_stop("gchord", gch.istart, gch.iend,
						s.x - 2, y + h + 2, w + 4, h + 4, s)
				continue
			}
			break
		case '@':			/* absolute */
			y = gch.y + yav
			if (y > 0) {
				y2 = y + h
				if (y2 > staff_tb[s.st].ann_top)
					staff_tb[s.st].ann_top = y2
			} else {
				if (y < staff_tb[s.st].ann_bot)
					staff_tb[s.st].ann_bot = y
			}
			break
		}
		if (user.anno_start)
			user.anno_start("annot", gch.istart, gch.iend,
				x - 2, y + h + 2, w + 4, h + 4, s)
		if (gch.box)
			xy_str_b(x, y, text)
		else
			xy_str(x, y, text)
		xy_str(x, y, text, null, null, gch.wh)
		if (user.anno_stop)
			user.anno_stop("annot", gch.istart, gch.iend,
				x - 2, y + h + 2, w + 4, h + 4, s)
	}
}
Changes to core/license.
1
2
3


1


2
3

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

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - lyrics.js - lyrics
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-2019 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.
︙
52
53
54
55
56
57
58
59

60
61
62
63
64
65
66
52
53
54
55
56
57
58

59
60
61
62
63
64
65
66







-
+







		while (p[i] == ' ' || p[i] == '\t')
			i++;
		c = p[i]
		if (!c)
			break
		switch (c) {
		case '|':
			while (s && s.type != BAR)
			while (s && s.type != C.BAR)
				s = s.next
			if (!s) {
				syntax(1, "Not enough measure bars for symbol line")
				return
			}
			s = s.next;
			i++
︙
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
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







-
+
















-
+














-
+







				}
			}
			syntax(1, errs.bad_char, c)
			break
		}

		/* store the element in the next note */
		while (s && (s.type != NOTE || s.grace))
		while (s && (s.type != C.NOTE || s.grace))
			s = s.next
		if (!s) {
			syntax(1, "Too many elements in symbol line")
			return
		}
		switch (c) {
		default:
//		case '*':
			break
		case '!':
			deco_cnv([d.slice(1, -1)], s, s.prev)
			break
		case '"':
			a_gch = s.a_gch;
			parse_gchord(d)
			if (a_gch)
				gch_build(s)
				self.gch_build(s)
			break
		}
		s = s.next;
		i++
	}
	curvoice.lyric_cont = s
}

/* -- parse a lyric (vocal) line (w:) -- */
function get_lyrics(text, cont) {
	var s, word, p, i, j, ly

	if (curvoice.ignore)
		return
	if (curvoice.pos.voc != SL_HIDDEN)
	if (curvoice.pos.voc != C.SL_HIDDEN)
		curvoice.have_ly = true

	// get the starting symbol of the lyrics
	if (cont) {					// +:
		s = curvoice.lyric_cont
		if (!s) {
			syntax(1, "+: lyric without music")
︙
162
163
164
165
166
167
168
169

170
171
172
173
174
175
176
162
163
164
165
166
167
168

169
170
171
172
173
174
175
176







-
+







		while (p[i] == ' ' || p[i] == '\t')
			i++
		if (!p[i])
			break
		j = parse.istart + i + 2	// start index
		switch (p[i]) { 
		case '|':
			while (s && s.type != BAR)
			while (s && s.type != C.BAR)
				s = s.next
			if (!s) {
				syntax(1, "Not enough measure bars for lyric line")
				return
			}
			s = s.next;
			i++
︙
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
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







-
+



















-
+






-
+










-
+







				case '*':
				case '|':
					i--
				case ' ':
				case '\t':
					break
				case '~':
					word += ' ';
					word += ' ';	// (&nbsp;)
					i++
					continue
				case '-':
					word += "\n"
					break
				case '\\':
					word += p[++i];
					i++
					continue
				default:
					word += p[i++]
					continue
				}
				break
			}
			break
		}

		/* store the word in the next note */
		while (s && (s.type != NOTE || s.grace))
		while (s && (s.type != C.NOTE || s.grace))
			s = s.next
		if (!s) {
			syntax(1, "Too many words in lyric line")
			return
		}
		if (word
		 && s.pos.voc != SL_HIDDEN) {
		 && s.pos.voc != C.SL_HIDDEN) {
			if (word.match(/^\$\d/)) {
				if (word[1] == '0')
					set_font("vocal")
				else
					set_font("u" + word[1]);
				word = word.slice(2)
			}
			ly = {
				t: word,
				font: gene.curfont,
				w: strwh(word)[0],
				wh: strwh(word),
				istart: j,
				iend: j + word.length
			}
			if (!s.a_ly)
				s.a_ly = []
			s.a_ly[curvoice.lyric_line] = ly
		}
︙
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
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







-
+


-
+







-
+




-
+







		if (!ly)
			continue
		p = ly.t;
		if (p == "-\n" || p == "_\n") {
			ly.shift = 0
			continue
		}
		w = ly.w;
		w = ly.wh[0];
		swfac = ly.font.swfac;
		xx = w + 2 * cwid(' ') * swfac
		if (s.type == GRACE) {			// %%graceword
		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 = cwid('(') * swfac
			} else {
				j = p.indexOf(' ');
				j = p.indexOf(' ');	// (&nbsp;)
				set_font(ly.font)
				if (j > 0)
					sz = strwh(p.slice(0, j))[0]
				else
					sz = w
					sz = w * .2
			}
			shift = (w - sz + 2 * cwid(' ') * swfac) * .4
			if (shift > 20)
				shift = 20;
			shift += sz
			if (ly.t[0] >= '0' && ly.t[0] <= '9') {
				if (shift > align)
︙
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
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







-
-
-
+
+
+
-









-
-
-
+
+
+







			wlw = shift;
//		if (p[p.length - 1] == "\n")		// if "xx-"
//			xx -= cwid(' ') * swfac
		xx -= shift;
		shift = 2 * cwid(' ') * swfac
		for (k = s.next; k; k = k.next) {
			switch (k.type) {
			case NOTE:
			case REST:
				if (!k.a_ly || !k.a_ly[i]
			case C.NOTE:
			case C.REST:
				if (!k.a_ly || !k.a_ly[i])
				 || k.a_ly[i].w == 0)
					xx -= 9
				else if (k.a_ly[i].t == "-\n"
				      || k.a_ly[i].t == "_\n")
					xx -= shift
				else
					break
				if (xx <= 0)
					break
				continue
			case CLEF:
			case METER:
			case KEY:
			case C.CLEF:
			case C.METER:
			case C.KEY:
				xx -= 10
				continue
			default:
				xx -= 5
				break
			}
			break
︙
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
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







-
-
+
+










-
-
+
+











-
+







		hyflag, lflag, x0, font, shift

	if (p_voice.hy_st & (1 << j)) {
		hyflag = true;
		p_voice.hy_st &= ~(1 << j)
	}
	for (s = p_voice.sym; /*s*/; s = s.next)
		if (s.type != CLEF
		 && s.type != KEY && s.type != METER)
		if (s.type != C.CLEF
		 && s.type != C.KEY && s.type != C.METER)
			break
	lastx = s.prev ? s.prev.x : tsfirst.x;
	x0 = 0
	for ( ; s; s = s.next) {
		if (s.a_ly)
			ly = s.a_ly[j]
		else
			ly = null
		if (!ly) {
			switch (s.type) {
			case REST:
			case MREST:
			case C.REST:
			case C.MREST:
				if (lflag) {
					out_wln(lastx + 3, y, x0 - lastx);
					lflag = false;
					lastx = s.x + s.wr
				}
			}
			continue
		}
		if (ly.font != gene.curfont)		/* font change */
			gene.curfont = font = ly.font;
		p = ly.t;
		w = ly.w;
		w = ly.wh[0];
		shift = ly.shift
		if (hyflag) {
			if (p == "_\n") {		/* '_' */
				p = "-\n"
			} else if (p != "-\n") {	/* not '-' */
				out_hyph(lastx, y, s.x - shift - lastx);
				hyflag = false;
︙
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
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







-
+















-
+







				ymn: y,
				ymx: y + gene.curfont.size,
				wl: 0,
				wr: w
			}
			anno_start(s2, 'lyrics')
		}
		xy_str(x0, y, p);
		xy_str(x0, y, p, null, null, ly.wh);
		anno_stop(s2, 'lyrics')
		lastx = x0 + w
	}
	if (hyflag) {
		hyflag = false;
		x0 = realwidth - 10
		if (x0 < lastx + 10)
			x0 = lastx + 10;
		out_hyph(lastx, y, x0 - lastx)
		if (cfmt.hyphencont)
			p_voice.hy_st |= (1 << j)
	}

	/* see if any underscore in the next line */
	for (p_voice.s_next ; s; s = s.next) {
		if (s.type == NOTE) {
		if (s.type == C.NOTE) {
			if (!s.a_ly)
				break
			ly = s.a_ly[j]
			if (ly && ly.t == "_\n") {
				lflag = true;
				x0 = realwidth - 15
				if (x0 < lastx + 12)
︙
530
531
532
533
534
535
536
537

538
539

540
541
542
543
544
545
546
529
530
531
532
533
534
535

536
537

538
539
540
541
542
543
544
545







-
+

-
+







				if (!a_ly)
					continue
/*fixme:should get the real width*/
				x = s.x;
				w = 10
				for (i = 0; i < a_ly.length; i++) {
					ly = a_ly[i]
					if (ly && ly.w != 0) {
					if (ly) {
						x -= ly.shift;
						w = ly.w
						w = ly.wh[0]
						break
					}
				}
				y = y_get(p_voice.st, 1, x, w)
				if (top < y)
					top = y;
				y = y_get(p_voice.st, 0, x, w)
︙
569
570
571
572
573
574
575
576

577
578
579
580
581
582
583
568
569
570
571
572
573
574

575
576
577
578
579
580
581
582







-
+







			lyst_tb[st] = {}
		lyst_tb[st].top = top;
		lyst_tb[st].bot = bot;
		nly_tb[v] = nly
		if (nly == 0)
			continue
		if (p_voice.pos.voc)
			above_tb[v] = p_voice.pos.voc == SL_ABOVE
			above_tb[v] = p_voice.pos.voc == C.SL_ABOVE
		else if (voice_tb[v + 1]
/*fixme:%%staves:KO - find an other way..*/
		      && voice_tb[v + 1].st == st
		      && voice_tb[v + 1].have_ly)
			above_tb[v] = true
		else
			above_tb[v] = false
︙
Changes to core/modules.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - modules.js - module handling
//
// Copyright (C) 2018 Jean-Francois Moine
// Copyright (C) 2018-2019 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.
︙
26
27
28
29
30
31
32

33
34
35

36

37

38

39
40
41
42
43
44
45
46
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

42

43
44
45
46
47
48
49







+



+

+

+
-
+
-







		ambitus: { fn: 'ambitus-1.js' },
		beginps: { fn: 'psvg-1.js' },
		break: { fn: 'break-1.js' },
		capo: { fn: 'capo-1.js' },
		clip: { fn: 'clip-1.js' },
		voicecombine: { fn: 'combine-1.js' },
		diagram: { fn: 'diag-1.js' },
	equalbars: { fn: 'equalbars-1.js' },
		grid: { fn: 'grid-1.js' },
		grid2: { fn: 'grid2-1.js' },
		MIDI: { fn: 'MIDI-1.js' },
	pageheight: { fn: 'page-1.js' },
		percmap: { fn: 'perc-1.js' },
	soloffs: { fn: 'soloffs-1.js' },
	sth: { fn: 'sth-1.js' },
	temperament: { fn: 'temper-1.js' },
	all_m: new RegExp("ambitus|beginps|break|capo|clip|voicecombine|diagram|\

grid2|grid|MIDI|percmap|sth", 'g'),
	nreq: 0,
	hooks: [],
	g_hooks: [],

	// scan the file and find the required modules
	// @file: ABC file
	// @relay: (optional) callback function for continuing the treatment
︙
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
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







-
-
+
+
+

-
-
+
+
-




-
-
-
+
+
+
-
-
-
-
-







				return function(m) { alert(m) }
			if (typeof console == 'object')
				return console.log
			return function(){}
		}

		// test if some keyword in the file
	    var	m, r, nreq_i,
		all = file.match(this.all_m)
	    var	m, r,
		nreq_i = this.nreq,
		ls = file.match(/(^|\n)(%%|I:).+?\b/g)

		if (!all)
			return true;
		if (!ls)
			return true
		nreq_i = this.nreq;
		this.cbf = relay ||		// (only one callback function)
			function(){}
		this.errmsg = errmsg || get_errmsg()

		for (var i = 0; i < all.length; i++) {
			m = abc2svg.modules[all[i]]
			if (m.loaded)
		for (var i = 0; i < ls.length; i++) {
			m = abc2svg.modules[ls[i].replace(/\n?(%%|I:)/, '')]
			if (!m || m.loaded)
				continue

			// check if really a command
			r = new RegExp('(^|\\n)(%.|I:|\\[) *' + all[i] + '\\s')
			if (!r.test(file))
				continue

			m.loaded = true

			// load the module
				this.nreq++;
				abc2svg.loadjs(m.fn,
︙
Changes to core/music.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - music.js - music generation
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-2019 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
33
19
20
21
22
23
24
25

26
27
28
29
30
31
32
33







-
+








var	gene,
	staff_tb,
	nstaff,			// current number of staves
	tsnext,			// next line when cut
	realwidth,		// real staff width while generating
	insert_meter,		// insert time signature (1) and indent 1st line (2)
	beta_last,		// for last short short line..
	spf_last,		// spacing for last short line

/* width of notes indexed by log2(note_length) */
	space_tb = new Float32Array([
		7, 10, 14.15, 20, 28.3,
		40,			/* crotchet (whole note / 4) */
		56.6, 80, 100, 120
	]),
︙
114
115
116
117
118
119
120
121

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

121
122
123
124
125
126
127
128







-
+







				if (dx_max < -dx)
					dx_max = -dx
				continue
			}
		}
		if (d < 0)
			d = -d
		if (d > 3 || (d >= 2 && s.head != SQUARE)) {
		if (d > 3 || (d >= 2 && s.head != C.SQUARE)) {
			shift = false
		} else {
			shift = !shift
			if (shift) {
				s.notes[i].shhd = dx
				if (dx_max < dx)
					dx_max = dx
︙
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
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







-
+









-
+

















-
-
+
+







/* this routine is called only once per tune */
function set_acc_shft() {
	var s, s2, st, i, acc, st, t, dx_head;

	// search the notes with accidentals at the same time
	s = tsfirst
	while (s) {
		if (s.type != NOTE
		if (s.type != C.NOTE
		 || s.invis) {
			s = s.ts_next
			continue
		}
		st = s.st;
		t = s.time;
		acc = false
		for (s2 = s; s2; s2 = s2.ts_next) {
			if (s2.time != t
			 || s2.type != NOTE
			 || s2.type != C.NOTE
			 || s2.st != st)
				break
			if (acc)
				continue
			for (i = 0; i <= s2.nhd; i++) {
				if (s2.notes[i].acc) {
					acc = true
					break
				}
			}
		}
		if (!acc) {
			s = s2
			continue
		}

		dx_head = dx_tb[s.head]
//		if (s.dur >= BASE_LEN * 2 && s.head == OVAL)
//		if (s.dur >= BASE_LEN * 2)
//		if (s.dur >= C.BLEN * 2 && s.head == C.OVAL)
//		if (s.dur >= C.BLEN * 2)
//			dx_head = 15.8;

		// build a pseudo chord and shift the accidentals
		st = {
			notes: []
		}
		for ( ; s != s2; s = s.ts_next)
︙
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
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







-
+
+
+
+
+



+


















-
+
+







-
+


















-
+







	if (s.next)
		s.next.prev = s.prev
	if (s.prev)
		s.prev.next = s.next
	else
		s.p_v.sym = s.next
	if (s.ts_next) {
		if (s.seqst && !s.ts_next.seqst) {
		if (s.seqst) {
		    if (s.ts_next.seqst) {
			s.ts_next.shrink += s.shrink;
			s.ts_next.space += s.space
		    } else {
			s.ts_next.seqst = true;
			s.ts_next.shrink = s.shrink;
			s.ts_next.space = s.space
		    }
		}
		s.ts_next.ts_prev = s.ts_prev
	}
	if (s.ts_prev)
		s.ts_prev.ts_next = s.ts_next
	if (tsfirst == s)
		tsfirst = s.ts_next
	if (tsnext == s)
		tsnext = s.ts_next
}

/* -- insert a clef change (treble or bass) before a symbol -- */
function insert_clef(s, clef_type, clef_line) {
	var	p_voice = s.p_v,
		new_s,
		st = s.st

	/* don't insert the clef between two bars */
	if (s.type == BAR && s.prev && s.prev.type == BAR)
	if (s.type == C.BAR && s.prev && s.prev.type == C.BAR
	 && s.prev.bar_type[0] != ':')
		s = s.prev;

	/* create the symbol */
	p_voice.last_sym = s.prev
	if (!p_voice.last_sym)
		p_voice.sym = null;
	p_voice.time = s.time;
	new_s = sym_add(p_voice, CLEF);
	new_s = sym_add(p_voice, C.CLEF);
	new_s.next = s;
	s.prev = new_s;

	new_s.clef_type = clef_type;
	new_s.clef_line = clef_line;
	new_s.st = st;
	new_s.clef_small = true
	delete new_s.second;
	new_s.notes = []
	new_s.notes[0] = {
		pit: s.notes[0].pit
	}
	new_s.nhd = 0;

	/* link in time */
	while (!s.seqst)
		s = s.ts_prev;
	lktsym(new_s, s)
	if (new_s.ts_prev.type != CLEF)
	if (new_s.ts_prev.type != C.CLEF)
		new_s.seqst = true
	return new_s
}

/* -- set the staff of the floating voices -- */
/* this function is called only once per tune */
function set_float() {
︙
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
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







-
+

















-
+







				continue
			}
			up = 127
			for (s1 = s.ts_prev; s1; s1 = s1.ts_prev) {
				if (s1.st != st
				 || s1.v == s.v)
					break
				if (s1.type == NOTE)
				if (s1.type == C.NOTE)
				    if (s1.notes[0].pit < up)
					up = s1.notes[0].pit
			}
			if (up == 127) {
				if (staff_chg)
					s.st++
				continue
			}
			if (s.notes[s.nhd].pit > up - 3) {
				staff_chg = false
				continue
			}
			down = -127
			for (s1 = s.ts_next; s1; s1 = s1.ts_next) {
				if (s1.st != st + 1
				 || s1.v == s.v)
					break
				if (s1.type == NOTE)
				if (s1.type == C.NOTE)
				    if (s1.notes[s1.nhd].pit > down)
					down = s1.notes[s1.nhd].pit
			}
			if (down == -127) {
				if (staff_chg)
					s.st++
				continue
︙
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
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
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
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

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


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







-
-
-
-
+
+
+
+
-

+
+
+
+










-
-
+
+














-
+


-
+

-
-
+
+


-


-
+

-
+

-
-
+
+

+


-
+


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




-
-
-
-
-
-
-
-


-
-
+
+








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







+

-
+
+


-
-
+
+













-
-
-
-
+
+
+
+











-
+







-
-
-
-
+
+
+
+



+
+














-
+


-
+


-
-
+
+


-
+


















-
+


















-
+





-
-
+
+















-
+




-
+








-
+


-
-
+
-


-
-
-
-
-
+

-
-
-

-
-
-
+















-
+








-
+




-
-
-
+










-
+





+
-
+

-
+
-
-







			s.st++
		}
	}
}

/* -- set the x offset of the grace notes -- */
function set_graceoffs(s) {
	var	next, m, dx,
		gspleft = Number(cfmt.gracespace[0]),
		gspinside = Number(cfmt.gracespace[1]),
		gspright = Number(cfmt.gracespace[2]),
	var	next, m, dx, x,
		gspleft = cfmt.gracespace[0],
		gspinside = cfmt.gracespace[1],
		gspright = cfmt.gracespace[2],
		xx = 0,
		g = s.extra;

	if (s.prev && s.prev.type == C.BAR)
		gspleft -= 3;
	x = gspleft;

	g.beam_st = true
	for ( ; ; g = g.next) {
		set_head_shift(g)
		acc_shift(g.notes, 7);
		dx = 0
		for (m = g.nhd; m >= 0; m--) {
			if (g.notes[m].shac > dx)
				dx = g.notes[m].shac
		}
		xx += dx;
		g.x = xx
		x += dx;
		g.x = x

		if (g.nflags <= 0) {
			g.beam_st = true;
			g.beam_end = true
		}
		next = g.next
		if (!next) {
			g.beam_end = true
			break
		}
		if (next.nflags <= 0)
			g.beam_end = true
		if (g.beam_end) {
			next.beam_st = true;
			xx += gspinside / 4
			x += gspinside / 4
		}
		if (g.nflags <= 0)
			xx += gspinside / 4
			x += gspinside / 4
		if (g.y > next.y + 8)
			xx -= 1.5
		xx += gspinside
			x -= 1.5
		x += gspinside
	}

	xx += gspleft + gspright;
	next = s.next
	if (next
	 && next.type == NOTE) {	/* if before a note */
	 && next.type == C.NOTE) {	/* if before a note */
		if (g.y >= 3 * (next.notes[next.nhd].pit - 18))
			xx -= 1		/* above, a bit closer */
			gspright -= 1		// above, a bit closer
		else if (g.beam_st
		      && g.y < 3 * (next.notes[0].pit - 18) - 7)
			xx += 2		/* below with flag, a bit further */
		      && g.y < 3 * (next.notes[next.nhd].pit - 18) - 4)
			gspright += 2		// below with flag, a bit further
	}
	x += gspright;

	/* return the whole width */
	return xx
	return x
}

/* -- compute the width needed by the guitar chords / annotations -- */
function gchord_width(s, wlnote, wlw) {
	var	s2, gch, w, wl, ix,
		lspc = 0,
		rspc = 0,
		alspc = 0,
		arspc = 0
// Compute the smallest spacing between symbols according to chord symbols
//	so that they stay at the same offset.
// Constraints:
// - assume the chord symbols are only in the first staff
// - treat only the first chord symbol of each symbol
// - the chord symbol under the staff are ignored
function set_w_chs(s) {
    var	i, ch, ch0, s0, dw, x,
	n = 0

	for ( ; s; s = s.ts_next) {
		if (s.shrink) {
			x += s.shrink;
			n++
		}
		if (!s.a_gch)
			continue
		for (i = 0; i < s.a_gch.length; i++) {
			ch = s.a_gch[i]
			if (ch.type != 'g' || ch.y < 0) // upper chord symbol only
				continue
			if (ch0) {
				if (ch0.w > x + ch.x) {
					dw = (ch0.w - x - ch.x) / n
					while (1) {
						s0 = s0.ts_next
						if (s0.shrink)
							s0.shrink += dw
						if (s0 == s)
							break
					}
				}
			}
			s0 = s;
			ch0 = ch;
			n = 0;
//			x = ch.box ? -2 : 0
			x = 0
			break
		}
	}
}

// compute the width needed by the left and right annotations
function gchord_width(s, wlnote, wlw) {
    var	gch, w, ix,
	arspc = 0

	for (ix = 0; ix < s.a_gch.length; ix++) {
		gch = s.a_gch[ix]
		switch (gch.type) {
		default:		/* default = above */
			wl = -gch.x
			if (wl > lspc)
				lspc = wl;
			w = gch.w + 2 - wl
			if (w > rspc)
				rspc = w
			break
		case '<':		/* left */
			w = gch.w + wlnote
			if (w > alspc)
				alspc = w
			if (w > wlw)
				wlw = w
			break
		case '>':		/* right */
			w = gch.w + s.wr
			if (w > arspc)
				arspc = w
			break
		}
	}

	/* adjust width for no clash */
	s2 = s.prev
	if (s2) {
		if (s2.a_gch) {
			for (s2 = s.ts_prev; ; s2 = s2.ts_prev) {
				if (s2 == s.prev) {
					if (wlw < lspc)
						wlw = lspc
					break
				}
				if (s2.seqst)
					lspc -= s2.shrink
			}
		}
		if (alspc != 0)
			if (wlw < alspc)
				wlw = alspc
	}
	s2 = s.next
	if (s2) {
		if (s2.a_gch) {
			for (s2 = s.ts_next; ; s2 = s2.ts_next) {
				if (s2 == s.next) {
					if (s.wr < rspc)
						s.wr = rspc
					break
				}
				if (s2.seqst)
					rspc -= 8
			}
		}
		if (arspc != 0)
			if (s.wr < arspc)
				s.wr = alspc
	}
	if (s.wr < arspc)
		s.wr = arspc

	return wlw
}

/* -- set the width of a symbol -- */
/* This routine sets the minimal left and right widths wl,wr
 * so that successive symbols are still separated when
 * no extra glue is put between them */
// (possible hook)
function set_width(s) {
	var s2, i, m, xx, w, wlnote, wlw, acc
    var	s2, i, m, xx, w, wlnote, wlw, acc,
	bar_type, meter, last_acc, n1, n2, esp, tmp

	switch (s.type) {
	case NOTE:
	case REST:
	case C.NOTE:
	case C.REST:

		/* set the note widths */
		s.wr = wlnote = hw_tb[s.head]

		/* room for shifted heads and accidental signs */
		if (s.xmx > 0)
			s.wr += s.xmx + 4;
		for (s2 = s.prev; s2; s2 = s2.prev) {
			if (w_tb[s2.type] != 0)
				break
		}
		if (s2) {
			switch (s2.type) {
			case BAR:
			case CLEF:
			case KEY:
			case METER:
			case C.BAR:
			case C.CLEF:
			case C.KEY:
			case C.METER:
				wlnote += 3
				break
			}
		}
		for (m = 0; m <= s.nhd; m++) {
			xx = s.notes[m].shhd
			if (xx < 0) {
				if (wlnote < -xx + 5)
					wlnote = -xx + 5
			}
			if (s.notes[m].acc) {
				var tmp = s.notes[m].shac +
				tmp = s.notes[m].shac +
					(s.notes[m].micro ? 5.5 : 3.5)
				if (wlnote < tmp)
					wlnote = tmp
			}
		}
		if (s2) {
			switch (s2.type) {
			case BAR:
			case CLEF:
			case KEY:
			case METER:
			case C.BAR:
			case C.CLEF:
			case C.KEY:
			case C.METER:
				wlnote -= 3
				break
			}
		} else {
			wlnote += 8		// (start of tune)
		}

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

		/* leave room for dots and set their offset */
		if (s.dots > 0) {
		if (s.dots) {
		  if (s.wl == undefined)	// don't recompute if new music line
			switch (s.head) {
			case SQUARE:
			case C.SQUARE:
				s.xmx += 4
				break
			case OVALBARS:
			case OVAL:
			case C.OVALBARS:
			case C.OVAL:
				s.xmx += 2
				break
			case EMPTY:
			case C.EMPTY:
				s.xmx += 1
				break
			}
			if (s.wr < s.xmx + 8)
				s.wr = s.xmx + 8
			if (s.dots >= 2)
				s.wr += 3.5 * (s.dots - 1)
		}

		/* if a tremolo on 2 notes, have space for the small beam(s) */
		if (s.trem2 && s.beam_end
		 && wlnote < 20)
			wlnote = 20

		wlw = wlnote

		if (s2) {
			switch (s2.type) {
			case NOTE:	/* extra space when up stem - down stem */
			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
				}

				/* have ties wide enough */
				if (s2.ti1) {
					if (wlw < 14)
						wlw = 14
				}
				break
			case CLEF:		/* extra space at start of line */
			case C.CLEF:		/* extra space at start of line */
				if (s2.second
				 || s2.clef_small)
					break
				wlw += 8
				break
			case KEY:
/*			case METER:	*/
			case C.KEY:
/*			case C.METER:	*/
				wlw += 4
				break
			}
		}

		/* leave room for guitar chord */
		if (s.a_gch)
			wlw = gchord_width(s, wlnote, wlw)

		/* leave room for vocals under note */
		/* related to draw_lyrics() */
		if (s.a_ly)
			wlw = ly_width(s, wlw)

		/* if preceeded by a grace note sequence, adjust */
		if (s2 && s2.type == GRACE)
		if (s2 && s2.type == C.GRACE)
			s.wl = wlnote - 4.5
		else
			s.wl = wlw
		return
	case SPACE:
	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 BAR:
	case C.BAR:
		if (s.norepbra)
			break
		if (!s.invis) {
			var bar_type = s.bar_type
		bar_type = s.bar_type

			switch (bar_type) {
			case "|":
				w = 7		// 4 + 3
				break
			case "|:":
			case ":|":
				w = 15		// 4 + 5 + 6
				w = 5		// 3 + 2
				break
			case "::":
				w = 26		// 4 + 5 + 6 + 6 + 5
				break
			default:
				if (!bar_type)
					break
				w = 4 + 3 * bar_type.length
				w = 2 + 2.8 * bar_type.length
				for (i = 0; i < bar_type.length; i++) {
					switch (bar_type[i]) {
					case "[":
					case "]":
						w += 3
						break
					case ":":
						w += 2
						break
					}
				}
				break
			}
			s.wl = w
			if (s.next
			 && s.next.type != METER)
			 && 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 */
			for (s2 = s.prev; s2; s2 = s2.prev) {
				if (w_tb[s2.type] != 0) {
					if (s2.type == GRACE)
					if (s2.type == C.GRACE)
						s.wl -= 8
					break
				}
			}
		} else {
			s.wl = s.wr = 0
		}

		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
		}
		return
	case CLEF:
	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 ? 9 : 12
		s.wl = s.wr = s.clef_small ? 8 : 12
		s.wr = s.clef_small ? 7 : 12
		return
	case KEY:
	case C.KEY:
		var n1, n2, esp;

		s.wl = 3;
		esp = 4
		if (!s.k_a_acc) {
			n1 = s.k_sf			/* new key sig */
			if (s.k_old_sf && (cfmt.cancelkey || n1 == 0))
				n2 = s.k_old_sf	/* old key */
			else
︙
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
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







-
+












-
+



-
-
+
+
+
+
+


+
-
+
+
+
+
+







				if (n1 < 0)
					n1 = -n1;
				esp += 3	/* see extra space in draw_keysig() */
			}
		} else {
			n1 = n2 = s.k_a_acc.length
			if (n2)
			    var	last_acc = s.k_a_acc[0].acc
				last_acc = s.k_a_acc[0].acc
			for (i = 1; i < n2; i++) {
				acc = s.k_a_acc[i]
				if (acc.pit > s.k_a_acc[i - 1].pit + 6
				 || acc.pit < s.k_a_acc[i - 1].pit - 6)
					n1--		// no clash
				else if (acc.acc != last_acc)
					esp += 3;
				last_acc = acc.acc
			}
		}
		s.wr = 5.5 * n1 + esp
		return
	case METER:
	case C.METER:
		wlw = 0;
		s.x_meter = []
		for (i = 0; i < s.a_meter.length; i++) {
			var meter = s.a_meter[i]
			if (meter.top[0] == "C") {
			meter = s.a_meter[i]
			switch (meter.top[0]) {
			case 'C':
			case 'c':
			case 'o':
				s.x_meter[i] = wlw + 6;
				wlw += 12
				break
			} else {
			case '.':
			case '|':
				s.x_meter[i] = s.x_meter[i - 1]
				break
			default:
				w = 0
				if (!meter.bot
				 || meter.top.length > meter.bot.length)
					meter = meter.top
				else
					meter = meter.bot;
				for (m = 0; m < meter.length; m++) {
︙
837
838
839
840
841
842
843
844

845
846
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
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
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
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
1046
1047

1048
1049

1050
1051
1052
1053



1054
1055

1056
1057
1058
1059

1060
1061
1062


1063
1064
1065

























1066
1067



1068




1069
1070








1071
1072
1073
1074
1075

1076
1077
1078
1079
1080
1081
1082
843
844
845
846
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
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
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
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
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
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
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
1156
1157
1158



1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183


1184
1185
1186
1187
1188
1189
1190
1191


1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203

1204
1205
1206
1207
1208
1209
1210
1211







-
+



-
+





-
+

-
+






-
+


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







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



-
+





-
+


-
-
-
+
+
+








-
+



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


-
+


-
+

-
-
-
-
-
+
+
+
+
+














-
+






-
+









-
+












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


-
-
+
+















-
-
+
+
+
+
+

+
+





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



-
+
-
-

+
+
-
-
+
+
+
+
+
+
+



-
+

-
+

-
-
-
+
+
+
-
-
+



-
+



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

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




-
+







				s.x_meter[i] = wlw + w / 2
				wlw += w
			}
		}
		s.wl = 0;
		s.wr = wlw + 6
		return
	case MREST:
	case C.MREST:
		s.wl = 6;
		s.wr = 66
		return
	case GRACE:
	case C.GRACE:
		s.wl = set_graceoffs(s);
		s.wr = 0
		if (s.a_ly)
			ly_width(s, wlw)
		return
	case STBRK:
	case C.STBRK:
		s.wl = s.xmx
		if (s.next && s.next.type == CLEF) {
		if (s.next && s.next.type == C.CLEF) {
			s.wr = 2
			delete s.next.clef_small	/* big clef */
		} else {
			s.wr = 8
		}
		return
	case CUSTOS:
	case C.CUSTOS:
		s.wl = s.wr = 4
		return
	case C.TEMPO:		// no width, but set here the [w,h] of the strings
		set_font("tempo")
		if (s.tempo_str1)
			s.tempo_wh1 = strwh(s.tempo_str1)
		if (s.tempo_notes ) {
			s.tempo_str0 = '= '
			if (s.tempo_ca)
				s.tempo_str0 += s.tempo_ca
			if (s.tempo)
				s.tempo_str0 += s.tempo;
			s.tempo_wh0 = strwh(s.tempo_str0)
		}
		if (s.tempo_str2)
			s.tempo_wh2 = strwh(s.tempo_str2)
		break
	case BLOCK:				// no width
	case PART:
	case REMARK:
	case STAVES:
	case C.BLOCK:				// no width
	case C.PART:
	case C.REMARK:
	case C.STAVES:
	case TEMPO:
		break
	default:
		error(2, s, "set_width - Cannot set width for symbol $1", s.type)
		break
	}
	s.wl = s.wr = 0
}

// convert delta time to natural spacing
function time2space(s, len) {
    var i, l, space

	if (smallest_duration >= C.BLEN / 2) {
		if (smallest_duration >= C.BLEN)
			len /= 4
		else
			len /= 2
	} else if (!s.next && len >= C.BLEN) {
		len /= 2
	}
	if (len >= C.BLEN / 4) {
		if (len < C.BLEN / 2)
			i = 5
		else if (len < C.BLEN)
			i = 6
		else if (len < C.BLEN * 2)
			i = 7
		else if (len < C.BLEN * 4)
			i = 8
		else
			i = 9
	} else {
		if (len >= C.BLEN / 8)
			i = 4
		else if (len >= C.BLEN / 16)
			i = 3
		else if (len >= C.BLEN / 32)
			i = 2
		else if (len >= C.BLEN / 64)
			i = 1
		else
			i = 0
	}
	l = len - ((C.BLEN / 16 / 8) << i)
	space = space_tb[i]
	if (l != 0) {
		if (l < 0) {
			space = space_tb[0] * len / (C.BLEN / 16 / 8)
		} else {
			if (i >= 9)
				i = 8
			space += (space_tb[i + 1] - space_tb[i]) * l / len
		}
	}
	return space
}

/* -- set the natural space -- */
function set_space(s) {
	var	s2, i, l, space,
	var	s2, space,
		prev_time = s.ts_prev.time,
		len = s.time - prev_time		/* time skip */

	if (len == 0) {
		switch (s.type) {
		case MREST:
		case C.MREST:
			return s.wl
///*fixme:do same thing at start of line*/
//		case NOTE:
//		case REST:
//			if (s.ts_prev.type == BAR) {
//		case C.NOTE:
//		case C.REST:
//			if (s.ts_prev.type == C.BAR) {
//				if (s.nflags < -2)
//					return space_tb[0]
//				return space_tb[2]
//			}
//			break
		}
		return 0
	}
	if (s.ts_prev.type == MREST)
	if (s.ts_prev.type == C.MREST)
//		return s.ts_prev.wr + 16
//				+ 3		// (bar wl=5 wr=8)
		return 71	// 66 (mrest.wl) + 5 (bar.wl)
	if (smallest_duration >= BASE_LEN / 2) {
		if (smallest_duration >= BASE_LEN)
			len /= 4
		else
			len /= 2
	} else if (!s.next && len >= BASE_LEN) {
		len /= 2
	}

	if (len >= BASE_LEN / 4) {
		if (len < BASE_LEN / 2)
			i = 5
		else if (len < BASE_LEN)
			i = 6
		else if (len < BASE_LEN * 2)
			i = 7
		else if (len < BASE_LEN * 4)
			i = 8
		else
			i = 9
	} else {
		if (len >= BASE_LEN / 8)
			i = 4
		else if (len >= BASE_LEN / 16)
			i = 3
		else if (len >= BASE_LEN / 32)
			i = 2
		else if (len >= BASE_LEN / 64)
			i = 1
		else
			i = 0
	}
	l = len - ((BASE_LEN / 16 / 8) << i)
	space = space_tb[i]
	space = time2space(s, len)
	if (l != 0) {
		if (l < 0) {
			space = space_tb[0] * len / (BASE_LEN / 16 / 8)
		} else {
			if (i >= 9)
				i = 8
			space += (space_tb[i + 1] - space_tb[i]) * l / len
		}

	}
	while (!s.dur) {
		switch (s.type) {
		case BAR:
		case C.BAR:
			// (hack to have quite the same note widths between measures)
			return space * .9 - 7
		case CLEF:
		case C.CLEF:
			return space - s.wl - s.wr
		case BLOCK:			// no space
		case PART:
		case REMARK:
		case STAVES:
		case TEMPO:
		case C.BLOCK:			// no space
		case C.PART:
		case C.REMARK:
		case C.STAVES:
		case C.TEMPO:
			s = s.ts_next
			if (!s)
				return space
			continue
		}
		break
	}

	/* reduce spacing within a beam */
	if (!s.beam_st)
		space *= .9			// ex fnnp

	/* decrease spacing when stem down followed by stem up */
/*fixme:to be done later, after x computed in sym_glue*/
	if (s.type == NOTE && s.nflags >= -1
	if (s.type == C.NOTE && s.nflags >= -1
	 && s.stem > 0) {
		var stemdir = true

		for (s2 = s.ts_prev;
		     s2 && s2.time == prev_time;
		     s2 = s2.ts_prev) {
			if (s2.type == NOTE
			if (s2.type == C.NOTE
			 && (s2.nflags < -1 || s2.stem > 0)) {
				stemdir = false
				break
			}
		}
		if (stemdir) {
			for (s2 = s.ts_next;
			     s2 && s2.time == s.time;
			     s2 = s2.ts_next) {
				if (s2.type == NOTE
				if (s2.type == C.NOTE
				 && (s2.nflags < -1 || s2.stem < 0)) {
					stemdir = false
					break
				}
			}
			if (stemdir)
				space *= .9
		}
	}
	return space
}

// set a fixed spacing inside tuplets
function set_sp_tup(s, s_et) {
    var	s2,
	tim = s.time,
	endtime = s_et.time + s_et.dur,
	ttim = endtime - tim,
	space = time2space(s, ttim / s.tq0) * s.tq0 / ttim

	// start on the second note/rest
	do {
		s = s.ts_next
	} while (!s.seqst)
//fixme: problem when BAR inside the tuplet sequence (in case user error)
//	while (!s.dur)
//		s = s.ts_next
//	while (!s.seqst)
//		s = s.ts_prev

	// stop outside the tuplet sequence
	// and add a measure bar when at end of tune
	do {
		if (!s_et.ts_next) {
			s2 = add_end_bar(s_et);
			s_et = s2
		} else {
			s_et = s_et.ts_next
		}
	} while (!s_et.seqst)

	// check the minimum spacing
	s2 = s
	while (1) {
		if (s2.dur
		 && s2.dur * space < s2.shrink)
			space = s2.shrink / s2.dur
		if (s2 == s_et)
			break
		s2 = s2.ts_next
	}

	// set the space values
	while (1) {
		if (s.seqst) {
			s.space = (s.time - tim) * space;
			tim = s.time
		}
		if (s == s_et)
			break
		s = s.ts_next
	}
}

// create an invisible bar for end of music lines
function add_end_bar(s) {
	return {
		type: BAR,
    var bar = {
		type: C.BAR,
		bar_type: "|",
		fname: s.fname,
		istart: s.istart,
		iend: s.iend,
		v: s.v,
		p_v: s.p_v,
		st: s.st,
		dur: 0,
		seqst: true,
		invis: true,
		time: s.time + s.dur,
		nhd: 0,
		notes: [{
			pit: s.notes[0].pit
		}],
		wl:0,
		wr:0
		wl: 0,
		wr: 0,
		prev: s,
		ts_prev: s,
		shrink: s.wr + 3
	}
	s.next = s.ts_next = bar
	return bar
}

/* -- set the width and space of all symbols -- */
/* this function is called once for the whole tune
 * then, once per music line up to the first sequence */
function set_allsymwidth(last_s) {
	var	new_val,
		s = tsfirst,
		xa = 0,
		xl = []
function set_allsymwidth() {
    var	maxx, new_val, s_tupc, s_tupn, st, s_chs,
	s = tsfirst,
	s2 = s,
	xa = 0,
	xl = [],
	wr = [],
	ntup = 0

	/* loop on all symbols */
	while (1) {
		var	maxx = xa,
		maxx = xa
			s2 = s

		do {
			if (s.a_gch && !s_chs)
				s_chs = s;
			set_width(s);
			new_val = (xl[s.st] || 0) + s.wl
			self.set_width(s);
			st = s.st
			if (xl[st] == undefined)
				xl[st] = 0
			if (wr[st] == undefined)
				wr[st] = 0;
			new_val = xl[st] + wr[st] + s.wl
			if (new_val > maxx)
				maxx = new_val;
			s = s.ts_next
		} while (s != last_s && !s.seqst);
		} while (s && !s.seqst);

		/* set the spaces at start of sequence */
		// set the spaces of the time sequence
		s2.shrink = maxx - xa
		if (s2.ts_prev)
			s2.space = set_space(s2)
		else
		if (!ntup)			// if not inside a tuplet sequence
			s2.space = s2.ts_prev ? set_space(s2) : 0

			s2.space = 0
		if (s2.shrink == 0 && s2.space == 0 && s2.type == CLEF) {
		if (s2.shrink == 0 && s2.space == 0 && s2.type == C.CLEF) {
			delete s2.seqst;		/* no space */
			s2.time = s2.ts_prev.time
		}
		if (s == last_s)
		if (!s)
			break

		// update the min left space per staff
		for (st = 0; st < wr.length; st++)
			wr[st] = 0;
		xa = maxx;
		s = s2
		do {
		xa = maxx
		do {
			st = s2.st;
			xl[st] = xa
			if (s2.wr > wr[st])
				wr[st] = s2.wr
			if (s2.tp0		// start of tuplet
			 && ++ntup == 1
			 && !s_tupc)
				s_tupc = s2;	// keep the first tuplet address
			if (s2.te0)		// end of tuplet
				ntup--;
			s2 = s2.ts_next
		} while (!s2.seqst)
	}

	// let the chord symbols at the same offset
	if (s_chs)
		set_w_chs(s_chs)

	// adjust the spacing inside the tuplets
	s = s_tupc
	if (!s)
		return
	do {
			if (!xl[s.st] || xl[s.st] < xa + s.wr)
				xl[s.st] = xa + s.wr;
		s2 = s;			// start of tuplet
		ntup = 1
		do {			// search the end of the tuplet sequence
			s = s.ts_next
			if (s.tp0)
				ntup++
			if (s.te0)
				ntup--
		} while (!s.seqst)
	}
		} while (ntup != 0);

		set_sp_tup(s2, s)

		do {			// search next tuplet
			s = s.ts_next
		} while (s && !s.tp0)
	} while (s)
}

/* change a symbol into a rest */
function to_rest(s) {
	s.type = REST
	s.type = C.REST
// just keep nl and seqst
	delete s.in_tuplet
	delete s.sl1
	delete s.sl2
	delete s.a_dd
	delete s.a_gch
	s.slur_start = s.slur_end = 0
︙
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
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
1270
1271
1272







-
+

















-
+














-
+








	/* treat the sequence repeat */
	if (n < 0) {				/* number of notes / measures */
		n = -n;
		i = n				/* number of notes to repeat */
		for (s3 = s.prev; s3; s3 = s3.prev) {
			if (!s3.dur) {
				if (s3.type == BAR) {
				if (s3.type == C.BAR) {
					error(1, s3, "Bar in repeat sequence")
					return
				}
				continue
			}
			if (--i <= 0)
				break
		}
		if (!s3) {
			error(1, s, errs.not_enough_n)
			return
		}
		dur = s.time - s3.time;

		i = k * n		/* whole number of notes/rests to repeat */
		for (s2 = s; s2; s2 = s2.next) {
			if (!s2.dur) {
				if (s2.type == BAR) {
				if (s2.type == C.BAR) {
					error(1, s2, "Bar in repeat sequence")
					return
				}
				continue
			}
			if (--i <= 0)
				break
		}
		if (!s2
		 || !s2.next) {		/* should have some symbol */
			error(1, s, errs.not_enough_n)
			return
		}
		for (s2 = s.prev; s2 != s3; s2 = s2.prev) {
			if (s2.type == NOTE) {
			if (s2.type == C.NOTE) {
				s2.beam_end = true
				break
			}
		}
		for (j = k; --j >= 0; ) {
			i = n			/* number of notes/rests */
			if (s.dur)
︙
1152
1153
1154
1155
1156
1157
1158
1159

1160
1161
1162

1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176

1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194

1195
1196
1197
1198
1199
1200
1201
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







-
+


-
+













-
+

















-
+







				}
				s2 = s2.ts_next
			}
			to_rest(s);
			s.dur = s.notes[0].dur = dur;
			s.rep_nb = -1;		// single repeat
			s.beam_st = true;
			set_width(s)
			self.set_width(s)
			if (s.seqst)
				s.space = set_space(s);
			s.head = SQUARE;
			s.head = C.SQUARE;
			for (s = s2; s; s = s.ts_next) {
				if (s.st == st
				 && s.v == v
				 && s.dur)
					break
			}
		}
		return
	}

	/* check the measure repeat */
	i = n				/* number of measures to repeat */
	for (s2 = s.prev.prev ; s2; s2 = s2.prev) {
		if (s2.type == BAR
		if (s2.type == C.BAR
		 || s2.time == tsfirst.time) {
			if (--i <= 0)
				break
		}
	}
	if (!s2) {
		error(1, s, errs.not_enough_m)
		return
	}

	dur = s.time - s2.time		/* repeat duration */

	if (n == 1)
		i = k			/* repeat number */
	else
		i = n			/* check only 2 measures */
	for (s2 = s; s2; s2 = s2.next) {
		if (s2.type == BAR) {
		if (s2.type == C.BAR) {
			if (--i <= 0)
				break
		}
	}
	if (!s2) {
		error(1, s, errs.not_enough_m)
		return
︙
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
1270
1271
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
1392

1393
1394
1395
1396
1397
1398
1399
1400







-
+
















-
+






-
+














-
+







	dur /= n
	if (n == 2) {			/* repeat 2 measures (once) */
		s3 = s
		for (s2 = s.ts_next; ; s2 = s2.ts_next) {
			if (s2.st != st)
				continue
			if (s2.v == v
			 && s2.type == BAR)
			 && s2.type == C.BAR)
				break
			unlksym(s2)
		}
		to_rest(s3);
		s3.dur = s3.notes[0].dur = dur;
		s3.invis = true
		if (s3.seqst)
			s3.space = set_space(s3);
		s2.bar_mrep = 2
		if (s2.seqst)
			s2.space = set_space(s2);
		s3 = s2.next;
		for (s2 = s3.ts_next; ; s2 = s2.ts_next) {
			if (s2.st != st)
				continue
			if (s2.v == v
			 && s2.type == BAR)
			 && s2.type == C.BAR)
				break
			unlksym(s2)
		}
		to_rest(s3);
		s3.dur = s3.notes[0].dur = dur;
		s3.invis = true;
		set_width(s3)
		self.set_width(s3)
		if (s3.seqst)
			s3.space = set_space(s3)
		if (s2.seqst)
			s2.space = set_space(s2)
		return
	}

	/* repeat 1 measure */
	s3 = s
	for (j = k; --j >= 0; ) {
		for (s2 = s3.ts_next; ; s2 = s2.ts_next) {
			if (s2.st != st)
				continue
			if (s2.v == v
			 && s2.type == BAR)
			 && s2.type == C.BAR)
				break
			unlksym(s2)
		}
		to_rest(s3);
		s3.dur = s3.notes[0].dur = dur;
		s3.beam_st = true
		if (s3.seqst)
︙
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

1332
1333
1334
1335
1336

1337
1338
1339
1340
1341
1342
1343
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







-
+











-
+


















-
+






-
-
+
+

-
+




-
+








/* add a custos before the symbol of the next line */
function custos_add(s) {
	var	p_voice, new_s, i,
		s2 = s

	while (1) {
		if (s2.type == NOTE)
		if (s2.type == C.NOTE)
			break
		s2 = s2.next
		if (!s2)
			return
	}

	p_voice = s.p_v;
	p_voice.last_sym = s.prev;
//	if (!p_voice.last_sym)
//		p_voice.sym = null;
	p_voice.time = s.time;
	new_s = sym_add(p_voice, CUSTOS);
	new_s = sym_add(p_voice, C.CUSTOS);
	new_s.next = s;
	s.prev = new_s;
	lktsym(new_s, s);

	new_s.seqst = true;
	new_s.shrink = s.shrink
	if (new_s.shrink < 8 + 4)
		new_s.shrink = 8 + 4;
	new_s.space = s2.space;
	new_s.wl = 0;
	new_s.wr = 4;

	new_s.nhd = s2.nhd;
	new_s.notes = []
	for (i = 0; i < s.notes.length; i++) {
		new_s.notes[i] = {
			pit: s2.notes[i].pit,
			shhd: 0,
			dur: BASE_LEN / 4
			dur: C.BLEN / 4
		}
	}
	new_s.stemless = true
}

/* -- define the beginning of a new music line -- */
function set_nl(s) {
	var s2, p_voice, done
function set_nl(s, eoln) {
    var	s2, s3, p_voice, done

	// set the end of line marker and
	// set the end of line marker and ...
	function set_eol(s) {
		if (cfmt.custos && voice_tb.length == 1)
			custos_add(s)

		// set the nl flag if more music
		// ... set the nl flag if more music
		for (var s2 = s.ts_next; s2; s2 = s2.ts_next) {
			if (s2.seqst) {
				s.nl = true
				break
			}
		}
	} // set_eol()
︙
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
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
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
1545
1546
1547
1548
1549
1550
1551

1552
1553
1554
1555
1556



1557
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
1586
1587
1588

1589
1590
1591
1592

1593
1594
1595
1596

1597
1598
1599
1600
1601

1602
1603
1604
1605
1606
1607





1608
1609
1610
1611




1612

1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630



1631
1632
1633
1634
1635
1636
1637
1638
1639
1640








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

-
+




-
-
-
+
+
+

-
-
-
-
-
-
-
-
-
+










-
+
-
-
-
-
-
-
-
-
+










-
-
+
+



-
+



-
+



-
+




-
+





-
-
-
-
-
+



-
-
-
-

-
+

















-
-
-
+
+
+







			if (s.seqst) {
				set_eol(s)
				break
			}
		}
		return s
	} // set_eol_next()

	// go to the end of the time sequence
	// for adding keywarn or timewarn
	while (s) {
		if (!s.ts_next)
			return // null
		if (s.ts_next.seqst)
			break
		s = s.ts_next
	}

	// if keywarn or timewarn, move K: and M: to the end of the previous line
	if (cfmt.keywarn || cfmt.timewarn) {
		for (s2 = s.ts_next; s2; s2 = s2.ts_next) {
			switch (s2.type) {
			case C.BAR:
			case C.CLEF:
				continue
			case C.KEY:
				if (!cfmt.keywarn)
					continue
			case C.METER:
				if (s2.type == C.METER && !cfmt.timewarn)
					continue
				s3 = s2.ts_prev;
				if (s3 == s) {		// if next symbol
					s = s2		// advance the eol
					continue
				}
				unlksym(s2);		// remove
				lktsym(s2, s.ts_next);	// link in time at eol
				s = s2
				while (1) {		// link in voice
					s2 = s2.ts_prev
					if (s2.v == s.v) {
						s.next = s2.next;
						s.prev = s2;
						s.next.prev = s;
						s2.next = s
						break
					}
				}

				// care with spacing
				if (s.type != s.ts_prev.type) {
					if (!s.seqst) {
						s.seqst = true;
						s.shrink = s.wl + s.prev.wr;
						s.space = s.ts_next.space;
						s.ts_next.space = 0
					}
				} else {
					delete s.seqst
				}

				s2 = s3		// restart
				continue
			}
			if (w_tb[s2.type])
				break		// symbol with a width
		}
	}

	/* if explicit EOLN, cut on the next symbol */
	if (s.eoln && !cfmt.keywarn && !cfmt.timewarn)
	if (eoln)
		return set_eol_next(s)

	/* if normal symbol, cut here */
	switch (s.type) {
	case CLEF:
	case BAR:
	case STAVES:
	case C.CLEF:
	case C.BAR:
	case C.STAVES:
		break
	case KEY:
		if (cfmt.keywarn && !s.k_none)
			break
		return set_eol_next(s)
	case METER:
		if (cfmt.timewarn)
			break
		return set_eol_next(s)
	case GRACE:			/* don't cut on a grace note */
	case C.GRACE:			/* don't cut on a grace note */
		s = s.next
		if (!s)
			return s
		/* fall thru */
	default:
		return set_eol_next(s)
	}

	/* go back to handle the staff breaks at end of line */
	for (; s; s = s.ts_prev) {
		if (!s.seqst)
		if (s.seqst && s.type != C.CLEF)
			continue
		switch (s.type) {
		case KEY:
		case CLEF:
		case METER:
			continue
		}
		break
			break
	}
	done = 0
	for ( ; ; s = s.ts_next) {
		if (!s)
			return s
		if (!s.seqst)
			continue
		if (done < 0)
			break
		switch (s.type) {
		case STAVES:
			if (s.ts_prev && s.ts_prev.type == BAR)
		case C.STAVES:
			if (s.ts_prev && s.ts_prev.type == C.BAR)
				break
			while (s.ts_next) {
				if (w_tb[s.ts_next.type] != 0
				 && s.ts_next.type != CLEF)
				 && s.ts_next.type != C.CLEF)
					break
				s = s.ts_next
			}
			if (!s.ts_next || s.ts_next.type != BAR)
			if (!s.ts_next || s.ts_next.type != C.BAR)
				continue
			s = s.ts_next
			// fall thru
		case BAR:
		case C.BAR:
			if (done)
				break
			done = 1;
			continue
		case STBRK:
		case C.STBRK:
			if (!s.stbrk_forced)
				unlksym(s)	/* remove */
			else
				done = -1	// keep the next symbols on the next line
			continue
		case METER:
			if (!cfmt.timewarn)
				break
			continue
		case CLEF:
		case C.CLEF:
			if (done)
				break
			continue
		case KEY:
			if (!cfmt.keywarn || s.k_none)
				break
			continue
		default:
			if (!done || (s.prev && s.prev.type == GRACE))
			if (!done || (s.prev && s.prev.type == C.GRACE))
				continue
			break
		}
		break
	}
	set_eol(s)
	return s
}

/* get the width of the starting clef and key signature */
// return
//	r[0] = width of clef and key signature
//	r[1] = width of the meter
function get_ck_width() {
    var	r0, r1,
	p_voice = voice_tb[0]

	set_width(p_voice.clef);
	set_width(p_voice.key);
	set_width(p_voice.meter)
	self.set_width(p_voice.clef);
	self.set_width(p_voice.key);
	self.set_width(p_voice.meter)
	return [p_voice.clef.wl + p_voice.clef.wr +
			p_voice.key.wl + p_voice.key.wr,
		p_voice.meter.wl + p_voice.meter.wr]
}

// get the width of the symbols up to the next eoln or eof
function get_width(s, last) {
︙
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
1545
1546
1547
1548

1549
1550
1551
1552
1553

1554
1555
1556
1557


1558
1559
1560
1561
1562

1563
1564

1565
1566
1567
1568
1569
1570
1571
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







-
+




















-
+

-
-
-
-
+
-

-
-
+
+


-
-
-
+
-
-
+







		xmin = s.x - s.shrink - indent;
		xmax = xmin + lwidth;
		xmid = xmin + wwidth / nlines;
		xmin += wwidth / nlines * cfmt.breaklimit;
		for (s = s.ts_next; s != last ; s = s.ts_next) {
			if (!s.x)
				continue
			if (s.type == BAR)
			if (s.type == C.BAR)
				s2 = s
			if (s.x >= xmin)
				break
		}
//fixme: can this occur?
		if (s == last) {
			if (last)
				last = set_nl(last)
			return last
		}

		/* try to cut on a measure bar */
		cut_here = false;
		s3 = null
		for ( ; s != last; s = s.ts_next) {
			x = s.x
			if (!x)
				continue
			if (x > xmax)
				break
			if (s.type != BAR)
			if (s.type != C.BAR)
				continue
			if (x < xmid) {
				s3 = s		// keep the last bar
				continue
			}


			// cut on the bar closest to the middle
			if (!s3 || s.x < xmid) {
				s3 = s
			if (x < xmid) {
				s3 = s		// closest bar before middle
				continue
			}
			if (s3 > xmid)
				break
			if (xmid - s3.x < s.x - xmid)
			if (!s3 || x - xmid < xmid - s3.x)
				break
			s3 = s
				s3 = s		// closest bar after middle
			break
		}

		/* if a bar, cut here */
		if (s3) {
			s = s3;
			cut_here = true
︙
1588
1589
1590
1591
1592
1593
1594
1595

1596
1597
1598
1599
1600
1601
1602
1749
1750
1751
1752
1753
1754
1755

1756
1757
1758
1759
1760
1761
1762
1763







-
+







				if (!x)
					continue
				if (x + s.wr >= xmax)
					break
				if (beam || s.in_tuplet)
					continue
//fixme: this depends on the meter
				if ((s.time - bar_time) % (BASE_LEN / 4) == 0) {
				if ((s.time - bar_time) % (C.BLEN / 4) == 0) {
					s3 = s
					continue
				}
				if (!s3 || s.x < xmid) {
					s3 = s
					continue
				}
︙
1653
1654
1655
1656
1657
1658
1659
1660

1661
1662
1663
1664
1665
1666
1667
1814
1815
1816
1817
1818
1819
1820

1821
1822
1823
1824
1825
1826
1827
1828







-
+







		indent = 0
	}
	return s
}

/* -- cut the tune into music lines -- */
function cut_tune(lwidth, indent) {
	var	s, s2, s3, i, xmin,
	var	s, s2, s3, i, xmin, lwx,
//fixme: not usable yet
//		pg_sav = {
//			leftmargin: cfmt.leftmargin,
//			rightmargin: cfmt.rightmargin,
//			pagewidth: cfmt.pagewidth,
//			scale: cfmt.scale
//		},
︙
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
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







-
+










+



-
+















-
+

















-
+

-
+







	if (cfmt.custos && voice_tb.length == 1)
		lwidth -= 12

	/* if asked, count the measures and set the EOLNs */
	if (cfmt.barsperstaff) {
		i = cfmt.barsperstaff;
		for (s2 = s; s2; s2 = s2.ts_next) {
			if (s2.type != BAR
			if (s2.type != C.BAR
			 || !s2.bar_num
			 || --i > 0)
				continue
			s2.eoln = true;
			i = cfmt.barsperstaff
		}
	}

	/* cut at explicit end of line, checking the line width */
	xmin = indent;
	lwx = lwidth * cfmt.maxshrink;
	s2 = s
	for ( ; s; s = s.ts_next) {
//fixme: not usable yet
//		if (s.type == BLOCK) {
//		if (s.type == C.BLOCK) {
//			switch (s.subtype) {
//			case "leftmargin":
//			case "rightmargin":
//			case "pagescale":
//			case "pagewidth":
//			case "scale":
//			case "staffwidth":
//				set_format(s.subtype, s.param)
//				break
//			}
//			continue
//		}
		if (!s.seqst && !s.eoln)
			continue
		xmin += s.shrink
		if (xmin > lwidth) {		// overflow
		if (xmin > lwx) {		// overflow
			s2 = set_lines(s2, s, lwidth, indent)
		} else {
			if (!s.eoln)
				continue
			delete s.eoln

			// if eoln on a note or a rest,
			// check for a smaller duration in an other voice
			if (s.dur) {
				for (s3 = s.ts_next; s3; s3 = s3.ts_next) {
					if (s3.seqst
					 || s3.dur < s.dur)
						break
				}
				if (s3 && !s3.seqst)
					s2 = set_lines(s2, s, lwidth, indent)
				else
					s2 = set_nl(s)
					s2 = set_nl(s, true)
			} else {
				s2 = set_nl(s)
				s2 = set_nl(s, true)
			}
		}
		if (!s2)
			break

		// (s2 may be tsfirst - no ts_prev - when only one
		//  embedded info in the first line after the first K:)
︙
1765
1766
1767
1768
1769
1770
1771
1772

1773
1774
1775
1776
1777
1778
1779
1927
1928
1929
1930
1931
1932
1933

1934
1935
1936
1937
1938
1939
1940
1941







-
+








/* -- set the y values of some symbols -- */
function set_yval(s) {
//fixme: staff_tb is not yet defined
//	var top = staff_tb[s.st].topbar
//	var bot = staff_tb[s.st].botbar
	switch (s.type) {
	case CLEF:
	case C.CLEF:
		if (s.second
		 || s.invis) {
//			s.ymx = s.ymn = (top + bot) / 2
			s.ymx = s.ymn = 12
			break
		}
		s.y = (s.clef_line - 1) * 6
︙
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
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







-
+









-
-
-
+
+
+













-
+



-
-
+
+







		if (s.clef_octave) {
			if (s.clef_octave > 0)
				s.ymx += 12
			else
				s.ymn -= 12
		}
		break
	case KEY:
	case C.KEY:
		if (s.k_sf > 2)
			s.ymx = 24 + 10
		else if (s.k_sf > 0)
			s.ymx = 24 + 6
		else
			s.ymx = 24 + 2;
		s.ymn = -2
		break
	default:
//		s.ymx = top + 2;
		s.ymx = 24 + 2;
		s.ymn = -2
//		s.ymx = top;
		s.ymx = 24;
		s.ymn = 0
		break
	}
}

// set the clefs (treble or bass) in a 'auto clef' sequence
// return the starting clef type
function set_auto_clef(st, s_start, clef_type_start) {
	var s, min, max, time, s2, s3;

	/* get the max and min pitches in the sequence */
	max = 12;					/* "F," */
	min = 20					/* "G" */
	for (s = s_start; s; s = s.ts_next) {
		if (s.type == STAVES && s != s_start)
		if (s.type == C.STAVES && s != s_start)
			break
		if (s.st != st)
			continue
		if (s.type != NOTE) {
			if (s.type == CLEF) {
		if (s.type != C.NOTE) {
			if (s.type == C.CLEF) {
				if (s.clef_type != 'a')
					break
				unlksym(s)
			}
			continue
		}
		if (s.notes[0].pit < min)
︙
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
1948
1949
1950
1951
1952
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







-
+

-
+















-
+






-
+













-
+






-
+

















-
+

-
+


-
+







		else
			clef_type_start = 'b'
	}
	var	clef_type = clef_type_start,
		s_last = s,
		s_last_chg = null
	for (s = s_start; s != s_last; s = s.ts_next) {
		if (s.type == STAVES && s != s_start)
		if (s.type == C.STAVES && s != s_start)
			break
		if (s.st != st || s.type != NOTE)
		if (s.st != st || s.type != C.NOTE)
			continue

		/* check if a clef change may occur */
		time = s.time
		if (clef_type == 't') {
			if (s.notes[0].pit > 12		/* F, */
			 || s.notes[s.nhd].pit > 20) {	/* G */
				if (s.notes[0].pit > 20)
					s_last_chg = s
				continue
			}
			s2 = s.ts_prev
			if (s2
			 && s2.time == time
			 && s2.st == st
			 && s2.type == NOTE
			 && s2.type == C.NOTE
			 && s2.notes[0].pit >= 19)	/* F */
				continue
			s2 = s.ts_next
			if (s2
			 && s2.st == st
			 && s2.time == time
			 && s2.type == NOTE
			 && s2.type == C.NOTE
			 && s2.notes[0].pit >= 19)	/* F */
				continue
		} else {
			if (s.notes[0].pit < 12		/* F, */
			 || s.notes[s.nhd].pit < 20) {	/* G */
				if (s.notes[s.nhd].pit < 12)
					s_last_chg = s
				continue
			}
			s2 = s.ts_prev
			if (s2
			 && s2.time == time
			 && s2.st == st
			 && s2.type == NOTE
			 && s2.type == C.NOTE
			 && s2.notes[0].pit <= 13)	/* G, */
				continue
			s2 = s.ts_next
			if (s2
			 && s2.st == st
			 && s2.time == time
			 && s2.type == NOTE
			 && s2.type == C.NOTE
			 && s2.notes[0].pit <= 13)	/* G, */
				continue
		}

		/* if first change, change the starting clef */
		if (!s_last_chg) {
			clef_type = clef_type_start =
					clef_type == 't' ? 'b' : 't';
			s_last_chg = s
			continue
		}

		/* go backwards and search where to insert a clef change */
		s3 = s
		for (s2 = s.ts_prev; s2 != s_last_chg; s2 = s2.ts_prev) {
			if (s2.st != st)
				continue
			if (s2.type == BAR
			if (s2.type == C.BAR
			 && s2.v == s.v) {
				s3 = s2
				s3 = s2.bar_type[0] != ':' ? s2 : s2.next
				break
			}
			if (s2.type != NOTE)
			if (s2.type != C.NOTE)
				continue

			/* have a 2nd choice on beam start */
			if (s2.beam_st
			 && !s2.p_v.second)
				s3 = s2
		}
︙
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2159
2160
2161
2162
2163
2164
2165


2166
2167
2168
2169
2170
2171
2172







-
-







	// set the starting clefs of the staves
	for (v = 0; v < voice_tb.length; v++) {
		p_voice = voice_tb[v]
		if (sy.voices[v].range < 0)
			continue
		st = sy.voices[v].st
		if (!sy.voices[v].second) {		// main voices
			if (p_voice.stafflines != undefined)
				sy.staves[st].stafflines = p_voice.stafflines
			if (p_voice.staffnonote != undefined)
				sy.staves[st].staffnonote = p_voice.staffnonote
			if (p_voice.staffscale)
				sy.staves[st].staffscale = p_voice.staffscale
			if (sy.voices[v].sep)
				sy.staves[st].sep = sy.voices[v].sep
			if (sy.voices[v].maxsep)
︙
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
2195
2196
2197
2198
2199
2200
2201

2202
2203
2204
2205
2206
2207
2208
2209
2210
2211


2212
2213
2214
2215
2216
2217
2218







-
+









-
-







		mid[st] = (sy.staves[st].stafflines.length - 1) * 3

	for (s = tsfirst; s; s = s.ts_next) {
		if (s.repeat_n)
			set_repeat(s)

		switch (s.type) {
		case STAVES:
		case C.STAVES:
			sy = s.sy
			for (st = 0; st <= nstaff; st++)
				staff_clef[st].autoclef = true
			for (v = 0; v < voice_tb.length; v++) {
				if (sy.voices[v].range < 0)
					continue
				p_voice = voice_tb[v];
				st = sy.voices[v].st
				if (!sy.voices[v].second) {
					if (p_voice.stafflines != undefined)
						sy.staves[st].stafflines = p_voice.stafflines
					if (p_voice.staffnonote != undefined)
						sy.staves[st].staffnonote = p_voice.staffnonote
					if (p_voice.staffscale)
						sy.staves[st].staffscale = p_voice.staffscale
					if (sy.voices[v].sep)
						sy.staves[st].sep = sy.voices[v].sep
					if (sy.voices[v].maxsep)
︙
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
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







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










-
+







						staff_clef[st].clef = p_voice.clef
					continue
				}
								// old staff
				if (new_type == staff_clef[st].clef.clef_type
				 && new_line == staff_clef[st].clef.clef_line)
					continue
				g = s.ts_prev
				while (g
				 && g.time == s.time
				 && (g.v != v || g.st != st))
					g = g.ts_prev
				if (!g || g.time != s.time) {
				g = s.ts_next
				while (g && (g.v != v || g.st != st))
					g = g.ts_next
				if (!g)				// ??
					g = s.ts_next
					while (g && (g.v != v || g.st != st))
						g = g.ts_next
					if (!g || g.time != s.time)
					continue
				if (g.type != CLEF) {
						g = s
				}
				if (g.type != C.CLEF) {
					g = insert_clef(g, new_type, new_line)
					if (s2.clef_auto)
						g.clef_auto = true
				}
				staff_clef[st].clef = p_voice.clef = g
			}
			continue
		default:
			s.mid = mid[s.st]
			continue
		case CLEF:
		case C.CLEF:
			break
		}

		if (s.clef_type == 'a') {
			s.clef_type = set_auto_clef(s.st,
						s.ts_next,
						staff_clef[s.st].clef.clef_type);
︙
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
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314

2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
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
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
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
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
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
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







+

-
-
-
+
+
+
+
+
+
+

+
+
+
+
+
+
+
+














+
+
+




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

-
+











+


-
+

-
+












-
+





-
+






-
+









-
-
+
+


-
+
+

-
-
+
+
+


















+


















-
+

-
+








-
+







	[10, 10],			/* crotchet */
	[6, 4],
	[10, 0],
	[10, 4],
	[10, 10]
]

// (possible hook)
function set_pitch(last_s) {
	var	s, s2, g, st, delta, m, pitch, note,
		dur = BASE_LEN,
		staff_delta = new Array(nstaff),
	var	s, s2, g, st, delta, pitch, note,
		dur = C.BLEN,
		m = nstaff + 1,
		staff_d = new Int16Array(new Array(m * 2)),	// (delta - ottava)
		staff_delta = new Int16Array(new Array(m * 2)),	// delta clef
		staff_ottava = new Int16Array(new Array(m * 2)), // ottava value
		staff_noo = new Int8Array(new Array(m)),	// number of ottava values
		sy = cur_sy

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

		deco_cnv([(start ? dc_st : dc_en)[2 + ottava]], s)
	}

	// 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)
			staff_delta[st] += s.clefpit
		if (cfmt.sound) {
			if (s.clef_octave && !s.clef_oct_transp)
				staff_delta[st] += s.clef_octave
		} else {
			if (s.clef_oct_transp)
				staff_delta[st] -= s.clef_octave
		}
		staff_d[st] = staff_delta[st];
		staff_ottava[st] = 0;
		staff_noo[st] = 0
	}

	for (s = tsfirst; s != last_s; s = s.ts_next) {
		st = s.st

		// set the ottava decorations and the associated pitch shift
		if (s.ottava != undefined && !cfmt.sound) {
			if (s.ottava) {
				if (staff_noo[st]++ == 0) {	// if first ottava
					ottava_add(s, s.ottava, true);
					staff_ottava[st] = s.ottava;
					staff_d[st] = staff_delta[st] - s.ottava * 7
				}
			} else {
				if (--staff_noo[st] == 0) {	// if last ottava
					ottava_add(s, staff_ottava[st]);
					staff_ottava[st] = s.ottava;
					staff_d[st] = staff_delta[st]
				}
			}
		}

		switch (s.type) {
		case CLEF:
		case C.CLEF:
			staff_delta[st] = delta_tb[s.clef_type] +
						s.clef_line * 2
			if (s.clefpit)
				staff_delta[st] += s.clefpit
			if (cfmt.sound) {
				if (s.clef_octave && !s.clef_oct_transp)
					staff_delta[st] += s.clef_octave
			} else {
				if (s.clef_oct_transp)
					staff_delta[st] -= s.clef_octave
			}
			staff_d[st] = staff_delta[st] - staff_ottava[st] * 7;
			set_yval(s)
			break
		case GRACE:
		case C.GRACE:
			for (g = s.extra; g; g = g.next) {
				delta = staff_delta[g.st]
				delta = staff_d[g.st]
				if (delta != 0
				 && !s.p_v.key.k_drum) {
					for (m = 0; m <= g.nhd; m++) {
						note = g.notes[m];
						note.pit += delta
					}
				}
				g.ymn = 3 * (g.notes[0].pit - 18) - 2;
				g.ymx = 3 * (g.notes[g.nhd].pit - 18) + 2
			}
			set_yval(s)
			break
		case KEY:
		case C.KEY:
			s.k_y_clef = staff_delta[st] /* keep the y delta */
			/* fall thru */
		default:
			set_yval(s)
			break
		case MREST:
		case C.MREST:
			if (s.invis)
				break
			s.y = 12;
			s.ymx = 24 + 15;
			s.ymn = -2
			break
		case REST:
		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 NOTE:
			delta = staff_delta[st]
		case C.NOTE:
			delta = staff_d[st]
			if (delta != 0
			 && !s.p_v.key.k_drum) {
				for (m = s.nhd; m >= 0; m--)
				for (m = s.nhd; m >= 0; m--) {
					s.notes[m].opit = s.notes[m].pit;
					s.notes[m].pit += delta
			}
			if (s.type == NOTE) {
				}
			}
			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 {
				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
}

/* -- set the stem direction when multi-voices -- */
/* this function is called only once per tune */
// (possible hook)
function set_stem_dir() {
	var	t, u, i, st, rvoice, v,
		v_st,			// voice -> staff 1 & 2
		st_v, vobj,		// staff -> (v, ymx, ymn)*
		v_st_tb,		// array of v_st
		st_v_tb = [],		// array of st_v
		s = tsfirst,
		sy = cur_sy,
		nst = sy.nstaff

	while (s) {
		for (st = 0; st <= nst; st++)
			st_v_tb[st] = []
		v_st_tb = []

		/* get the max/min offsets in the delta time */
/*fixme: the stem height is not calculated yet*/
		for (u = s; u; u = u.ts_next) {
			if (u.type == BAR)
			if (u.type == C.BAR)
				break;
			if (u.type == STAVES) {
			if (u.type == C.STAVES) {
				if (u != s)
					break
				sy = s.sy
				for (st = nst; st <= sy.nstaff; st++)
					st_v_tb[st] = []
				nst = sy.nstaff
				continue
			}
			if ((u.type != NOTE && u.type != REST)
			if ((u.type != C.NOTE && u.type != C.REST)
			 || u.invis)
				continue
			st = u.st;
/*fixme:test*/
if (st > nst) {
	var msg = "*** fatal set_stem_dir(): bad staff number " + st +
			" max " + nst;
︙
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


2435
2436
2437
2438


2439
2440
2441
2442
2443
2444
2445
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
2645
2646
2647
2648
2649
2650
2651







-
+








-
+

















-
+


-
+



+


+
+


-
-
+
+







						break
					}
				}
				if (i == st_v.length)
					st_v.push(vobj)
			}

			if (u.type != NOTE)
			if (u.type != C.NOTE)
				continue
			if (u.ymx > vobj.ymx)
				vobj.ymx = u.ymx
			if (u.ymn < vobj.ymn)
				vobj.ymn = u.ymn

			if (u.xstem) {
				if (u.ts_prev.st != st - 1
				 || u.ts_prev.type != NOTE) {
				 || u.ts_prev.type != C.NOTE) {
					error(1, s, "Bad !xstem!");
					u.xstem = false
/*fixme:nflags KO*/
				} else {
					u.ts_prev.multi = 1;
					u.multi = 1;
					u.stemless = true
				}
			}
		}

		for ( ; s != u; s = s.ts_next) {
			if (s.multi)
				continue
			switch (s.type) {
			default:
				continue
			case REST:
			case C.REST:
				// handle %%voicecombine 0
				if ((s.combine != undefined && s.combine < 0)
				 || !s.ts_next || s.ts_next.type != REST
				 || !s.ts_next || s.ts_next.type != C.REST
				 || s.ts_next.st != s.st
				 || s.time != s.ts_next.time
				 || s.dur != s.ts_next.dur
				 || (s.a_gch && s.ts_next.a_gch)
				 || s.invis)
					break
				if (s.ts_next.a_gch)
					s.a_gch = s.ts_next.a_gch
				unlksym(s.ts_next)
				break
			case NOTE:
			case GRACE:
			case C.NOTE:
			case C.GRACE:
				break
			}

			st = s.st;
			v = s.v;
			v_st = v_st_tb[v];
			st_v = st_v_tb[st]
︙
2489
2490
2491
2492
2493
2494
2495
2496

2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512

2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524

2525
2526
2527
2528
2529
2530
2531
2695
2696
2697
2698
2699
2700
2701

2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717

2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729

2730
2731
2732
2733
2734
2735
2736
2737







-
+















-
+











-
+







					 && (!t
					  || t.st != s.st
					  || t.time != s.time))
						s.multi = -1
				}
			}
		}
		while (s && s.type == BAR)
		while (s && s.type == C.BAR)
			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 == STAVES)
		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 != REST)
		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++) {
︙
2565
2566
2567
2568
2569
2570
2571
2572

2573
2574
2575
2576
2577
2578
2579
2771
2772
2773
2774
2775
2776
2777

2778
2779
2780
2781
2782
2783
2784
2785







-
+








		/* 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 != NOTE && s2.type != REST)
//			 || (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) {
︙
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
2717
2718
2719
2720
2721
2881
2882
2883
2884
2885
2886
2887

2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
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







-
+



















-
+











-
+







		last_s.shrink = 0
	}
	return s
}

/* -- init the symbols at start of a music line -- */
function init_music_line() {
	var	p_voice, s, s2, last_s, v, st,
	var	p_voice, s, s2, s3, last_s, v, st, shr, shrmx,
		nv = voice_tb.length

	/* initialize the voices */
	for (v = 0; v < nv; v++) {
		if (cur_sy.voices[v].range < 0)
			continue
		p_voice = voice_tb[v];
		p_voice.second = cur_sy.voices[v].second;
		p_voice.last_sym = p_voice.sym;

		/* move the voice to a printed staff */
		st = cur_sy.voices[v].st
		while (st < nstaff && !cur_sy.st_print[st])
			st++;
		p_voice.st = st
	}

	/* add a clef at start of the main voices */
	last_s = tsfirst
	while (last_s.type == CLEF) {		/* move the starting clefs */
	while (last_s && last_s.type == C.CLEF) {	// move the starting clefs
		v = last_s.v
		if (cur_sy.voices[v].range >= 0
		 && !cur_sy.voices[v].second) {
			delete last_s.clef_small;	/* normal clef */
			p_voice = last_s.p_v;
			p_voice.last_sym = p_voice.sym = last_s
		}
		last_s = last_s.ts_next
	}
	for (v = 0; v < nv; v++) {
		p_voice = voice_tb[v]
		if (p_voice.sym && p_voice.sym.type == CLEF)
		if (p_voice.sym && p_voice.sym.type == C.CLEF)
			continue
		if (cur_sy.voices[v].range < 0
		 || (cur_sy.voices[v].second
		  && !p_voice.bar_start))	// needed for correct linkage
			continue
		st = cur_sy.voices[v].st
		if (!staff_tb[st]
︙
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
2948
2949
2950
2951
2952
2953
2954

2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971

2972
2973
2974
2975
2976
2977
2978
2979

2980
2981
2982
2983
2984
2985
2986
2987







-
+
















-
+







-
+







			s.seqst = true
		} else {
			s.ts_prev.ts_next = s
			delete s.seqst
		}
		if (last_s) {
			last_s.ts_prev = s
			if (last_s.type == CLEF)
			if (last_s.type == C.CLEF)
				delete last_s.seqst
		}
		delete s.clef_small;
		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
	}

	/* add keysig */
	for (v = 0; v < nv; v++) {
		if (cur_sy.voices[v].range < 0
		 || cur_sy.voices[v].second
		 || !cur_sy.st_print[cur_sy.voices[v].st])
			continue
		p_voice = voice_tb[v]
		if (last_s && last_s.v == v && last_s.type == KEY) {
		if (last_s && last_s.v == v && last_s.type == C.KEY) {
			p_voice.last_sym = last_s;
			last_s.k_old_sf = last_s.k_sf;	// no key cancel
			last_s = last_s.ts_next
			continue
		}
		s2 = p_voice.key
		if (s2.k_sf || s2.k_a_acc) {
			s = new_sym(KEY, p_voice, last_s);
			s = new_sym(C.KEY, p_voice, last_s);
			s.k_sf = s2.k_sf;
			s.k_old_sf = s2.k_sf;	// no key cancel
			s.k_none = s2.k_none;
			s.k_a_acc = s2.k_a_acc;
			s.istart = s2.istart;
			s.iend = s2.iend
			if (s2.k_bagpipe) {
︙
2792
2793
2794
2795
2796
2797
2798
2799

2800
2801
2802
2803
2804

2805
2806
2807
2808
2809
2810
2811
2812
2813
2814



2815
2816
2817
2818

2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844

2845
2846
2847
2848
2849
2850

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
2893
2894
2895
2896

2897
2898
2899
2900
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
2936
2998
2999
3000
3001
3002
3003
3004

3005
3006
3007
3008
3009

3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025


3026
3027
3028
3029
3030
3031

3032
3033

3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049

3050
3051
3052
3053
3054
3055

3056
3057
3058
3059
3060
3061
3062
3063
3064
3065



3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
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







-
+




-
+










+
+
+


-
-
+





-


-
















-
+





-
+








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


-
+




-
+






-
+


-
+
+



-
-
-
-
+
+
+
+

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

+
+




-
+












-
+






-
+



-
+




-
+



-
+







			p_voice = voice_tb[v];
			s2 = p_voice.meter
			if (cur_sy.voices[v].range < 0
			 || cur_sy.voices[v].second
			 || !cur_sy.st_print[cur_sy.voices[v].st]
			 || s2.a_meter.length == 0)
				continue
			if (last_s && last_s.v == v && last_s.type == METER) {
			if (last_s && last_s.v == v && last_s.type == C.METER) {
				p_voice.last_sym = last_s;
				last_s = last_s.ts_next
				continue
			}
			s = new_sym(METER, p_voice, last_s);
			s = new_sym(C.METER, p_voice, last_s);
			s.istart = s2.istart;
			s.iend = s2.iend;
			s.wmeasure = s2.wmeasure;
			s.a_meter = s2.a_meter
		}
		insert_meter &= ~1		// no meter any more
	}

	/* add bar if needed (for repeat bracket) */
	for (v = 0; v < nv; v++) {
		p_voice = voice_tb[v];
		s2 = p_voice.bar_start;
		p_voice.bar_start = null

		// if bar already, keep it in sequence
		p_voice = voice_tb[v];
		if (last_s && last_s.v == v && last_s.type == BAR) {
		if (last_s && last_s.v == v && last_s.type == C.BAR) {
			p_voice.last_sym = last_s;
			last_s = last_s.ts_next
			continue
		}

		s2 = p_voice.bar_start
		if (!s2)
			continue
		p_voice.bar_start = null
		if (cur_sy.voices[v].range < 0
		 || !cur_sy.st_print[cur_sy.voices[v].st])
			continue

		s2.next = p_voice.last_sym.next
		if (s2.next)
			s2.next.prev = s2;
		p_voice.last_sym.next = s2;
		s2.prev = p_voice.last_sym;
		p_voice.last_sym = s2;
		lktsym(s2, last_s);
		s2.time = tsfirst.time
		if (s2.ts_prev.type != s2.type)
			s2.seqst = true;
		if (last_s && last_s.type == s2.type && s2.v != last_s.v) {
			delete last_s.seqst;
			last_s.shrink = 0
//			last_s.shrink = 0
		}
	}

	/* if initialization of a new music line, compute the spacing,
	 * including the first (old) sequence */
	set_pitch(last_s);
	self.set_pitch(last_s)
	for (s = last_s; s; s = s.ts_next) {
		if (s.seqst) {
			for (s = s.ts_next; s; s = s.ts_next)
				if (s.seqst)
					break
			break
		}
	}

	set_allsymwidth(s)	/* set the width of the added symbols */
}

	// set the spacing of the added symbols
	while (last_s) {
		if (last_s.seqst) {
			do {
				last_s = last_s.ts_next
			} while (last_s && !last_s.seqst)
			break
		}
		last_s = last_s.ts_next
	}

	s = tsfirst
	while (1) {
		s2 = s;
		shrmx = 0
		do {
			self.set_width(s);
			shr = s.wl
			for (s3 = s.prev; s3; s3 = s3.prev) {
				if (w_tb[s3.type] != 0) {
					shr += s3.wr
					break
				}
			}
			if (shr > shrmx)
				shrmx = shr;
			s = s.ts_next
		} while (s != last_s && !s.seqst);
		s2.shrink = shrmx;
		s2.space = 0
		if (s == last_s)
			break
	}
}

/* -- set a pitch in all symbols and the start/stop of the beams -- */
function set_words(p_voice) {
	var	s, s2, nflags, lastnote,
	var	s, s2, nflags, lastnote, res,
		start_flag = true,
		pitch = 127			/* no note */

	for (s = p_voice.sym; s; s = s.next) {
		if (s.type == NOTE) {
		if (s.type == C.NOTE) {
			pitch = s.notes[0].pit
			break
		}
	}
	for (s = p_voice.sym; s; s = s.next) {
		switch (s.type) {
		case MREST:
		case C.MREST:
			start_flag = true
			break
		case BAR:
		case C.BAR:
			s.bar_type = bar_cnv(s.bar_type)
			if (!s.beam_on)
				start_flag = true
			if (!s.next && s.prev
//			 && s.prev.type == NOTE
//			 && s.prev.dur >= BASE_LEN * 2)
			 && s.prev.head == OVALBARS)
				s.prev.head = SQUARE
//			 && s.prev.type == C.NOTE
//			 && s.prev.dur >= C.BLEN * 2)
			 && s.prev.head == C.OVALBARS)
				s.prev.head = C.SQUARE
			break
		case NOTE:
		case REST:
			if (s.trem2)
		case C.NOTE:
		case C.REST:
			res = identify_note(s, s.dur_orig);
			s.head = res[0];
			s.dots = res[1];
			s.nflags = res[2]
			if (s.nflags <= -2)
				s.stemless = true

			if (s.xstem)
				s.nflags = 0	// beam break
			if (s.trem1) {
				if (s.nflags > 0)
					s.nflags += s.ntrem
				else
					s.nflags = s.ntrem
			}
			if (s.next && s.next.trem2)
				break
			if (s.trem2) {
				s.prev.trem2 = true;
				s.prev.nflags = --s.nflags;
				s.prev.head = ++s.head
				if (s.nflags > 0) {
					s.nflags += s.ntrem;
				} else {
					if (s.nflags <= -2) {
						s.stemless = true;
						s.prev.stemless = true
					}
					s.nflags = s.ntrem
				}
				s.prev.nflags = s.nflags
				break
			}

			nflags = s.nflags

			if (s.ntrem)
				nflags += s.ntrem
			if (s.type == REST && s.beam_end) {
			if (s.type == C.REST && s.beam_end) {
				s.beam_end = false;
				start_flag = true
			}
			if (start_flag
			 || nflags <= 0) {
				if (lastnote) {
					lastnote.beam_end = true;
					lastnote = null
				}
				if (nflags <= 0) {
					s.beam_st = true;
					s.beam_end = true
				} else if (s.type == NOTE) {
				} else if (s.type == C.NOTE) {
					s.beam_st = true;
					start_flag = false
				}
			}
			if (s.beam_end)
				start_flag = true
			if (s.type == NOTE)
			if (s.type == C.NOTE)
				lastnote = s
			break
		}
		if (s.type == NOTE) {
		if (s.type == C.NOTE) {
			if (s.nhd != 0)
				sort_pitch(s);
			pitch = s.notes[0].pit
//			if (s.prev
//			 && s.prev.type != NOTE) {
//			 && s.prev.type != C.NOTE) {
//				s.prev.notes[0].pit = (s.prev.notes[0].pit
//						    + pitch) / 2
			for (s2 = s.prev; s2; s2 = s2.prev) {
				if (s2.type != REST)
				if (s2.type != C.REST)
					break
				s2.notes[0].pit = pitch
			}
		} else {
			if (!s.notes) {
				s.notes = []
				s.notes[0] = {}
︙
2945
2946
2947
2948
2949
2950
2951
2952

2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964

2965
2966
2967
2968
2969
2970
2971
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







-
+











-
+








/* -- set the end of the repeat sequences -- */
function set_rb(p_voice) {
	var	s2, mx, n,
		s = p_voice.sym

	while (s) {
		if (s.type != BAR || !s.rbstart || s.norepbra) {
		if (s.type != C.BAR || !s.rbstart || s.norepbra) {
			s = s.next
			continue
		}

		mx = cfmt.rbmax

		/* if 1st repeat sequence, compute the bracket length */
		if (s.text && s.text[0] == '1') {
			n = 0;
			s2 = null
			for (s = s.next; s; s = s.next) {
				if (s.type != BAR)
				if (s.type != C.BAR)
					continue
				n++
				if (s.rbstop) {
					if (n <= cfmt.rbmax) {
						mx = n;
						s2 = null
					}
︙
2993
2994
2995
2996
2997
2998
2999
3000

3001
3002
3003
3004
3005
3006
3007
3265
3266
3267
3268
3269
3270
3271

3272
3273
3274
3275
3276
3277
3278
3279







-
+







					if (s.rbstart != 2)
						break
				}
			}
			n = 0;
			s2 = null
			for (s = s.next; s; s = s.next) {
				if (s.type != BAR)
				if (s.type != C.BAR)
					continue
				n++
				if (s.rbstop)
					break
				if (!s.next)
					s.rbstop = 2	// right repeat with end
				else if (n == mx)
︙
3044
3045
3046
3047
3048
3049
3050
3051

3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073


3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091

3092
3093
3094
3095
3096
3097
3098
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







-
+




















-
-
+
+

















-
+







	}

	/* set the staff of the floating voices */
	set_float();

	// set the clefs and adjust the pitches of all symbol
	set_clefs();
	set_pitch(null)
	self.set_pitch(null)
}

/* -- return the left indentation of the staves -- */
function set_indent(first) {
	var	st, v, w, p_voice, p, i, j, font,
		nv = voice_tb.length,
		maxw = 0

	for (v = 0; v < nv; v++) {
		p_voice = voice_tb[v]
		if (cur_sy.voices[v].range < 0)
			continue
		st = cur_sy.voices[v].st
//		if (!cur_sy.st_print[st])
//			continue
		p = ((first || p_voice.new_name) && p_voice.nm) ?
			p_voice.nm : p_voice.snm
		if (!p)
			continue
		if (!font) {
			font = get_font("voice");
			set_font(font);
			set_font("voice");
			font = gene.curfont
		}
		i = 0
		while (1) {
			j = p.indexOf("\\n", i)
			if (j < 0)
				w = strwh(p.slice(i))
			else
				w = strwh(p.slice(i, j))
			w = w[0]
			if (w > maxw)
				maxw = w
			if (j < 0)
				break
			i = j + 1
		}
	}
	if (font)
		maxw += 4 * cwid(' ') * font.swfac;
		maxw += 4 * cwidf(' ');

	w = .5				// (width of left bar)
	for (st = 0; st <= cur_sy.nstaff; st++) {
		if (cur_sy.staves[st].flags
				& (OPEN_BRACE2 | OPEN_BRACKET2)) {
			w = 12
			break
︙
3110
3111
3112
3113
3114
3115
3116
3117
3118


3119
3120
3121
3122
3123
3124
3125
3382
3383
3384
3385
3386
3387
3388


3389
3390
3391
3392
3393
3394
3395
3396
3397







-
-
+
+







/* -- decide on beams and on stem directions -- */
/* this routine is called only once per tune */
function set_beams(sym) {
	var	s, t, g, beam, s_opp, dy, avg, n, m, mid_p, pu, pd,
		laststem = -1

	for (s = sym; s; s = s.next) {
		if (s.type != NOTE) {
			if (s.type != GRACE)
		if (s.type != C.NOTE) {
			if (s.type != C.GRACE)
				continue
			g = s.extra
			if (g.stem == 2) {	/* opposite gstem direction */
				s_opp = s
				continue
			}
			if (!s.stem
︙
3140
3141
3142
3143
3144
3145
3146
3147

3148
3149
3150
3151
3152
3153
3154
3412
3413
3414
3415
3416
3417
3418

3419
3420
3421
3422
3423
3424
3425
3426







-
+







			if (beam) {
				s.stem = laststem
			} else if (s.beam_st && !s.beam_end) {	// beam start
				beam = true;
				pu = s.notes[s.nhd].pit;
				pd = s.notes[0].pit
				for (g = s.next; g; g = g.next) {
					if (g.type != NOTE)
					if (g.type != C.NOTE)
						continue
					if (g.stem || g.multi) {
						s.stem = g.stem || g.multi
						break
					}
					if (g.notes[g.nhd].pit > pu)
						pu = g.notes[g.nhd].pit
︙
3207
3208
3209
3210
3211
3212
3213
3214

3215
3216

3217
3218
3219
3220
3221
3222
3223
3479
3480
3481
3482
3483
3484
3485

3486
3487

3488
3489
3490
3491
3492
3493
3494
3495







-
+

-
+








// check if there may be one head for unison when voice overlap
function same_head(s1, s2) {
	var i1, i2, l1, l2, head, i11, i12, i21, i22, sh1, sh2

	if (s1.shiftunison && s1.shiftunison >= 3)
		return false
	if ((l1 = s1.dur) >= BASE_LEN)
	if ((l1 = s1.dur) >= C.BLEN)
		return false
	if ((l2 = s2.dur) >= BASE_LEN)
	if ((l2 = s2.dur) >= C.BLEN)
		return false
	if (s1.stemless && s2.stemless)
		return false
	if (s1.dots != s2.dots) {
		if ((s1.shiftunison && (s1.shiftunison & 1))
		 || s1.dots * s2.dots != 0)
			return false
︙
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
3560
3561
3562
3563
3564
3565
3566


3567
3568
3569

3570
3571

3572
3573
3574
3575
3576

3577
3578
3579
3580
3581
3582
3583
3584







-
-
+
+

-
+

-
+




-
+








	head = 0
	if (l1 != l2) {
		if (l1 < l2) {
			l1 = l2;
			l2 = s1.dur
		}
		if (l1 < BASE_LEN / 2) {
			if (s2.dots > 0)
		if (l1 < C.BLEN / 2) {
			if (s2.dots)
				head = 2
			else if (s1.dots > 0)
			else if (s1.dots)
				head = 1
		} else if (l2 < BASE_LEN / 4) {	/* (l1 >= BASE_LEN / 2) */
		} else if (l2 < C.BLEN / 4) {	/* (l1 >= C.BLEN / 2) */
//			if ((s1.shiftunison && s1.shiftunison == 2)
//			 || s1.dots != s2.dots)
			if (s1.shiftunison && (s1.shiftunison & 2))
				return false
			head = s2.dur >= BASE_LEN / 2 ? 2 : 1
			head = s2.dur >= C.BLEN / 2 ? 2 : 1
		} else {
			return false
		}
	}
	if (head == 0)
		head = s1.p_v.scale < s2.p_v.scale ? 2 : 1
	if (head == 1) {
︙
3393
3394
3395
3396
3397
3398
3399
3400

3401
3402
3403
3404
3405
3406
3407
3665
3666
3667
3668
3669
3670
3671

3672
3673
3674
3675
3676
3677
3678
3679







-
+







		i = s.notes[m].pit * 2
		if (i < 0)
			i = 0
		else if (i >= MAXPIT - 1)
			i = MAXPIT - 2
		if (w > left[i])
			left[i] = w
		if (s.head != SQUARE)
		if (s.head != C.SQUARE)
			w -= 1
		if (w > left[i - 1])
			left[i - 1] = w
		if (w > left[i + 1])
			left[i + 1] = w
	}

︙
3465
3466
3467
3468
3469
3470
3471
3472

3473
3474
3475
3476
3477
3478
3479
3737
3738
3739
3740
3741
3742
3743

3744
3745
3746
3747
3748
3749
3750
3751







-
+







		i = s.notes[m].pit * 2
		if (i < 0)
			i = 0
		else if (i >= MAXPIT - 1)
			i = MAXPIT - 2
		if (w > right[i])
			right[i] = w
		if (s.head != SQUARE)
		if (s.head != C.SQUARE)
			w -= 1
		if (w > right[i - 1])
			right[i - 1] = w
		if (w > right[i + 1])
			right[i + 1] = w
	}

︙
3494
3495
3496
3497
3498
3499
3500
3501

3502
3503
3504
3505
3506
3507
3508
3766
3767
3768
3769
3770
3771
3772

3773
3774
3775
3776
3777
3778
3779
3780







-
+







		d = d2;
		pl = left1;
		pr = right1;
		dr2 = dr
	}

	for (s = tsfirst; s; s = s.ts_next) {
		if (s.type != NOTE
		if (s.type != C.NOTE
		 || s.invis)
			continue

		/* treat the stem on two staves with different directions */
		if (s.xstem
		 && s.ts_prev.stem < 0) {
			for (m = 0; m <= s.nhd; m++) {
︙
3517
3518
3519
3520
3521
3522
3523
3524

3525
3526
3527
3528
3529
3530
3531
3789
3790
3791
3792
3793
3794
3795

3796
3797
3798
3799
3800
3801
3802
3803







-
+







			s2 = s2.ts_next
			if (!s2)
				break
			if (s2.time != s.time) {
				s2 = null
				break
			}
			if (s2.type == NOTE
			if (s2.type == C.NOTE
			 && !s2.invis
			 && s2.st == s.st)
				break
		}
		if (!s2)
			continue
		s1 = s
︙
3546
3547
3548
3549
3550
3551
3552
3553

3554
3555
3556
3557
3558
3559
3560
3818
3819
3820
3821
3822
3823
3824

3825
3826
3827
3828
3829
3830
3831
3832







-
+








		/* compute the minimum space for 's1 s2' and 's2 s1' */
		right1 = set_right(s1);
		left2 = set_left(s2);

		s3 = s1.ts_prev
		if (s3 && s3.time == s1.time
		 && s3.st == s1.st && s3.type == NOTE && !s3.invis) {
		 && s3.st == s1.st && s3.type == C.NOTE && !s3.invis) {
			right3 = set_right(s3)
			for (i = 0; i < MAXPIT; i++) {
				if (right3[i] > right1[i])
					right1[i] = right3[i]
			}
		} else {
			s3 = null
︙
3756
3757
3758
3759
3760
3761
3762

3763
3764

3765
3766
3767
3768


3769
3770
3771




3772
3773
3774
3775
3776
3777
3778
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







+

-
+


-
-
+
+



+
+
+
+







		if (sd)
			s1.xmx = s2.xmx		// align the dots
	}
}

/* -- set the stem height -- */
/* this routine is called only once per tune */
// (possible hook)
function set_stems() {
	var s, s2, g, slen, scale,ymn, ymx, nflags, ymin, ymax
	var s, s2, g, slen, scale,ymn, ymx, nflags, ymin, ymax, res

	for (s = tsfirst; s; s = s.ts_next) {
		if (s.type != NOTE) {
			if (s.type != GRACE)
		if (s.type != C.NOTE) {
			if (s.type != C.GRACE)
				continue
			ymin = ymax = s.mid
			for (g = s.extra; g; g = g.next) {
				res = identify_note(s, g.dur);
				g.head = res[0];
				g.dots = res[1];
				g.nflags = res[2];
				slen = GSTEM
				if (g.nflags > 1)
					slen += 1.2 * (g.nflags - 1);
				ymn = 3 * (g.notes[0].pit - 18);
				ymx = 3 * (g.notes[g.nhd].pit - 18)
				if (s.stem >= 0) {
					g.y = ymn;
︙
3803
3804
3805
3806
3807
3808
3809
3810

3811
3812
3813
3814
3815
3816
3817
4080
4081
4082
4083
4084
4085
4086

4087
4088
4089
4090
4091
4092
4093
4094







-
+







		/* if start or end of beam, adjust the number of flags
		 * with the other end */
		nflags = s.nflags
		if (s.beam_st && !s.beam_end) {
			if (s.feathered_beam)
				nflags = ++s.nflags
			for (s2 = s.next; /*s2*/; s2 = s2.next) {
				if (s2.type == NOTE) {
				if (s2.type == C.NOTE) {
					if (s.feathered_beam)
						s2.nflags++
					if (s2.beam_end)
						break
				}
			}
/*			if (s2) */
︙
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837




3838
3839
3840
3841
3842
3843
3844
4104
4105
4106
4107
4108
4109
4110




4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121







-
-
-
-
+
+
+
+







			    if (s2.nflags > nflags)
				nflags = s2.nflags
		}

		/* set height of stem end */
		slen = cfmt.stemheight
		switch (nflags) {
		case 2: slen += 2; break
		case 3:	slen += 5; break
		case 4:	slen += 10; break
		case 5:	slen += 16; break
		case 2: slen += 0; break
		case 3:	slen += 4; break
		case 4:	slen += 8; break
		case 5:	slen += 12; break
		}
		if ((scale = s.p_v.scale) != 1)
			slen *= (scale + 1) * .5;
		ymn = 3 * (s.notes[0].pit - 18)
		if (s.nhd > 0) {
			slen -= 2;
			ymx = 3 * (s.notes[s.nhd].pit - 18)
︙
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
4133
4134
4135
4136
4137
4138
4139


4140
4141
4142
4143
4144
4145
4146







-
-







				s.y = ymx
			}
			if (nflags == -4)		/* if longa */
				ymn -= 6;
			s.ymx = ymx + 4;
			s.ymn = ymn - 4
		} else if (s.stem >= 0) {
			if (nflags >= 2)
				slen -= 1
			if (s.notes[s.nhd].pit > 26
			 && (nflags <= 0
			  || !s.beam_st
			  || !s.beam_end)) {
				slen -= 2
				if (s.notes[s.nhd].pit > 28)
					slen -= 2
︙
3896
3897
3898
3899
3900
3901
3902

3903
3904
3905
3906
3907
3908
3909


3910
3911
3912
3913
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
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
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183


4184
4185
4186
4187
4188
4189
4190
4191

4192
4193
4194

4195
4196

4197
4198
4199
4200
4201
4202
4203
4204

4205
4206
4207
4208
4209

4210
4211

4212
4213

4214
4215
4216

4217
4218
4219
4220
4221
4222





4223






4224


4225
4226
4227
4228

4229
4230
4231
4232

4233
4234
4235


4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247

4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266

4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282

4283
4284
4285
4286
4287
4288
4289
4290







+





-
-
+
+






-
+


-
+

-
+







-
+




-
+

-
+

-
+


-
+





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




-
+



-
+


-
-
+
+

+








-
+


















-
+















-
+







				ymx += 3;
			s.ymx = ymx + 4
		}
	}
}

/* -- split up unsuitable bars at end of staff -- */
// return true if the bar type has changed
function check_bar(s) {
	var	bar_type, i, b1, b2,
		p_voice = s.p_v

	/* search the last bar */
	while (s.type == CLEF || s.type == KEY || s.type == METER) {
		if (s.type == METER
	while (s.type == C.CLEF || s.type == C.KEY || s.type == C.METER) {
		if (s.type == C.METER
		 && s.time > p_voice.sym.time)	/* if not empty voice */
			insert_meter |= 1;	/* meter in the next line */
		s = s.prev
		if (!s)
			return
	}
	if (s.type != BAR)
	if (s.type != C.BAR)
		return

	if (s.text != undefined) {			// if repeat bar
	if (s.text != undefined) {		// if repeat bar
		p_voice.bar_start = clone(s);
		p_voice.bar_start.bar_type = "["
		p_voice.bar_start.bar_type = ""
		delete s.text
		delete s.a_gch
//		return
	}
	bar_type = s.bar_type
	if (bar_type == ":")
		return
	if (bar_type.slice(-1) != ':')	// if not left repeat bar
	if (bar_type.slice(-1) != ':')		// if not left repeat bar
		return

	if (!p_voice.bar_start)
		p_voice.bar_start = clone(s)
	if (bar_type[0] != ':') {			/* 'xx:' (not ':xx:') */
	if (bar_type[0] != ':') {		// 'xx:' (not ':xx:')
		if (bar_type == "||:") {
			p_voice.bar_start.bar_type = "|:";
			p_voice.bar_start.bar_type = "[|:";
			s.bar_type = "||"
			return
			return true
		}
		p_voice.bar_start.bar_type = bar_type
		if (s.prev && s.prev.type == BAR)
		if (s.prev && s.prev.type == C.BAR)
			unlksym(s)
		else
			s.bar_type = "|"
		return
	}
	if (bar_type == "::") {
		p_voice.bar_start.bar_type = "|:";
		s.bar_type = ":|"
		return
	}

	if (bar_type == "||:") {
		p_voice.bar_start.bar_type = "|:";
		s.bar_type = "||"
		return
	}

	// ':xx:' -> ':x|]' and '[|x:'
	// '::xx::' -> '::|' and '|::'
//fixme: do the same in abcm2ps
	i = 0
	while (bar_type[i] == ':')
		i++
	if (i < bar_type.length) {
		s.bar_type = bar_type.slice(0, i) + '|';
		s.bar_type = bar_type.slice(0, i) + '|]';
		i = bar_type.length - 1
		while (bar_type[i] == ':')
			i--;
		p_voice.bar_start.bar_type = '|' + bar_type.slice(i + 1)
		p_voice.bar_start.bar_type = '[|' + bar_type.slice(i + 1)
	} else {
		i = (bar_type.length / 2) |0;			// '::::' !
		s.bar_type = bar_type.slice(0, i) + '|';
		p_voice.bar_start.bar_type = '|' + bar_type.slice(i)
		s.bar_type = bar_type.slice(0, i) + '|]';
		p_voice.bar_start.bar_type = '[|' + bar_type.slice(i)
	}
	return true
}

/* -- move the 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 != CLEF) {
		 && s.type != C.CLEF) {
			s.st++;
			s.invis = true
		}
	}
}

// generate a block symbol
var blocks = []		// array of delayed block symbols

function block_gen(s) {
	switch (s.subtype) {
	case "leftmargin":
	case "rightmargin":
	case "pagescale":
	case "pagewidth":
	case "scale":
	case "staffwidth":
		svg_flush();
		set_format(s.subtype, s.param);
		self.set_format(s.subtype, s.param)
		break
	case "ml":
		svg_flush();
		user.img_out(s.text)
		break
	case "newpage":
		blk_flush();
		block.newpage = true;
		blk_out()
		break
	case "sep":
		set_page();
		vskip(s.sk1);
		output += '<path class="stroke"\n\td="M';
		out_sxsy(s.x, ' ', 0);
		output += 'h' + s.l.toFixed(2) + '"/>\n';
		output += 'h' + s.l.toFixed(1) + '"/>\n';
		vskip(s.sk2);
		break
	case "text":
		write_text(s.text, s.opt)
		break
	case "title":
		write_title(s.text, true)
︙
4032
4033
4034
4035
4036
4037
4038
4039

4040
4041
4042
4043
4044
4045
4046
4298
4299
4300
4301
4302
4303
4304

4305
4306
4307
4308
4309
4310
4311
4312







-
+







		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, nst, nv,
	var	s, last, p_voice, st, v, nst, 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]
︙
4117
4118
4119
4120
4121
4122
4123
4124

4125
4126
4127
4128
4129
4130
4131
4132
4133
4134

4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148

4149
4150
4151
4152
4153
4154
4155
4156
4157
4158


4159

4160
4161
4162
4163
4164
4165
4166
4167




4168
4169
4170


4171
4172
4173
4174
4175
4176
4177





4178
4179
4180
4181





4182
4183
4184


4185

4186
4187
4188
4189
4190
4191
4192
4383
4384
4385
4386
4387
4388
4389

4390
4391
4392
4393
4394
4395
4396
4397
4398
4399

4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413

4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426

4427
4428
4429
4430
4431




4432
4433
4434
4435
4436


4437
4438

4439





4440
4441
4442
4443
4444




4445
4446
4447
4448
4449



4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460







-
+









-
+













-
+










+
+
-
+




-
-
-
-
+
+
+
+

-
-
+
+
-

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

+







	 * search the next end of line,
	 * and mark the empty staves
	 */
	for (s = tsfirst; s; s = s.ts_next) {
		if (s.nl) {
//fixme: not useful
//			// delay the next block symbols
//			while (s && s.type == BLOCK) {
//			while (s && s.type == C.BLOCK) {
//				blocks.push(s);
//				unlksym(s);
//				s = s.ts_next
//			}
			break
		}
		if (!s.ts_next)
			last = s		// keep the last symbol
		switch (s.type) {
		case STAVES:
		case C.STAVES:
			set_brace();
			sy.st_print = new Uint8Array(non_empty);
			sy = s.sy;
			nst = sy.nstaff
			if (nstaff < nst) {
				for (st = nstaff + 1; st <= nst; st++)
					reset_staff(st);
				nstaff = nst
			}
			non_empty = []
			continue

		// the block symbols will be treated after music line generation
		case BLOCK:
		case C.BLOCK:
			blocks.push(s);
			unlksym(s)
			if (last)
				last = s.ts_prev
			continue
		}
		st = s.st
		if (non_empty[st])
			continue
		switch (s.type) {
		default:
			continue
		case CLEF:
		case C.CLEF:
			if (st > nstaff) {	// if clef warning/change for new staff
				staff_tb[st].clef = s;
				unlksym(s)
			}
			break
		case BAR:
			if (!sy.staves[st].staffnonote	// default = 1
			 || sy.staves[st].staffnonote <= 1)
			continue
		case C.BAR:
			if (s.bar_mrep
			 || sy.staves[st].staffnonote > 1)
				break
			// fall thru
		case GRACE:
			continue
		case C.GRACE:
			non_empty_gl[st] = non_empty[st] = true
			break
		case NOTE:
		case REST:
		case SPACE:
		case MREST:
			if (sy.staves[st].staffnonote > 1) {
		case C.NOTE:
		case C.REST:
		case C.SPACE:
		case C.MREST:
			if (sy.staves[st].staffnonote > 1)
				non_empty_gl[st] = non_empty[st] = true
			} else if (!s.invis) {
				if (sy.staves[st].staffnonote != 0
				 || s.type == NOTE)
				break
			if (s.invis)
				continue
			if (sy.staves[st].staffnonote != 0
			 || s.type == C.NOTE)
					non_empty_gl[st] = non_empty[st] = true
			}
			break
				break
			continue
		}
		non_empty_gl[st] = non_empty[st] = true
	}
	tsnext = s;

	/* set the last empty staves */
	set_brace()
//	for (st = 0; st <= nstaff; st++)
//		sy.st_print[st] = non_empty[st];
︙
4225
4226
4227
4228
4229
4230
4231
4232





4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245

4246
4247
4248
4249
4250
4251
4252

4253
4254
4255
4256
4257

4258
4259
4260

4261
4262

4263
4264
4265






4266
4267
4268



4269
4270
4271
4272

4273
4274
4275



4276
4277
4278
4279



4280
4281
4282




4283
4284
4285
4286

4287
4288
4289
4290

4291

4292
4293
4294


4295
4296
4297
4298
4299
4300


4301
4302
4303
4304
4305
4306
4307


4308
4309
4310


4311
4312
4313
4314


4315
4316
4317
4318
4319


4320
4321
4322
4323



4324
4325
4326

4327
4328
4329
4330
4331
4332



4333
4334
4335
4336
4337
4338

4339
4340
4341

4342
4343
4344


4345
4346
4347
4348

4349
4350

4351
4352
4353
4354
4355
4356









4357
4358
4359
4360
4361

4362
4363
4364
4365


4366
4367
4368
4369


4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380







4381
4382
4383
4384
4385
4386
4387
4388








4389
4390
4391
4392
4393
4394
4395
4396
4397

4398
4399
4400
4401



4402
4403
4404
4405
4406
4407
4408


4409
4410
4411
4412
4413

4414
4415
4416
4417
4418
4419

4420
4421
4422
4423
4424
4425
4426
4493
4494
4495
4496
4497
4498
4499

4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516

4517
4518



4519
4520

4521
4522
4523
4524
4525
4526
4527
4528


4529


4530



4531
4532
4533
4534
4535
4536
4537


4538
4539
4540
4541
4542

4543
4544



4545
4546
4547




4548
4549
4550



4551
4552
4553
4554
4555
4556
4557

4558
4559
4560
4561
4562
4563

4564



4565
4566

4567




4568
4569







4570
4571



4572
4573




4574
4575





4576
4577




4578
4579
4580



4581






4582
4583
4584






4585



4586



4587
4588




4589


4590






4591
4592
4593
4594
4595
4596
4597
4598
4599





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
4634
4635
4636
4637
4638
4639
4640







-
+
+
+
+
+












-
+

-
-
-


-
+





+

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

-
-
+
+
+


-

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



-
+




+
-
+
-
-
-
+
+
-

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


-
+



-

-
+







			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;
						check_bar(s)
						if (check_bar(s)) {
							tmp = s.wl;
							self.set_width(s);
							s.shrink += s.wl - tmp
						}
						break
					}
				}
				if (s)
					continue
			}
			p_voice.s_next = p_voice.sym;
			p_voice.sym = null
		}
	}

	// if the last symbol is not a bar, add an invisible bar
	if (last.type != BAR) {
	if (last.type != C.BAR) {
		s = add_end_bar(last);
		s.prev = s.ts_prev = last;
		last.ts_next = last.next = s;
		s.shrink = last.wr + 2;	// just a small space before end of staff
		s.space = set_space(s)
		if (s.space < s.shrink
		 && last.type != KEY)
		 && last.type != C.KEY)
			s.space = s.shrink
	}
}

/* -- position the symbols along the staff -- */
// (possible hook)
function set_sym_glue(width) {
	var space, beta0, alfa, beta, min, g, spafac, xmax

    var	s, g, ll,
	/* calculate the whole space of the symbols */
	var	some_grace,
	some_grace,
		s = tsfirst,
		xmin = 0,
		x = 0
	spf,			// spacing factor
	xmin = 0,		// sigma shrink = minimum spacing
	xx = 0,			// sigma natural spacing
	x = 0,			// sigma expandable elements
	xs = 0,			// sigma unexpandable elements with no space
	xse = 0			// sigma unexpandable elements with space

	while (1) {
		if (s.type == GRACE && !some_grace)
	/* 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) {
			space = s.space;
			xmin += s.shrink
			if (s.space) {
			if (space < s.shrink)
				space = s.shrink;
			x += space
				if (s.space < s.shrink) {
					xse += s.shrink;
					xx += s.shrink
//			if (cfmt.stretchstaff)
//				space *= 1.8;
//			xmax += space
		}
				} else {
					xx += s.space
				}
		if (!s.ts_next)
			break
		s = s.ts_next
			} else {
				xs += s.shrink
			}
		}
	}

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

	// last line?
	xmax = x
	ll = !tsnext ||			// yes
	if (cfmt.stretchstaff)
		xmax *= 1.8;
	/* set max shrink and stretch */
		tsnext.type == C.BLOCK	// no, but followed by %%command
		|| blocks.length	//	(abcm2ps compatibility)
	beta0 = 1			/* max expansion before complaining */

	/* memorize the glue for the last music line */
	if (tsnext
	 && blocks.length == 0 && tsnext.type != BLOCK) { // (abcm2ps compatibility)
		if (x >= width) {
	// strong shrink
	if (xmin >= width) {
			beta_last = 0
		} else {
			beta_last = (width - x) / (xmax - x)	/* stretch */
			if (beta_last > beta0) {
				if (cfmt.stretchstaff) {
					if (cfmt.linewarn) {
						error(0, s,
		if (xmin > width)
			error(1, s, "Line too much shrunk $1 $2 $3",
							"Line underfull ($1pt of $2pt)",
							(beta0 * xmax + (1 - beta0) * x).toFixed(2),
							width.toFixed(2))
				xmin.toFixed(1),
				xx.toFixed(1),
					}
				} else {
					width = x;
					beta_last = 0
				width.toFixed(1));
		x = 0
				}
			}
		}
	} else {			/* if last music line */
		if (x < width) {
		for (s = tsfirst; s; s = s.ts_next) {
			if (s.seqst)
			beta = (width - x) / (xmax - x)	/* stretch */
			if (beta >= beta_last) {
				beta = beta_last * xmax + (1 - beta_last) * x

				x += s.shrink;
			s.x = x
		}
				/* shrink underfull last line same as previous */
				if (beta < width * (1. - cfmt.stretchlast))
					width = beta
//		realwidth = width
			}
		}
	}

	spafac = width / x;			/* space expansion factor */

		spf_last = 0
	} else if ((ll && xx + xs > width * (1 - cfmt.stretchlast))
		 || (!ll && (xx + xs > width || cfmt.stretchstaff))) {
	/* define the x offsets of all starting symbols */
	x = xmax = 0;
	s = tsfirst
	while (1) {
		if (s.seqst) {
			space = s.shrink
		if (xx == xse)			// if no space
			if (s.space != 0)
				xmax += s.space * spafac * 1.8;
			x += space;
			xx += 5
			xmax += space;
			s.x = x;
			s.xmax = xmax
		for (var cnt = 4; --cnt >= 0; ) {
			spf = (width - xs - xse) / (xx - xse);
		}
		if (!s.ts_next)
			break
		s = s.ts_next
			xx = 0;
	}

			xse = 0;
	/* calculate the exact glue */
	if (x >= width) {
		beta = 0
		if (x == xmin) {
			alfa = 1			// no extra space
		} else {
			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 {
			alfa = (x - width) / (x - xmin)		/* shrink */
			if (alfa > 1) {
				error(1, s, "Line too much shrunk $1 $2 $3",
					xmin.toFixed(2),
					x.toFixed(2),
							xx += s.space;
					width.toFixed(2))
// uncomment for staff greater than music line
//				alfa = 1
			}
							x += s.space * spf
						}
		}
		realwidth = xmin * alfa + x * (1 - alfa)
	} else {
		alfa = 0
					} else {
						x += s.shrink
		if (xmax > x)
			beta = (width - x) / (xmax - x)		/* stretch */
		else
			beta = 1				/* (no note) */
		if (beta > beta0) {
			if (!cfmt.stretchstaff)
				beta = 0
		}
		realwidth = xmax * beta + x * (1 - beta)
	}

					}
				}
				s.x = x
			}
			if (Math.abs(x - width) < 0.1)
				break
		}
	/* set the final x offsets */
	s = tsfirst
	if (alfa != 0) {
		if (alfa < 1) {
			x = xmin = 0
			for (; s; s = s.ts_next) {
				if (s.seqst) {
					xmin += s.shrink * alfa;
		spf_last = spf
	} else {			// shorter line
		spf = (width - xs - xse) / xx
		if (spf_last < spf)
			spf = spf_last
		for (s = tsfirst; s; s = s.ts_next) {
			if (s.seqst)
				x += s.space * spf <= s.shrink ?
					x = xmin + s.x * (1 - alfa)
				}
				s.x = x
			}
		} else {
			alfa = realwidth / x;
			x = 0
			for (; s; s = s.ts_next) {
				if (s.seqst)
						s.shrink : s.space * spf
					x = s.x * alfa;
				s.x = x
			}
		}
			s.x = x
		}
	}
	} else {
		x = 0
		for (; s; s = s.ts_next) {
			if (s.seqst)
				x = s.xmax * beta + s.x * (1 - beta);
			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 != GRACE)
		if (s.type != C.GRACE)
			continue
		if (s.gr_shift)
			x = s.prev.x + s.prev.wr
				+ Number(cfmt.gracespace[0])
		else
			x = s.x - s.wl + Number(cfmt.gracespace[0])
			x = s.x - s.wl
		for (g = s.extra; g; g = g.next)
			g.x += x
	}
}

// set the starting symbols of the voices for the new music line
function set_sym_line() {
︙
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459



4460
4461
4462
4463
4464

4465
4466
4467

4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478

4479
4480
4481
4482
4483
4484
4485
4486
4487


4488
4489
4490
4491
4492
4493

4494
4495
4496
4497
4498
4499
4500
4501

4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517

4518
4519
4520

4521
4522
4523
4524
4525
4526
4527
4528

4529
4530
4531
4532
4533
4534
4535
4536
4537
4538



4539

4540
4541
4542
4543
4544
4545
4546
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
4697
4698
4699
4700


4701
4702

4703
4704
4705
4706

4707
4708
4709
4710
4711
4712
4713
4714

4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730

4731
4732
4733

4734
4735
4736
4737
4738
4739

4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755

4756
4757
4758
4759
4760
4761
4762
4763







-
-
-
+
+
+




-
+


-
+











+







-
-
+
+
-




-
+







-
+















-
+


-
+





-


+










+
+
+
-
+








	for ( ; s; s = s.ts_next) {
		if (s.time != tim) {
			set_page()
			return
		}
		switch (s.type) {
		case NOTE:
		case REST:
		case MREST:
		case C.NOTE:
		case C.REST:
		case C.MREST:
			set_page()
			return
		default:
			continue
		case STAVES:
		case C.STAVES:
			cur_sy = s.sy
			break
		case BLOCK:
		case C.BLOCK:
			block_gen(s)
			break
		}
		unlksym(s)
		if (s.p_v.s_next == s)
			s.p_v.s_next = s.next
	}
	tsfirst = null			/* no more notes */
}

/* -- generate the music -- */
// (possible hook)
function output_music() {
	var v, lwidth, indent, line_height

	gen_init()
	if (!tsfirst)
		return
	set_global()
	if (voice_tb.length > 1) {	/* if many voices */
		set_stem_dir()		/* set the stems direction in 'multi' */
	if (voice_tb.length > 1)	/* if many voices */
		self.set_stem_dir()	// set the stems direction in 'multi'
	}

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

	set_stems()			/* set the stem lengths */
	self.set_stems()		// set the stem lengths
	if (voice_tb.length > 1) {	/* if many voices */
		set_rest_offset();	/* set the vertical offset of rests */
		set_overlap();		/* shift the notes on voice overlap */
//		set_rp_bars()		// set repeat bars
	}
	set_acc_shft();			// set the horizontal offset of accidentals

	set_allsymwidth(null);		/* set the width of all symbols */
	set_allsymwidth();		/* set the width of all symbols */

	indent = set_indent(true)

	/* if single line, adjust the page width */
	if (cfmt.singleline) {
		v = get_ck_width();
		lwidth = indent + v[0] + v[1] + get_width(tsfirst, null);
		img.width = lwidth * cfmt.scale + img.lm + img.rm + 2
	} else {

	/* else, split the tune into music lines */
		lwidth = get_lwidth();
		cut_tune(lwidth, indent)
	}

	beta_last = 0.2
	spf_last = 1.2				// last spacing factor
	while (1) {				/* loop per music line */
		set_piece();
		set_sym_glue(lwidth - indent)
		self.set_sym_glue(lwidth - indent)
		if (realwidth != 0) {
			if (indent != 0)
				posx += indent;
			draw_sym_near();		// delayed output
			line_height = set_staff();
			delayed_update();
			draw_systems(indent);
			draw_all_sym();
			delayed_update();
			vskip(line_height)
			if (indent != 0) {
				posx -= indent;
				insert_meter &= ~2	// no more indentation
			}
			while (blocks.length != 0)
				block_gen(blocks.shift())
		}

		tsfirst = tsnext
		if (cfmt.splittune)
			blk_flush()
		else
		svg_flush()
			svg_flush()
		if (!tsnext)
			break

		// next line
		gen_init()
		if (!tsfirst)
			break
︙
Changes to core/parse.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - parse.js - ABC parse
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-2019 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.
︙
37
38
39
40
41
42
43
44

45
46
47
48
49
50
51
37
38
39
40
41
42
43

44
45
46
47
48
49
50
51







-
+







}

// -- %% pseudo-comment

// clef definition (%%clef, K: and V:)
function new_clef(clef_def) {
	var	s = {
			type: CLEF,
			type: C.CLEF,
			clef_line: 2,
			clef_type: "t",
			v: curvoice.v,
			p_v: curvoice,
			time: curvoice.time,
			dur: 0
		},
︙
92
93
94
95
96
97
98
99


100
101
102
103
104
105
106
92
93
94
95
96
97
98

99
100
101
102
103
104
105
106
107







-
+
+







//		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.key.k_sf = 0;		// no accidental
		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 = Number(clef_def[i]);
︙
118
119
120
121
122
123
124


125
126
127
128
129
130
131
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134







+
+







		s.clef_oct_transp = true
	case '-':
		s.clef_octave = -7
		break
	}
	return s
}

var note_pit = new Int8Array([0, 2, 4, 5, 7, 9, 11])

// get a transposition value
function get_transp(param,
			type) {		// undefined or "instr"
	var	i, val, tmp, note,
		pit = []

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







-
+










-
-







				param = param.replace(/.*\//, 'c')
		}
	}

	tmp = new scanBuf();
	tmp.buffer = param
	for (i = 0; i < 2; i++) {
		note = parse_acc_pit(tmp)
		note = tmp.buffer[tmp.index] ? parse_acc_pit(tmp) : null
		if (!note) {
			syntax(1, "Bad transpose value")
			return
		}
		note.pit += 124;	// 126 - 2 for value > 0 and 'C' % 7 == 0
		val = ((note.pit / 7) | 0) * 12 + note_pit[note.pit % 7]
		if (note.acc && note.acc != 3)		// if not natural
			val += note.acc;
		pit[i] = val
	}
	if (cfmt.sound)
		pit[0] = 252;			// 'c'

	val = (pit[1] - pit[0]) * 3
	if (note) {
		switch (note.acc) {
		default:
			return val
		case 2:
︙
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
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







-
+














+







		val += '|'
	return val
}

// create a block symbol in the tune body
function new_block(subtype) {
	var	s = {
			type: BLOCK,
			type: C.BLOCK,
			subtype: subtype,
			dur: 0
		}

	if (parse.state == 2)
		goto_tune()
	var voice_s = curvoice;
	curvoice = voice_tb[par_sy.top_voice]
	sym_link(s);
	curvoice = voice_s
	return s
}

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

	while (1) {
		item = a.shift()
		if (!item)
			break
︙
385
386
387
388
389
390
391
392
393

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


394
395
396
397
398
399
400
401







-
-
+







		case "cue=":
			curvoice.scale = a.shift() == 'on' ? .7 : 1
			break
		case "instrument=":
			curvoice.transp = get_transp(a.shift(), 'instr')
			break
		case "map=":			// %%voicemap
			if (cfmt.sound != "play")
				curvoice.map = a.shift()
			curvoice.map = a.shift()
			break
		case "name=":
		case "nm=":
			curvoice.nm = a.shift()
			if (curvoice.nm[0] == '"')
				curvoice.nm = curvoice.nm.slice(1, -1);
			curvoice.new_name = true
︙
445
446
447
448
449
450
451


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







+
+







			if (curvoice.snm[0] == '"')
				curvoice.snm = curvoice.snm.slice(1, -1);
			break
		case "stafflines=":
			val = get_st_lines(a.shift())
			if (val == undefined)
				syntax(1, "Bad %%stafflines value")
			else if (curvoice.st != undefined)
				par_sy.staves[curvoice.st].stafflines = val
			else
				curvoice.stafflines = val
			break
		case "staffnonote=":
			val = parseInt(a.shift())
			if (isNaN(val))
				syntax(1, "Bad %%staffnonote value")
︙
510
511
512
513
514
515
516
517

518
519
520
521
522
523
524
513
514
515
516
517
518
519

520
521
522
523
524
525
526
527







-
+







			if (info.V['*'])
				a = info.V['*'].concat(a)
			if (info.V[curvoice.id])
				a = info.V[curvoice.id].concat(a)
		}
	}
	if (a.length != 0)
		set_vp(a)
		self.set_vp(a)
} // set_kv_parm()

// memorize the K:/V: parameters
function memo_kv_parm(vid,	// voice ID (V:) / '*' (K:/V:*)
			a) {	// array of items
	if (a.length == 0)
		return
︙
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
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







-
+



















-
-
-

-
-
+
+






-


+








// K: key signature
// return the key and the voice/clef parameters
function new_key(param) {
	var	i, clef, key_end, c, tmp,
		mode = 0,
		s = {
			type: KEY,
			type: C.KEY,
			k_delta: 0,
			dur:0
		}

	set_ref(s);

	// tonic
	i = 1
	switch (param[0]) {
	case 'A': s.k_sf = 3; break
	case 'B': s.k_sf = 5; break
	case 'C': s.k_sf = 0; break
	case 'D': s.k_sf = 2; break
	case 'E': s.k_sf = 4; break
	case 'F': s.k_sf = -1; break
	case 'G': s.k_sf = 1; break
	case 'H':				// bagpipe
		switch (param[1]) {
		case 'P':
			s.k_bagpipe = "P";
			i++
			break
		case 'p':
			s.k_bagpipe = "p";
			s.k_sf = 2;
			s.k_bagpipe = param[1];
			s.k_sf = param[1] == 'P' ? 0 : 2;
			i++
			break
		default:
			syntax(1, "Unknown bagpipe-like key")
			break
		}
		key_end = true
		break
	case 'P':
		syntax(1, "K:P is deprecated");
		s.k_drum = true;
		key_end = true
		break
	case 'n':				// none
		if (param.indexOf("none") == 0) {
			s.k_sf = 0;
			s.k_none = true;
︙
589
590
591
592
593
594
595








596
597
598
599
600
601
602
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610







+
+
+
+
+
+
+
+







	if (!key_end) {
		switch (param[i]) {
		case '#': s.k_sf += 7; i++; break
		case 'b': s.k_sf -= 7; i++; break
		}
		param = param.slice(i).trim()
		switch (param.slice(0, 3).toLowerCase()) {
		default:
			if (param[0] != 'm'
			 || (param[1] != ' ' && param[1] != '\t'
			  && param[1] != '\n')) {
				key_end = true
				break
			}
			// fall thru ('m')
		case "aeo":
		case "m":
		case "min": s.k_sf -= 3;
			mode = 5
			break
		case "dor": s.k_sf -= 2;
			mode = 1
︙
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
619
620
621
622
623
624
625










626
627
628
629
630
631
632







-
-
-
-
-
-
-
-
-
-







			break
		case "mix": s.k_sf -= 1;
			mode = 4
			break
		case "phr": s.k_sf -= 4;
			mode = 2
			break
		default:
			if (param[0] == 'm'
			 && (param[1] == ' ' || param[1] == '\t'
			  || param[1] == '\n')) {
				s.k_sf -= 3;
				mode = 5
				break
			}
			key_end = true
			break
		}
		if (!key_end)
			param = param.replace(/\w+\s*/, '')

		// [exp] accidentals
		if (param.indexOf("exp ") == 0) {
			param = param.replace(/\w+\s*/, '')
︙
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
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







-
+



-
+

-
+








-






-
+


-
+





-
+
-
-
-
+
+
+



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









-
+







			param = param.replace(/\w+\s*/, '')
		}
	}

	s.k_delta = cgd2cde[(s.k_sf + 7) % 7];
	s.k_mode = mode

	return [s, info_split(param, 0)]
	return [s, info_split(param)]
}

// M: meter
function new_meter(text) {
function new_meter(p) {
	var	s = {
			type: METER,
			type: C.METER,
			dur: 0,
			a_meter: []
		},
		meter = {},
		val, v,
		m1 = 0, m2,
		i = 0, j,
		wmeasure,
		p = text,
		in_parenth;

	set_ref(s)

	if (p.indexOf("none") == 0) {
		i = 4;				/* no meter */
		wmeasure = 1;	// simplify measure numbering and MREST conversion
		wmeasure = 1;	// simplify measure numbering and C.MREST conversion
	} else {
		wmeasure = 0
		while (i < text.length) {
		while (i < p.length) {
			if (p[i] == '=')
				break
			switch (p[i]) {
			case 'C':
				meter.top = p[i++]
				if (p[i] == '|')
				if (!m1) {
					meter.top += p[i++];
				m1 = 4;
				m2 = 4
					m1 = 4;
					m2 = 4
				}
				break
			case 'c':
			case 'o':
				meter.top = p[i++]
				if (!m1) {
				m1 = p[i] == 'c' ? 4 : 3;
				m2 = 4;
				meter.top = p[i++]
				if (p[i] == '.')
					meter.top += p[i++]
					if (p[-1] == 'c') {
						m1 = 2;
						m2 = 4
					} else {
						m1 = 3;
						m2 = 4
					}
					switch (p[i]) {
					case '|':
						m2 /= 2
						break
					case '.':
						m1 *= 3;
						m2 *= 2
						break
					}
				}
				break
			case '.':
			case '|':
				meter.top = p[i++]
				break
			case '(':
				if (p[i + 1] == '(') {	/* "M:5/4 ((2+3)/4)" */
					in_parenth = true;
					meter.top = p[i++];
					s.a_meter.push(meter);
					meter = {}
				}
				j = i + 1
				while (j < text.length) {
				while (j < p.length) {
					if (p[j] == ')' || p[j] == '/')
						break
					j++
				}
				if (p[j] == ')' && p[j + 1] == '/') {	/* "M:5/4 (2+3)/4" */
					i++		/* remove the parenthesis */
					continue
︙
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
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







-
+










-
+


















-
+



+
+
+

-
+






-
-
+
+

-
+







						meter.bot = p[i++]
						while (p[i] >= '0' && p[i] <= '9')
							meter.bot += p[i++]
						break
					}
					if (p[i] != ' ' && p[i] != '+')
						break
					if (i >= text.length
					if (i >= p.length
					 || p[i + 1] == '(')	/* "M:5 (2/4+3/4)" */
						break
					meter.top += p[i++]
				}
				m1 = parseInt(meter.top)
				break
			}
			if (!in_parenth) {
				if (meter.bot)
					m2 = parseInt(meter.bot);
				wmeasure += m1 * BASE_LEN / m2
				wmeasure += m1 * C.BLEN / m2
			}
			s.a_meter.push(meter);
			meter = {}
			while (p[i] == ' ')
				i++
			if (p[i] == '+') {
				meter.top = p[i++];
				s.a_meter.push(meter);
				meter = {}
			}
		}
	}
	if (p[i] == '=') {
		val = p.substring(++i).match(/^(\d+)\/(\d+)$/)
		if (!val) {
			syntax(1, "Bad duration '$1' in M:", p.substring(i))
			return
		}
		wmeasure = BASE_LEN * val[1] / val[2]
		wmeasure = C.BLEN * val[1] / val[2]
	}
	s.wmeasure = wmeasure

	if (cfmt.writefields.indexOf('M') < 0)
		s.a_meter = []

	if (parse.state != 3) {
		info.M = text;
		info.M = p;
		glovar.meter = s
		if (parse.state >= 1) {

			/* in the tune header, change the unit note length */
			if (!glovar.ulen) {
				if (wmeasure <= 1
				 || wmeasure >= BASE_LEN * 3 / 4)
					glovar.ulen = BASE_LEN / 8
				 || wmeasure >= C.BLEN * 3 / 4)
					glovar.ulen = C.BLEN / 8
				else
					glovar.ulen = BASE_LEN / 16
					glovar.ulen = C.BLEN / 16
			}
			for (v = 0; v < voice_tb.length; v++) {
				voice_tb[v].meter = s;
				voice_tb[v].wmeasure = wmeasure
			}
		}
	} else {
︙
819
820
821
822
823
824
825
826

827
828
829
830
831
832
833
837
838
839
840
841
842
843

844
845
846
847
848
849
850
851







-
+







	}
}

/* Q: tempo */
function new_tempo(text) {
	var	i = 0, j, c, nd, tmp,
		s = {
			type: TEMPO,
			type: C.TEMPO,
			dur: 0
		}

	set_ref(s)

	if (cfmt.writefields.indexOf('Q') < 0)
		s.del = true			// don't display
︙
853
854
855
856
857
858
859
860

861
862
863
864
865
866
867
871
872
873
874
875
876
877

878
879
880
881
882
883
884
885







-
+







//		c = tmp.char()
		c = text[tmp.index]
		if (c == undefined || c <= '0' || c > '9')
			break
		nd = parse_dur(tmp)
		if (!s.tempo_notes)
			s.tempo_notes = []
		s.tempo_notes.push(BASE_LEN * nd[0] / nd[1])
		s.tempo_notes.push(C.BLEN * nd[0] / nd[1])
		while (1) {
//			c = tmp.char()
			c = text[tmp.index]
			if (c != ' ')
				break
			tmp.index++
		}
︙
879
880
881
882
883
884
885
886

887
888
889
890
891
892
893
897
898
899
900
901
902
903

904
905
906
907
908
909
910
911







-
+







			tmp.index += 4;
//			c = text[tmp.index]
		}
		if (text[tmp.index + 1] != '/') {
			s.tempo = tmp.get_int()
		} else {
			nd = parse_dur(tmp);
			s.new_beat = BASE_LEN * nd[0] / nd[1]
			s.new_beat = C.BLEN * nd[0] / nd[1]
		}
		c = text[tmp.index]
		while (c == ' ')
			c = text[++tmp.index]
	}

	/* string after */
︙
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
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







-
+










-
+






-
+







function do_info(info_type, text) {
	var s, d1, d2, a, vid

	switch (info_type) {

	// info fields in any state
	case 'I':
		do_pscom(text)
		self.do_pscom(text)
		break
	case 'L':
//fixme: ??
		if (parse.state == 2)
			goto_tune();
		a = text.match(/^1\/(\d+)(=(\d+)\/(\d+))?$/)
		if (a) {
			d1 = Number(a[1])
			if (!d1 || (d1 & (d1 - 1)) != 0)
				break
			d1 = BASE_LEN / d1
			d1 = C.BLEN / d1
			if (a[2]) {
				d2 = Number(a[4])
				if (!d2 || (d2 & (d2 - 1)) != 0) {
					d2 = 0
					break
				}
				d2 = Number(a[3]) / d2 * BASE_LEN
				d2 = Number(a[3]) / d2 * C.BLEN
			} else {
				d2 = d1
			}
		} else if (text == "auto") {
			d1 = d2 = -1
		}
		if (!d2) {
︙
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
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







-
+













-
+







			break
		}
		if (parse.state == 2)
			goto_tune()
		if (cfmt.writefields.indexOf(info_type) < 0)
			break
		s = {
			type: PART,
			type: C.PART,
			text: text,
			dur: 0
		}

		/*
		 * If not in the main voice, then,
		 * if the voices are synchronized and no P: yet in the main voice,
		 * the misplaced P: goes into the main voice.
		 */
		var p_voice = voice_tb[par_sy.top_voice]
		if (curvoice.v != p_voice.v) {
			if (curvoice.time != p_voice.time)
				break
			if (p_voice.last_sym && p_voice.last_sym.type == PART)
			if (p_voice.last_sym && p_voice.last_sym.type == C.PART)
				break		// already a P:
			var voice_sav = curvoice;
			curvoice = p_voice;
			sym_link(s);
			curvoice = voice_sav
		} else {
			sym_link(s)
︙
1029
1030
1031
1032
1033
1034
1035
1036

1037
1038
1039
1040
1041
1042
1043
1047
1048
1049
1050
1051
1052
1053

1054
1055
1056
1057
1058
1059
1060
1061







-
+







			info[info_type] += '\n' + text
		break
	case 'r':
		if (!user.keep_remark
		 || parse.state != 3)
			break
		s = {
			type: REMARK,
			type: C.REMARK,
			text: text,
			dur: 0
		}
		sym_link(s)
		break
	default:
		syntax(0, "'$1:' line ignored", info_type)
︙
1053
1054
1055
1056
1057
1058
1059
1060
1061


1062
1063

1064
1065
1066
1067
1068
1069
1070
1071
1072

1073
1074
1075
1076
1077
1078
1079
1071
1072
1073
1074
1075
1076
1077


1078
1079
1080

1081
1082
1083
1084
1085
1086
1087
1088
1089

1090
1091
1092
1093
1094
1095
1096
1097







-
-
+
+

-
+








-
+








	/* search the start of the measure */
	s2 = curvoice.last_sym
	if (!s2)
		return;

	/* the bar time is correct if there are multi-rests */
	if (s2.type == MREST
	 || s2.type == BAR)			/* in second voice */
	if (s2.type == C.MREST
	 || s2.type == C.BAR)			/* in second voice */
		return
	while (s2.type != BAR && s2.prev)
	while (s2.type != C.BAR && s2.prev)
		s2 = s2.prev;
	time = s2.time;
	auto_time = curvoice.time - time

	/* remove the invisible rest at start of tune */
	if (time == 0) {
		while (s2 && !s2.dur)
			s2 = s2.next
		if (s2 && s2.type == REST
		if (s2 && s2.type == C.REST
		 && s2.invis) {
			time += s2.dur * curvoice.wmeasure / auto_time
			if (s2.prev)
				s2.prev.next = s2.next
			else
				curvoice.sym = s2.next
			if (s2.next)
︙
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
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







-
+




-
-
-
-
-
-
-
-









-
+







	for ( ; s2; s2 = s2.next) {
		s2.time = time
		if (!s2.dur || s2.grace)
			continue
		s2.dur = s2.dur * curvoice.wmeasure / auto_time;
		s2.dur_orig = s2.dur_orig * curvoice.wmeasure / auto_time;
		time += s2.dur
		if (s2.type != NOTE && s2.type != REST)
		if (s2.type != C.NOTE && s2.type != C.REST)
			continue
		for (i = 0; i <= s2.nhd; i++)
			s2.notes[i].dur = s2.notes[i].dur
					 * curvoice.wmeasure / auto_time;
		res = identify_note(s2, s2.dur_orig);
		s2.head = res[0];
		s2.dots = res[1];
		s2.nflags = res[2]
		if (s2.nflags <= -2)
			s2.stemless = true
		else
			delete s2.stemless
	}
	curvoice.time = s.time = time
}

/* -- parse a bar -- */
function new_bar() {
	var	s2, c, bar_type,
		line = parse.line,
		s = {
			type: BAR,
			type: C.BAR,
			fname: parse.fname,
			istart: parse.bol + line.index,
			dur: 0,
			multi: 0		// needed for decorations
		}

	if (vover && vover.bar)			// end of voice overlay
︙
1146
1147
1148
1149
1150
1151
1152
1153

1154
1155
1156
1157



















1158
1159
1160
1161
1162
1163
1164
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







-
+




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







		} else {
			s.rbstop = 2		// right repeat with end
		}
	}

	// set the guitar chord and the decorations
	if (a_gch)
		gch_build(s)
		self.gch_build(s)
	if (a_dcn) {
		deco_cnv(a_dcn, s);
		a_dcn = null
	}

	// set the start/stop of ottava
	if (parse.ottava != undefined) {
		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
		delete parse.ottava
	}

	/* if the last element is '[', it may start
	 * a chord or an embedded header */
	switch (bar_type.slice(-1)) {
	case '[':
		if (/[0-9" ]/.test(c))		// "
			break
︙
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
1270
1271
1272
1273
1274
1275
1253
1254
1255
1256
1257
1258
1259




1260
1261
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
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319







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



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

-
-
+
+

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







	 && !curvoice.second)
		s.norepbra = true

	if (curvoice.ulen < 0)			// L:auto
		adjust_dur(s);

	s2 = curvoice.last_sym
	if (s2 && s2.type == SPACE) {
		s2.time--		// keep the space at the right place
	} else if (s2 && s2.type == BAR) {
//fixme: why these next lines?
	if (s2 && s2.time == curvoice.time) {
		if (s2.type == C.SPACE) {
			s2.time--		// keep the space at the right place
		} else if (bar_type == "["
			|| bar_type == "|:") {

			// 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 == 0
		  || (par_sy.staves[curvoice.st - 1].flags & STOP_BAR)
		  || s.norepbra)) {
			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
				// remove the invisible repeat bars
				// when no shift is needed
				if (bar_type == "["
				 && !s2.text
				 && (curvoice.st == 0
				  || (par_sy.staves[curvoice.st - 1].flags & STOP_BAR)
				  || s.norepbra)) {
					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
		}
					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
				// merge back-to-back repeat bars
				if (s2.st == curvoice.st
				 && 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 "[":
︙
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
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







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








-
+







	}
	s.bar_type = bar_type
	if (!curvoice.lyric_restart)
		curvoice.lyric_restart = s
	if (!curvoice.sym_restart)
		curvoice.sym_restart = s

	/* the bar must appear before a key signature */
	if (s2 && s2.type == KEY
	 && (!s2.prev || s2.prev.type != BAR)) {
		curvoice.last_sym = s2.prev
		if (!s2.prev)
			curvoice.sym = s2.prev;	// null
		sym_link(s);
	sym_link(s);
		s.next = s2;
		s2.prev = s;
		curvoice.last_sym = s2
	} else {
		sym_link(s)
	}

	s.st = curvoice.st			/* original staff */

	/* if repeat bar and shift, add a repeat bar */
	if (s.rbstart
	 && !curvoice.norepbra
	 && curvoice.st > 0
	 && !(par_sy.staves[curvoice.st - 1].flags & STOP_BAR)) {
		s2 = {
			type: BAR,
			type: C.BAR,
			fname: s.fname,
			istart: s.istart,
			iend: s.iend,
			bar_type: "[",
			multi: 0,
			invis: true,
			text: s.text,
︙
1342
1343
1344
1345
1346
1347
1348


1349
1350





1351
1352

1353
1354
1355


1356

1357
1358
1359
1360
1361
1362
1363
1375
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







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

+







		a_vf = [],
		err = false,
		flags = 0,
		brace = 0,
		bracket = 0,
		parenth = 0,
		flags_st = 0,
	e,
	a = p.match(/\w+|[^\s]/g)
		i = 0


	if (!a) {
		syntax(1, errs.bad_val, "%%staves")
		return // null
	}
	/* parse the voices */
	while (i < p.length) {
	while (1) {
		switch (p[i]) {
		case ' ':
		case '\t':
		e = a.shift()
		if (!e)
			break
		switch (e) {
		case '[':
			if (parenth || brace + bracket >= 2) {
				syntax(1, errs.misplaced, '[');
				err = true
				break
			}
			flags |= brace + bracket == 0 ? OPEN_BRACKET : OPEN_BRACKET2;
︙
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
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







-
+






-
-
-
+
+
+
+

-
-
-
-
+
-
-
-







			if (brace && !parenth && !(flags & (OPEN_BRACE | OPEN_BRACE2)))
				flags |= FL_VOICE
			break
		case '+':
			flags |= MASTER_VOICE
			break
		default:
			if (!/\w/.test(p[i])) {
			if (!/\w/.test(e)) {
				syntax(1, "Bad voice ID in %%staves");
				err = true
				break
			}

			/* get / create the voice in the voice table */
			vid = ""
			while (i < p.length) {
				if (" \t()[]{}|*".indexOf(p[i]) >= 0)
			vid = e
			while (1) {
				e = a.shift()
				if (!e)
					break
				vid += p[i++]
			}
			for ( ; i < p.length; i++) {
				switch (p[i]) {
				switch (e) {
				case ' ':
				case '\t':
					continue
				case ']':
					if (!(flags_st & OPEN_BRACKET)) {
						syntax(1, errs.misplaced, ']');
						err = true
						break
					}
					bracket--;
︙
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
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
1545
1546

1547

1548
1549
1550

1551
1552
1553
1554

1555
1556
1557

1558
1559
1560

1561
1562
1563

1564
1565
1566
1567
1568
1569
1570
1571







+
-
+
+
+

-














-
+

+



-
-




-
-
+
+
+
+


-
-
+
+

-
+






-
+


-
+

+
+
-
+



-

-
+


-
+



-
+


-
+


-
+


-
+







					flags |= STOP_BAR
					continue
				}
				break
			}
			a_vf.push([vid, flags]);
			flags = 0
			if (!e)
			continue
				break
			a.unshift(e)
			break
		}
		i++
	}
	if (flags_st != 0) {
		syntax(1, "'}', ')' or ']' missing in %%staves");
		err = true
	}
	if (err || a_vf.length == 0)
		return //null
	return a_vf
}

// split an info string
function info_split(text) {
	if (!text)
		return []
    var	a = text.match(/(".+?"|.+?)(\s+|=|$)/g)
    var	a = text.match(/=?[^\s"=]+=?|".+?"/g)	// "
	if (!a) {
//fixme: bad error text
		syntax(1, "Unterminated string")
		return []
	}
	for (var i = 0; i < a.length; i++)
		a[i] = a[i].trim()
	return a
}

/* -- get head type, dots, flags of note/rest for a duration -- */
function identify_note(s, dur) {
	var head, dots, flags
function identify_note(s, dur_o) {
    var	head, dots, flags,
	dots = 0,
	dur = dur_o

	if (dur % 12 != 0)
		syntax(1, "Invalid note duration $1", dur);
	dur /= 12			/* see BASE_LEN for values */
		error(1, s, "Invalid note duration $1", dur);
	dur /= 12			/* see C.BLEN for values */
	if (dur == 0)
		syntax(1, "Note too short")
		error(1, s, "Note too short")
	for (flags = 5; dur != 0; dur >>= 1, flags--) {
		if (dur & 1)
			break
	}
	dur >>= 1
	switch (dur) {
	case 0: dots = 0; break
	case 0: break
	case 1: dots = 1; break
	case 3: dots = 2; break
//	case 7: dots = 3; break
	case 7: dots = 3; break
	default:
		error(1, s, "Invalid note duration $1", dur_o);
		flags += ((11 - dur) / 4) | 0;
		dots = 3
		dots = 4
		break
	}
	flags -= dots
//--fixme: is 'head' useful?
	if (flags >= 0) {
		head = FULL
		head = C.FULL
	} else switch (flags) {
	default:
		syntax(1, "Note too long");
		error(1, s, "Note too long");
		flags = -4
		/* fall thru */
	case -4:
		head = SQUARE
		head = C.SQUARE
		break
	case -3:
		head = cfmt.squarebreve ? SQUARE : OVALBARS
		head = cfmt.squarebreve ? C.SQUARE : C.OVALBARS
		break
	case -2:
		head = OVAL
		head = C.OVAL
		break
	case -1:
		head = EMPTY
		head = C.EMPTY
		break
	}
	return [head, dots, flags]
}

// parse a duration and return [numerator, denominator]
// 'line' is not always 'parse.line'
︙
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634




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







-














-
-
-
-
+
+
+
+

-
+

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

-
+













-
+







	}
	while (c == ',') {
		pit -= 7;
		c = line.next_char()
	}
	note = {
		pit: pit,
		apit: pit,
		shhd: 0,
		shac: 0,
		ti1: 0
	}
	if (acc) {
		note.acc = acc
		if (micro_n) {
			note.micro_n = micro_n;
			note.micro_d = micro_d
		}
	}
	return note
}

/* set the mapping of a note */
function set_map(note) {
	var	bn, an, nn, i,
		map = maps[curvoice.map]	// never null
// convert a note pitch to ABC text
function note2abc(note) {
    var	i,
	abc = 'abcdefg'[(note.pit + 77) % 7]

	bn = 'abcdefg'[(note.pit + 77) % 7]
//fixme: treat microtone
	if (note.acc)
		an = ['__', '_', '', '^', '^^', '='][note.acc + 2]
		abc = ['__', '_', '', '^', '^^', '='][note.acc + 2] + abc
	else
		an = ''
//fixme: treat microtone
	nn = an + bn
	for (i = note.pit; i >= 28; i -= 7)
		nn += "'"
	for (i = note.pit; i < 21; i += 7)
		nn += ",";

	for (i = note.pit; i >= 30; i -= 7)	// down to 'c'
		abc += "'"
	for (i = note.pit; i < 23; i += 7)	// up to 'C'
		abc += ","
	return abc
}

/* set the mapping of a note */
function set_map(note) {
    var	map = maps[curvoice.map],	// never null
	nn = note2abc(note)

	if (!map[nn]) {
		nn = 'octave,' + an + bn		// octave
		nn = 'octave,' + nn.replace(/[',]/g, '')	// octave '
		if (!map[nn]) {
			nn = 'key,' +			// 'key,'
				'abcdefg'[(note.pit + 77 -
						curvoice.ckey.k_delta) % 7]
			if (!map[nn]) {
				nn = 'all'		// 'all'
				if (!map[nn])
					return
			}
		}
	}
	note.map = map[nn]
	if (note.map[1]) {
		note.apit = note.pit = note.map[1].pit;	// print
		note.pit = note.map[1].pit;		// print/play
		note.acc = note.map[1].acc
	}
}

/* -- parse note or rest with pitch and length -- */
// 'line' is not always 'parse.line'
function parse_basic_note(line, ulen) {
︙
1686
1687
1688
1689
1690
1691
1692
1693

1694
1695
1696
1697

1698
1699
1700

1701
1702

1703
1704
1705
1706
1707
1708
1709
1724
1725
1726
1727
1728
1729
1730

1731
1732
1733
1734

1735
1736
1737

1738
1739

1740
1741
1742
1743
1744
1745
1746
1747







-
+



-
+


-
+

-
+








function parse_vpos() {
	var	c,
		line = parse.line,
		ti1 = 0

	if (line.buffer[line.index - 1] == '.' && !a_dcn)
		ti1 = SL_DOTTED
		ti1 = C.SL_DOTTED
	switch (line.next_char()) {
	case "'":
		line.index++
		return ti1 + SL_ABOVE
		return ti1 + C.SL_ABOVE
	case ",":
		line.index++
		return ti1 + SL_BELOW
		return ti1 + C.SL_BELOW
	}
	return ti1 + SL_AUTO
	return ti1 + C.SL_AUTO
}

var	cde2fcg = new Int8Array([0, 2, 4, -1, 1, 3, 5]),
	cgd2cde = new Int8Array([0, 4, 1, 5, 2, 6, 3]),
	acc2 = new Int8Array([-2, -1, 3, 1, 2])

/* transpose a note / chord */
︙
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1758
1759
1760
1761
1762
1763
1764

1765
1766
1767
1768
1769
1770
1771







-







	dp += ((t / 3 / 12) | 0) * 7
	for (i = 0; i <= m; i++) {
		note = s.notes[i];

		// pitch
		n = note.pit;
		note.pit += dp;
		note.apit = note.pit;

		// accidental
		i1 = cde2fcg[(n + 5 + 16 * 7) % 7];	/* fcgdaeb */
		a = note.acc
		if (!a) {
			if (!curvoice.okey.a_acc) {
				if (sf_old > 0) {
︙
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
1884
1885
1886
1887
1888

1889
1890
1891
1892

1893
1894
1895
1896
1897
1898
1899
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







-










-



















+










-
+















-
+











-
+







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



-
+











-
+



-
+







				} else {
					a = -i1
				}
				break
			case 2:			// double sharp
				if (n > d / 2) {
					note.pit += 1;
					note.apit = note.pit;
					n -= d / 2
				} else {
					n += d / 2
				}
				a = i1;
				note.micro_n = n
				break
			case -2:		// double flat
				if (n >= d / 2) {
					note.pit -= 1;
					note.apit = note.pit;
					n -= d / 2
				} else {
					n += d / 2
				}
				a = i1;
				note.micro_n = n
				break
			}
		}
		note.acc = a
	}
}

/* sort the notes of the chord by pitch (lowest first) */
function sort_pitch(s) {
	s.notes = s.notes.sort(function(n1, n2) {
			return n1.pit - n2.pit
		})
}
// (possible hook)
function new_note(grace, tp_fact) {
	var	note, s, in_chord, c, dcn, type,
		i, n, s2, nd, res, num, dur,
		sl1 = 0,
		line = parse.line,
		a_dcn_sav = a_dcn;	// save parsed decoration names

	a_dcn = null;
	parse.stemless = false;
	s = {
		type: NOTE,
		type: C.NOTE,
		fname: parse.fname,
		stem: 0,
		multi: 0,
		nhd: 0,
		xmx: 0
	}
	s.istart = parse.bol + line.index

	if (curvoice.color)
		s.color = curvoice.color

	if (grace) {
		s.grace = true
	} else {
		if (a_gch)
			gch_build(s)
			self.gch_build(s)
		if (parse.repeat_n) {
			s.repeat_n = parse.repeat_n;
			s.repeat_k = parse.repeat_k;
			parse.repeat_n = 0
		}
	}
	c = line.char()
	switch (c) {
	case 'X':
		s.invis = true
	case 'Z':
		s.type = MREST;
		s.type = C.MREST;
		c = line.next_char()
		s.nmes = (c > '0' && c <= '9') ? line.get_int() : 1;
		s.dur = curvoice.wmeasure * s.nmes

		// ignore if in second voice
		if (curvoice.second) {
			curvoice.time += s.dur
			return null
			return //null
		}

		// convert 'Z'/'Z1' to a whole measure rest
		if (s.nmes == 1) {
			s.type = C.REST;
			s.dur_orig = s.dur;
			s.notes = [{
				pit: 18,
				dur: s.dur
			}]
		}
		break
	case 'y':
		s.type = SPACE;
		s.type = C.SPACE;
		s.invis = true;
		s.dur = 0;
		c = line.next_char()
		if (c >= '0' && c <= '9')
			s.width = line.get_int()
		else
			s.width = 10
		break
	case 'x':
		s.invis = true
	case 'z':
		s.type = REST;
		s.type = C.REST;
		line.index++;
		nd = parse_dur(line);
		s.dur_orig = ((curvoice.ulen < 0) ?
					15120 :	// 2*2*2*2*3*3*3*5*7
					C.BLEN :
					curvoice.ulen) * nd[0] / nd[1];
		s.dur = s.dur_orig * curvoice.dur_fact;
		s.notes = [{
			pit: 18,
			dur: s.dur_orig
		}]
		break
︙
1913
1914
1915
1916
1917
1918
1919
1920

1921
1922
1923
1924
1925
1926
1927
1959
1960
1961
1962
1963
1964
1965

1966
1967
1968
1969
1970
1971
1972
1973







-
+







			if (in_chord) {
				while (1) {
					if (!c)
						break
					i = c.charCodeAt(0);
					if (i >= 128) {
						syntax(1, errs.not_ascii)
						return null
						return //null
					}
					type = char_tb[i]
					switch (type[0]) {
					case '(':
						sl1 <<= 4;
						sl1 += parse_vpos();
						c = line.char()
︙
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
1994
1995
1996
1997
1998
1999
2000

2001
2002

2003
2004
2005
2006
2007
2008
2009



2010
2011
2012
2013
2014
2015
2016
2017







-
+

-
+






-
-
-
+







						c = line.next_char()
						continue
					}
					break
				}
			}
			note = parse_basic_note(line,
					s.grace ? BASE_LEN / 4 :
					s.grace ? C.BLEN / 4 :
					curvoice.ulen < 0 ?
						15120 :	// 2*2*2*2*3*3*3*5*7
						C.BLEN :
						curvoice.ulen)
			if (!note)
				return //null

			// transpose
			if (curvoice.octave)
				note.apit = note.pit += curvoice.octave * 7
			if (curvoice.ottava)
				note.pit += curvoice.ottava
				note.pit += curvoice.octave * 7
			if (sl1) {
				note.sl1 = sl1
				if (s.sl1)
					s.sl1++
				else
					s.sl1 = 1;
				sl1 = 0
︙
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
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







-
+







-
-
-
+
+
+







			}
		}

		// the duration of the chord is the duration of the 1st note
		s.dur_orig = s.notes[0].dur;
		s.dur = s.notes[0].dur * curvoice.dur_fact
	}
	if (s.grace && s.type != NOTE) {
	if (s.grace && s.type != C.NOTE) {
		syntax(1, "Not a note in grace note sequence")
		return //null
	}

	if (s.notes) {				// if note or rest
		if (!s.grace) {
			switch (curvoice.pos.stm) {
			case SL_ABOVE: s.stem = 1; break
			case SL_BELOW: s.stem = -1; break
			case SL_HIDDEN: s.stemless = true; break
			case C.SL_ABOVE: s.stem = 1; break
			case C.SL_BELOW: s.stem = -1; break
			case C.SL_HIDDEN: s.stemless = true; break
			}

			// adjust the symbol duration
			s.dur *= tp_fact;
			num = curvoice.brk_rhythm
			if (num) {
				curvoice.brk_rhythm = 0;
︙
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
2155
2156
2157
2158
2159


2160
2161
2162
2163
2164
2165
2166
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
2155
2156

2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188


2189
2190
2191
2192
2193
2194
2195
2196
2197







-
-
-
-
-
-
-
-






-
+









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


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





-
+




















+
+
+
+







-
-
+
+







					s2.dur = s2.dur * n / num;
					s2.dur_orig = s2.dur_orig * n / num
					for (i = 0; i <= s2.nhd; i++)
						s2.notes[i].dur =
							s2.notes[i].dur * n / num
				}
				curvoice.time = s2.time + s2.dur;
				res = identify_note(s2, s2.dur_orig);
				s2.head = res[0];
				s2.dots = res[1];
				s2.nflags = res[2]
				if (s2.nflags <= -2)
					s2.stemless = true
				else
					delete s2.stemless

				// adjust the time of the grace notes, bars...
				for (s2 = s2.next; s2; s2 = s2.next)
					s2.time = curvoice.time
			}
		} else {		/* grace note - adjust its duration */
			var div = curvoice.key.k_bagpipe ? 8 : 4
			var div = curvoice.ckey.k_bagpipe ? 8 : 4

			for (i = 0; i <= s.nhd; i++)
				s.notes[i].dur /= div;
			s.dur /= div;
			s.dur_orig /= div
			if (grace.stem)
				s.stem = grace.stem
		}

		// set the symbol parameters
		// adjust the duration
		if (s.type == NOTE) {
			res = identify_note(s, s.dur_orig);
		dur = s.dur_orig
			s.head = res[0];
			s.dots = res[1];
			s.nflags = res[2]
			if (s.nflags <= -2)
				s.stemless = true
		} else {					// rest
		if (curvoice.ulen < 0) {
			dur = C.BLEN
		} else if (s.type == C.REST

			/* change the figure of whole measure rests */
//--fixme: does not work in sample.abc because broken rhythm on measure bar
//--fixme: does not work in abcm2ps sample.abc because broken rhythm on measure bar
			dur = s.dur_orig
			if (dur == curvoice.wmeasure) {
				if (dur < BASE_LEN * 2)
					dur = BASE_LEN
				else if (dur < BASE_LEN * 4)
					dur = BASE_LEN * 2
				else
					dur = BASE_LEN * 4
			}
			&& dur == curvoice.wmeasure) {
			if (dur < C.BLEN * 2)
				dur = C.BLEN
			else if (dur < C.BLEN * 4)
				dur = C.BLEN * 2
			else
				dur = C.BLEN * 4
		}
			res = identify_note(s, dur);
			s.head = res[0];
			s.dots = res[1];
			s.nflags = res[2]
		}

		curvoice.last_note = s
	}

	sym_link(s)

	if (s.type == NOTE) {
	if (s.type == C.NOTE) {
		if (curvoice.vtransp)
			note_transp(s)
		if (curvoice.map
		 && maps[curvoice.map]) {
			for (i = 0; i <= s.nhd; i++)
				set_map(s.notes[i])
		}
	}

	if (cfmt.shiftunison)
		s.shiftunison = cfmt.shiftunison
	if (!grace) {
		if (!curvoice.lyric_restart)
			curvoice.lyric_restart = s
		if (!curvoice.sym_restart)
			curvoice.sym_restart = s
	}

	if (a_dcn_sav)
		deco_cnv(a_dcn_sav, s, s.prev)
	if (parse.ottava != undefined) {
		s.ottava = parse.ottava
		delete parse.ottava
	}
	if (parse.stemless)
		s.stemless = true
	s.iend = parse.bol + line.index
	return s
}

// characters in the music line (ASCII only)
var nil = ["0"]
var char_tb = [
var nil = ["0"],
    char_tb = [
	nil, nil, nil, nil,		/* 00 - .. */
	nil, nil, nil, nil,
	nil, " ", "\n", nil,		/* . \t \n . */
	nil, nil, nil, nil,
	nil, nil, nil, nil,
	nil, nil, nil, nil,
	nil, nil, nil, nil,
︙
2188
2189
2190
2191
2192
2193
2194
2195



2196
2197
2198
2199
2200
2201
2202
2219
2220
2221
2222
2223
2224
2225

2226
2227
2228
2229
2230
2231
2232
2233
2234
2235







-
+
+
+







	"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,
		tp_a = [], tp,
		tpn = -1,
		tp_fact = 1,
		slur_start = 0,
︙
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412



2413
2414
2415
2416
2417
2418
2419
2436
2437
2438
2439
2440
2441
2442



2443
2444
2445
2446
2447
2448
2449
2450
2451
2452







-
-
-
+
+
+







				continue
			case ')':			// slur end
				if (curvoice.ignore)
					break
				s = curvoice.last_sym
				if (s) {
					switch (s.type) {
					case NOTE:
					case REST:
					case SPACE:
					case C.NOTE:
					case C.REST:
					case C.SPACE:
						break
					default:
						s = null
						break
					}
				}
				if (!s) {
︙
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
2468
2476
2477
2478
2479
2480
2481
2482



2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494

2495
2496
2497
2498
2499
2500
2501
2502







-
-
-
+
+
+
+








-
+







					}
					if (!c) {
						line.index = i;
						syntax(1, "No end of decoration")
						break
					}
				}
				if (ottava[dcn])
					set_ottava(dcn)
				a_dcn.push(dcn)
				if (ottava[dcn] != undefined)
					parse.ottava = ottava[dcn]
				else
					a_dcn.push(dcn)
				break
			case '"':
				parse_gchord(type)
				break
			case '-':
			    var tie_pos = 0

				if (!curvoice.last_note
				 || curvoice.last_note.type != NOTE) {
				 || curvoice.last_note.type != C.NOTE) {
					syntax(1, "No note before '-'")
					break
				}
				tie_pos = parse_vpos();
				s = curvoice.last_note
				for (i = 0; i <= s.nhd; i++) {
					if (!s.notes[i].ti1)
︙
2499
2500
2501
2502
2503
2504
2505
2506

2507
2508
2509

2510
2511
2512
2513
2514
2515
2516
2533
2534
2535
2536
2537
2538
2539

2540
2541
2542

2543
2544
2545
2546
2547
2548
2549
2550







-
+


-
+







					line.index = 0;
					do_info(c_next, text);
					line.index = i
					continue
				}
				// fall thru ('[' is start of chord)
			case 'n':				// note/rest
				s = new_note(grace, tp_fact)
				s = self.new_note(grace, tp_fact)
				if (!s)
					continue
				if (s.type == NOTE) {
				if (s.type == C.NOTE) {
					if (slur_start) {
						s.slur_start = slur_start;
						slur_start = 0
					}
				}
				if (grace) {
//fixme: tuplets in grace notes?
︙
2542
2543
2544
2545
2546
2547
2548



2549

2550
2551
2552
2553



2554

2555
2556
2557
2558
2559
2560
2561
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585

2586
2587
2588
2589
2590
2591
2592
2593

2594
2595
2596
2597
2598
2599
2600
2601







+
+
+
-
+




+
+
+
-
+







						s.tq0 = tp.q;
						s.tf = tp.f;	// %%tuplets
						tp.p = 0
					}
					tp.r--
					if (tp.r == 0) {
						if (tpn-- == 0) {
							if (s.tp0)	// if one note
								s.tp0 = false
							else
							s.te0 = true;
								s.te0 = true;
							tp_fact = 1;
							curvoice.time = Math.round(curvoice.time);
							s.dur = curvoice.time - s.time
						} else {
							if (s.tp1)	// if one note
								s.tp1 = false
							else
							s.te1 = true;
								s.te1 = true;
							tp = tp_a[0]
							if (tp.r == 0) {
								tpn--;
								s.te0 = true;
								tp_fact = 1;
								curvoice.time = Math.round(curvoice.time);
								s.dur = curvoice.time - s.time
︙
2590
2591
2592
2593
2594
2595
2596
2597

2598
2599
2600
2601
2602
2603
2604
2605
2606



2607
2608
2609
2610
2611
2612
2613
2630
2631
2632
2633
2634
2635
2636

2637
2638
2639
2640
2641
2642
2643



2644
2645
2646
2647
2648
2649
2650
2651
2652
2653







-
+






-
-
-
+
+
+







					break
				}
				last_note_sav = curvoice.last_note;
				curvoice.last_note = null;
				a_dcn_sav = a_dcn;
				a_dcn = undefined;
				grace = {
					type: GRACE,
					type: C.GRACE,
					fname: parse.fname,
					istart: parse.bol + line.index,
					dur: 0,
					multi: 0
				}
				switch (curvoice.pos.gst) {
				case SL_ABOVE: grace.stem = 1; break
				case SL_BELOW: grace.stem = -1; break
				case SL_HIDDEN:	grace.stem = 2; break	/* opposite */
				case C.SL_ABOVE: grace.stem = 1; break
				case C.SL_BELOW: grace.stem = -1; break
				case C.SL_HIDDEN: grace.stem = 2; break	/* opposite */
				}
				sym_link(grace);
				c = line.next_char()
				if (c == '/') {
					grace.sappo = true	// acciaccatura
					break
				}
︙
2633
2634
2635
2636
2637
2638
2639
2640

2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2673
2674
2675
2676
2677
2678
2679

2680
2681
2682
2683
2684




2685
2686
2687
2688
2689
2690
2691







-
+




-
-
-
-







				s.gr_end = true;
				grace.extra = grace.next;
				grace.extra.prev = null;
				grace.next = null;
				curvoice.last_sym = grace;
				grace = null
				if (!s.prev			// if one grace note
				 && !curvoice.key.k_bagpipe) {
				 && !curvoice.ckey.k_bagpipe) {
					for (i = 0; i <= s.nhd; i++)
						s.notes[i].dur *= 2;
					s.dur *= 2;
					s.dur_orig *= 2
					var res = identify_note(s, s.dur_orig);
					s.head = res[0];
					s.dots = res[1];
					s.nflags = res[2]
				}
				curvoice.last_note = last_note_sav;
				a_dcn = a_dcn_sav
				break
			case "\\":
				c = line.buffer[line.index + 1]
				if (!c) {
︙
Changes to core/subs.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
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


-
+
















-
-
+
+

+
+
-
+















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












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







// abc2svg - subs.js - text output
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-2019 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/>.

/* width of characters according to the encoding */
/* these are the widths for Times-Roman, extracted from the 'a2ps' package */
// width of characters according to the font type
// these tables were created from the font 'Liberation'

// serif
  var
var cw_tb = new Float32Array([
    sw_tb = new Float32Array([
	.000,.000,.000,.000,.000,.000,.000,.000,	// 00
	.000,.000,.000,.000,.000,.000,.000,.000,
	.000,.000,.000,.000,.000,.000,.000,.000,	// 10
	.000,.000,.000,.000,.000,.000,.000,.000,
	.250,.333,.408,.500,.500,.833,.778,.333,	// 20
	.333,.333,.500,.564,.250,.564,.250,.278,
	.500,.500,.500,.500,.500,.500,.500,.500,	// 30
	.500,.500,.278,.278,.564,.564,.564,.444,
	.921,.722,.667,.667,.722,.611,.556,.722,	// 40
	.722,.333,.389,.722,.611,.889,.722,.722,
	.556,.722,.667,.556,.611,.722,.722,.944,	// 50
	.722,.722,.611,.333,.278,.333,.469,.500,
	.333,.444,.500,.444,.500,.444,.333,.500,	// 60
	.500,.278,.278,.500,.278,.778,.500,.500,
	.500,.500,.333,.389,.278,.500,.500,.722,	// 70
	.500,.500,.444,.480,.200,.480,.541,.500
])
	.500,.500,.444,.480,.200,.480,.541,.500]),
// sans-serif
    ssw_tb = new Float32Array([
	.000,.000,.000,.000,.000,.000,.000,.000,	// 00
	.000,.000,.000,.000,.000,.000,.000,.000,
	.000,.000,.000,.000,.000,.000,.000,.000,	// 10
	.000,.000,.000,.000,.000,.000,.000,.000,
	.278,.278,.355,.556,.556,.889,.667,.191,	// 20
	.333,.333,.389,.584,.278,.333,.278,.278,
	.556,.556,.556,.556,.556,.556,.556,.556,	// 30
	.556,.556,.278,.278,.584,.584,.584,.556,
       1.015,.667,.667,.722,.722,.667,.611,.778,	// 40
	.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
function strwh(str) {
}

// estimate the width and height of a string ..
var strwh = typeof document != "undefined" ?

    // .. by the browser
    (function(el) {
	el.style.position = 'absolute';
	el.style.top = '-1000px';
	el.style.padding = '0';
	document.body.appendChild(el)

	return function(str) {
	    var	c,
		font = gene.curfont,
		h = font.size,
		w = 0,
		n = str.length,
		i0 = 0,
		i = 0

		el.style.font = style_font(font).slice(5);

		while (1) {
			i = str.indexOf('$', i)
			if (i < 0)
				break
			c = str[i + 1]
			if (c == '0') {
				font = gene.deffont
			} else if (c >= '1' && c <= '9') {
				font = get_font("u" + c)
			} else {
				i++
				continue
			}
			el.innerHTML = str.slice(i0, i);
			w += el.clientWidth
			if (font.size > h)
				h = font.size;

			el.style.font = style_font(font).slice(5);
			i += 2;
			i0 = i
		}
		el.innerHTML = str.slice(i0);
		w += el.clientWidth;

		gene.curfont = font
		return [w, h]
	}
    })(document.createElement('div')) :

    // .. by internal tables
    function(str) {
    var	font = gene.curfont,
	swfac = font.swfac,
	h = font.size,
	w = 0,
	i, j, c,
	n = str.length

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







+









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

















-











-
-
+


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


+



-
+


+








-
-
+
+
-
-


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







	return [w, h]
}

// 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) {
	var	n_font,
		o_font = gene.curfont,
		c_font = o_font;

	output += str.replace(/<|>|&.*?;|&|  |\$./g, function(c){
	output += str.replace(/\$./g, function(c) {
			switch (c[0]) {
			case '<': return "&lt;"
			case '>': return "&gt;"
			case '&':
				if (c == '&')
					 return "&amp;"
				return c
			case ' ':
				return '  '		// space + nbspace
			case '$':
				if (c[1] == '0') {
					n_font = gene.deffont;
					use_font(n_font)
				} else if (c[1] >= '1' && c[1] <= '9')
					n_font = get_font("u" + c[1])
				else
					return c
				c = ''
				if (n_font == c_font)
					return c
				if (c_font != o_font)
					c = "</tspan>";
				c_font = n_font
				if (c_font == o_font)
					return c
				return c + '<tspan\n\tclass="' +
						font_class(n_font) + '">'
			}
		})
	if (c_font != o_font) {
		output += "</tspan>";
		gene.curfont = c_font	// keep current font for next paragraph
	}
}

// output a string, handling the font changes
// the action is:
//	'c' align center
//	'r' align right
//	'\t' handle the tabulations - dx is the space between the fields
//	'j' justify - line_w is the line width
//	'j' justify - w is the line width
//	otherwise align left
function xy_str(x, y, str,
		 action,
		 line_w) {
    var	h = strwh(str)[1];
	y += h * .2;			// a bit upper for the descent
	output += '<text class="' + font_class(gene.curfont) + '" x="';
	out_sxsy(x, '" y="', y)
		action,		// default: align left
		w,		// needed for justify
		wh) {		// optional [width, height]
	if (!wh)
		wh = strwh(str);

	output += '<text class="' + font_class(gene.curfont)
	if (action != 'j' && str.length > 5
	 && gene.curfont.wadj)
		output += '" lengthAdjust="' + gene.curfont.wadj +
			'" textLength="' + wh[0].toFixed(1);
	output += '" x="';
	out_sxsy(x, '" y="', y + wh[1] * .2)	// a bit upper for the descent
	switch (action) {
	case 'c':
		x -= wh[0] / 2;
		output += '" text-anchor="middle">'
		break
	case 'j':
		output += '" textLength="' + line_w.toFixed(2) + '">'
		output += '" textLength="' + w.toFixed(1) + '">'
		break
	case 'r':
		x -= wh[0];
		output += '" text-anchor="end">'
		break
	default:
		output += '">'
		break
	}
	out_str(str);
	output += "</text>\n"
}


	if (!w && gene.curfont.box) {
// output a string in a box
function xy_str_b(x, y, str) {
// not in the SVG documentation,
// but this works for almost all browsers but firefox
//	output += '<g style="outline: solid black;\
// outline-width: 1px">\n';
//	xy_str(x, y, str, action, line_w);
//	output += '</g>\n'
//		output += '<g style="outline: solid black;\
//			outline-width: 1px">\n';
//	//	xy_str(x, y, str, action, w);
//		output += '</g>\n'
    var	wh = strwh(str);

	output += '<rect class="stroke" x="';
	out_sxsy(x - 2, '" y="', y + wh[1] + 1);
	output += '" width="' + (wh[0] + 4).toFixed(2) +
		'" height="' + (wh[1] + 3).toFixed(2) +
		'"/>\n';
		output += '<rect class="stroke" x="';
		out_sxsy(x - 2, '" y="', y + wh[1]);
		output += '" width="' + (wh[0] + 4).toFixed(1) +
			'" height="' + (wh[1] + 2).toFixed(1) +
			'"/>\n'
	xy_str(x, y, str)
	}
}

/* -- move trailing "The" to front, set to uppercase letters or add xref -- */
function trim_title(title, is_subtitle) {
	var i

	if (cfmt.titletrim) {
︙
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
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
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







-
+












-
+
+

-
+

-
+
















-
-
-
-
-






+
-
+


















+




-
-
+
+
+
+
+















-
-
+
+
+
+
+

















+





+
-
-
+
+
+
+
+






+
-
-
+
+
+
+







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

// header generation functions
function write_title(title, is_subtitle) {
    var	font, h
    var	h, wh

	if (!title)
		return
	set_page();
	title = trim_title(title, is_subtitle)
	if (is_subtitle) {
		set_font("subtitle");
		h = cfmt.subtitlespace
	} else {
		set_font("title");
		h = cfmt.titlespace
	}
	vskip(strwh(title)[1] + h)
	wh = strwh(title);
	vskip(wh[1] + h)
	if (cfmt.titleleft)
		xy_str(0, 0, title)
		xy_str(0, 0, title, null, null, wh)
	else
		xy_str(get_lwidth() / 2, 0, title, "c")
		xy_str(get_lwidth() / 2, 0, title, "c", null, wh)
}

/* -- output a header format '111 (222)' -- */
function put_inf2r(x, y, str1, str2, action) {
	if (!str1) {
		if (!str2)
			return
		str1 = str2;
		str2 = null
	}
	if (!str2)
		xy_str(x, y, str1, action)
	else
		xy_str(x, y, str1 + ' (' + str2 + ')', action)
}

// let vertical room for a text line
function str_skip(str) {
	vskip(strwh(str)[1] * cfmt.lineskipfac)
}

/* -- write a text block (%%begintext / %%text / %%center) -- */
function write_text(text, action) {
	if (action == 's')
		return				// skip
	set_font("text");
	set_page();
    var	wh, font,
	var	strlw = get_lwidth(),
	strlw = get_lwidth(),
		sz = gene.curfont.size,
		lineskip = sz * cfmt.lineskipfac,
		parskip = sz * cfmt.parskipfac,
		p_start = block.started ? function(){} : blk_out,
		p_flush = block.started ? svg_flush : blk_flush,
		i, j, x, words, w, k, ww, str;

	p_start()
	switch (action) {
	default:
//	case 'c':
//	case 'r':
		switch (action) {
		case 'c': x = strlw / 2; break
		case 'r': x = strlw; break
		default: x = 0; break
		}
		j = 0
		font = gene.curfont
		while (1) {
			i = text.indexOf('\n', j)
			if (i < 0) {
				str = text.slice(j);
				str_skip(str);
				xy_str(x, 0, str, action)
				wh = strwh(str);
				gene.curfont = font;
				vskip(wh[1]  * cfmt.lineskipfac);
				xy_str(x, 0, str, action, null, wh);
				font = gene.curfont
				break
			}
			if (i == j) {			// new paragraph
				vskip(parskip);
				p_flush();
				use_font(gene.curfont)
				while (text[i + 1] == '\n') {
					vskip(lineskip);
					i++
				}
				if (i == text.length)
					break
				p_start()
			} else {
				str = text.slice(j, i);
				str_skip(str);
				xy_str(x, 0, str, action)
				wh = strwh(str);
				gene.curfont = font;
				vskip(wh[1]  * cfmt.lineskipfac);
				xy_str(x, 0, str, action, null, wh);
				font = gene.curfont
			}
			j = i + 1
		}
		vskip(parskip);
		p_flush()
		break
	case 'f':
	case 'j':
		j = 0
		while (1) {
			i = text.indexOf('\n\n', j)
			if (i < 0)
				words = text.slice(j)
			else
				words = text.slice(j, i);
			words = words.split(/\s+/);
			w = k = 0
			font = gene.curfont
			for (j = 0; j < words.length; j++) {
				ww = strwh(words[j] + ' ')[0];
				w += ww
				if (w >= strlw) {
					str = words.slice(k, j).join(' ');
					gene.curfont = font;
					str_skip(str);
					xy_str(0, 0, str, action, strlw);
					wh = strwh(str);
					gene.curfont = font;
					vskip(wh[1]  * cfmt.lineskipfac);
					xy_str(0, 0, str, action, strlw, wh);
					font = gene.curfont;
					k = j;
					w = ww
				}
			}
			if (w != 0) {
				str = words.slice(k).join(' ');
				gene.curfont = font;
				str_skip(str);
				xy_str(0, 0, str)
				wh = strwh(str);
				gene.curfont = font;
				vskip(wh[1]  * cfmt.lineskipfac);
				xy_str(0, 0, str, null, null, wh)
			}
			vskip(parskip);
			p_flush()
			if (i < 0)
				break
			while (text[i + 2] == '\n') {
				vskip(lineskip);
︙
393
394
395
396
397
398
399
400
401
402
403
404
405

406
407
408
409
410
411
412
475
476
477
478
479
480
481

482
483
484
485

486
487
488
489
490
491
492
493







-




-
+







		if (k != 0)
			xy_str(x, 0, p.slice(j, k), 'r')
		if (i < p.length)
			xy_str(x + 5, 0, p.slice(i), 'l')
		return i >= p.length && k == 0
	} // put_wline()

	blk_out();
	set_font("words")

	/* see if we may have 2 columns */
	var	middle = get_lwidth() / 2,
		max2col = (middle - 45.) / (cwid('a') * gene.curfont.swfac);
		max2col = (middle - 45.) / cwidf('a');
	n = 0;
	words = words.split('\n');
	nw = words.length
	for (i = 0; i < nw; i++) {
		p = words[i]
/*fixme:utf8*/
		if (p.length > max2col) {
︙
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
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







-
+




















+
-
-
+
+







			i2++
		}
	}
}

/* -- output history -- */
function put_history() {
	var	i, j, c, str, font, h, w, head,
	var	i, j, c, str, font, h, w, wh, head,
		names = cfmt.infoname.split("\n"),
		n = names.length

	for (i = 0; i < n; i++) {
		c = names[i][0]
		if (cfmt.writefields.indexOf(c) < 0)
			continue
		str = info[c]
		if (!str)
			continue
		if (!font) {
			font = true;
			set_font("history");
			vskip(cfmt.textspace);
			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);
		w = strwh(head)[0];
		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);
︙
662
663
664
665
666
667
668

669
670
671
672
673
674
675
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758







+







			if (info_sz[c])
				sz += info_sz[c];
			set_font(font);
			x = xa[align];
			y = ya[align] + sz

			if (c == 'Q') {			/* special case for tempo */
				set_width(glovar.tempo)
				if (!glovar.tempo.del) {
					if (align != 'l') {
						var w = tempo_width(glovar.tempo)

						if (align == 'c')
							w *= .5;
						x -= w
︙
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
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







-







+











+







			}
			write_title(info.T.slice(i, j), i != 0);
			i = j + 1
		}
	}

	/* rhythm, composer, origin */
	set_font("composer");
//	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'
︙
Changes to core/svg.js.
1
2
3

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







24
25
26
27
28
29
30
1
2

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



21
22
23
24
25
26
27
28
29
30
31
32
33
34


-
+

















-
-
-
+
+
+
+
+
+
+







// abc2svg - svg.js - svg functions
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-2019 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	output = "",		// output buffer
	style = '\n.fill {fill: currentColor}\
\n.stroke {stroke: currentColor; fill: none}\
\n.music text, .music tspan {fill:currentColor}',
	style = '\n.fill{fill:currentColor}\
\n.stroke{stroke:currentColor;fill:none}\
\n.bW{stroke-width:1}\
\n.bthW{stroke-width:3}\
\n.slW{stroke-width:.7}\
\n.slthW{stroke-width:1.5}\
\n.sW{stroke-width:.7}',
	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
︙
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
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







+

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




+



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

-
+



-
+


-
-
+
+

+
+

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

+
+
+

-
+



-
+










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


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




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







		g: 0
//		color: undefined
	},
	block = {}		/* started & newpage */

// glyphs in music font
var tgls = {
 "mtr ": {x:0, y:0, c:"\u0020"},	// space
  brace: {x:0, y:0, c:"\ue000"},
  hl: {x:-4, y:0, c:"\ue022"},
  hl1: {x:-6, y:0, c:"\ue023"},
//  hl2: {x:-6, y:0, c:"\ue023"},		// (unused)
  ghl: {x:-4, y:0, c:"\ue024"},
  lphr: {x:0, y:24, c:"\ue030"},
  mphr: {x:0, y:24, c:"\ue038"},
  sphr: {x:0, y:27, 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:4, c:"\ue047"},
  coda: {x:-12, y:6, c:"\ue048"},
  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"},
  sbclef: {x:-7, y:0, c:"\ue07c"},
  oct: {x:0, y:2, c:"\ue07d"},		// 8 for clefs
  meter0: {c:"\ue080"},
  meter1: {c:"\ue081"},
  meter2: {c:"\ue082"},
  meter3: {c:"\ue083"},
  meter4: {c:"\ue084"},
  meter5: {c:"\ue085"},
  meter6: {c:"\ue086"},
  meter7: {c:"\ue087"},
  meter8: {c:"\ue088"},
  meter9: {c:"\ue089"},
  "meter+": {c:"\ue08c"},
  "meter(": {c:"\ue094"},
  "meter)": {c:"\ue095"},
  csig: {x:0, y:0, c:"\ue08a"},
  ctsig: {x:0, y:0, c:"\ue08b"},
  mtr0: {x:0, y:0, c:"\ue080"},		// meters
  mtr1: {x:0, y:0, c:"\ue081"},
  mtr2: {x:0, y:0, c:"\ue082"},
  mtr3: {x:0, y:0, c:"\ue083"},
  mtr4: {x:0, y:0, c:"\ue084"},
  mtr5: {x:0, y:0, c:"\ue085"},
  mtr6: {x:0, y:0, c:"\ue086"},
  mtr7: {x:0, y:0, c:"\ue087"},
  mtr8: {x:0, y:0, c:"\ue088"},
  mtr9: {x:0, y:0, c:"\ue089"},
  mtrC: {x:0, y:0, c:"\ue08a"},		// common time (4/4)
//  "mtrC|": {x:0, y:0, c:"\ue08b"},	// cut time (2/2) (unused)
  "mtr+":  {x:0, y:0, c:"\ue08c"},
  "mtr(":  {x:0, y:0, c:"\ue094"},
  "mtr)":  {x:0, y:0, c:"\ue095"},
  HDD: {x:-7, y:0, c:"\ue0a0"},
  breve: {x:-6, y:0, c:"\ue0a1"},
  breve: {x:-7, y:0, c:"\ue0a1"},
  HD: {x:-5.2, y:0, c:"\ue0a2"},
  Hd: {x:-3.8, y:0, c:"\ue0a3"},
  hd: {x:-3.7, y:0, c:"\ue0a4"},
  ghd: {x:2, y:0, c:"\ue0a4", sc:.66},
  ghd: {x:2, y:0, c:"\ue0a4", sc:.66},	// grace note head
  pshhd: {x:-3.7, y:0, c:"\ue0a9"},
  pfthd: {x:-3.7, y:0, c:"\ue0b3"},
  x: {x:-3.7, y:0, c:"\ue0a9"},
  "circle-x": {x:-3.7, y:0, c:"\ue0b3"},
  x: {x:-3.7, y:0, c:"\ue0a9"},		// 'x' note head
  "circle-x": {x:-3.7, y:0, c:"\ue0b3"}, // 'circle-x' note head
  srep: {x:-5, y:0, c:"\ue101"},
  diamond: {x:-4, y:0, c:"\ue1b9"},
  triangle: {x:-4, y:0, c:"\ue1bb"},
  dot: {x:-2, y:0, c:"\ue1e7"},
  flu1: {x:-.3, y:0, c:"\ue240"},	// flags
  fld1: {x:-.3, y:0, c:"\ue241"},
  flu2: {x:-.3, y:0, c:"\ue242"},
  fld2: {x:-.3, y:0, c:"\ue243"},
  flu3: {x:-.3, y:3.5, c:"\ue244"},
  fld3: {x:-.3, y:-4, c:"\ue245"},
  flu4: {x:-.3, y:8, c:"\ue246"},
  fld4: {x:-.3, y:-9, c:"\ue247"},
  flu5: {x:-.3, y:12.5, c:"\ue248"},
  fld5: {x:-.3, y:-14, c:"\ue249"},
 "acc-1": {x:-3, y:0, c:"\ue260"},
  acc3: {x:-2, y:0, c:"\ue261"},
  acc1: {x:-3, y:0, c:"\ue262"},
  acc2: {x:-3, y:0, c:"\ue263"},
 "acc-2": {x:-3, y:0, c:"\ue264"},
 "acc-1_1_4": {x:-3, y:0, c:"\ue280"},
 "acc-1": {x:-1, y:0, c:"\ue260"},	// flat
  acc3: {x:-1, y:0, c:"\ue261"},	// natural
  acc1: {x:-2, y:0, c:"\ue262"},	// sharp
  acc2: {x:-3, y:0, c:"\ue263"},	// double sharp
 "acc-2": {x:-3, y:0, c:"\ue264"},	// double flat
 "acc-1_1_4": {x:-2, y:0, c:"\ue280"},	// quarter-tone flat
 "acc-1_3_4": {x:-3, y:0, c:"\ue281"},	// three-quarter-tones flat
  acc1_1_4: {x:-1, y:0, c:"\ue282"},	// quarter-tone sharp
  acc1_3_4: {x:-3, y:0, c:"\ue283"},	// three-quarter-tones sharp
  accent: {x:-3, y:0, 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:0, c:"\ue4ac"},
  hld: {x:-7, y:0, c:"\ue4c0"},
  hld: {x:-7, y:0, c:"\ue4c0"},		// fermata
  brth: {x:0, y:0, c:"\ue4ce"},
  r00: {x:-1.5, y:0, c:"\ue4e1"},
  r0: {x:-1.5, y:0, c:"\ue4e2"},
  r1: {x:-3.5, y:6, c:"\ue4e3"},
  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:-4, y:-6, c:"\ue522"},
  pppp: {x:-4, y:-6, c:"\ue529"},
  ppp: {x:-4, y:-6, c:"\ue52a"},
  pp: {x:-4, y:-6, c:"\ue52b"},
  mp: {x:-4, y:-6, c:"\ue52c"},
  mf: {x:-4, y:-6, c:"\ue52d"},
  ff: {x:-4, y:-6, c:"\ue52f"},
  fff: {x:-4, y:-6, c:"\ue530"},
  ffff: {x:-4, y:-6, c:"\ue531"},
  sfz: {x:-4, y:-6, c:"\ue539"},
  trl: {x:-4, y:-4, c:"\ue566"},	// trill
  turn: {x:-5, y:4, c:"\ue567"},
  turnx: {x:-5, y:4, c:"\ue569"},
  umrd: {x:-7, y:2, c:"\ue56c"},
  lmrd: {x:-7, y:2, c:"\ue56d"},
  turn: {x:-5, y:-4, c:"\ue567"},
  turnx: {x:-5, y:-4, c:"\ue569"},
  umrd: {x:-7, y:-2, c:"\ue56c"},
  lmrd: {x:-7, y:-2, c:"\ue56d"},
  dplus: {x:-4, y:10, c:"\ue582"},	// plus
  sld: {x:-8, y:12, c:"\ue5d4"},	// 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:0, 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
// "mtrc|": {x:0, y:0, c:"\ue918"},	// (unused)
 "mtr.":  {x:0, y:0, c:"\ue920"},	// prolatione perfecta
 "mtr|":  {x:0, y:0, c:"\ue925"},	// (twice as fast)
  longa: {x:-6, y:0, c:"\ue95c"}
  longa: {x:-3.7, y:0, c:"\ue95d"},
  custos: {x:-4, y:3, c:"\uea02"},
  ltr: {x:2, y:6, c:"\ueaa4"}		// long trill element
}

// glyphs to put in <defs>
var glyphs = {
}
  acc1_1_4: '<g id="acc1_1_4">\n\

	<path d="m0 7.8v-15.4" class="stroke"/>\n\
	<path class="fill" d="M-1.8 2.7l3.6 -1.1v2.2l-3.6 1.1v-2.2z\n\
		M-1.8 -3.7l3.6 -1.1v2.2l-3.6 1.1v-2.2"/>\n\
</g>',
  acc1_3_4: '<g id="acc1_3_4">\n\
	<path d="m-2.5 8.7v-15.4M0 7.8v-15.4M2.5 6.9v-15.4" class="stroke"/>\n\
	<path class="fill" d="m-3.7 3.1l7.4 -2.2v2.2l-7.4 2.2v-2.2z\n\
// convert a meter string to a SmuFL encoded string
function m_gl(s) {
	return s.replace(/[Cco]\||[co]\.|./g,
		function(e) {
		    var	m = tgls["mtr" + e]
			if (!m.x && !m.y)
		M-3.7 -3.2l7.4 -2.2v2.2l-7.4 2.2v-2.2"/>\n\
</g>',
 "acc-1_3_4": '<g id="acc-1_3_4">\n\
    <path class="fill" d="m0.6 -2.7\n\
	c-5.7 -3.1 -5.7 3.6 0 6.7c-3.9 -4 -4 -7.6 0 -5.8\n\
	M1 -2.7c5.7 -3.1 5.7 3.6 0 6.7c3.9 -4 4 -7.6 0 -5.8"/>\n\
    <path d="m1.6 3.5v-13M0 3.5v-13" class="stroke" stroke-width=".6"/>\n\
</g>',
  pmsig: '<path id="pmsig" class="stroke" stroke-width="0.8"\n\
	d="m0 -7a5 5 0 0 1 0 -10a5 5 0 0 1 0 10"/>',
  pMsig: '<g id="pMsig">\n\
	<use xlink:href="#pmsig"/>\n\
				return m.c
	<path class="fill" d="m0 -10a2 2 0 0 1 0 -4a2 2 0 0 1 0 4"/>\n\
</g>',
  imsig: '<path id="imsig" class="stroke" stroke-width="0.8"\n\
	d="m3 -8a5 5 0 1 1 0 -8"/>',
  iMsig: '<g id="iMsig">\n\
	<use xlink:href="#imsig"/>\n\
	<path class="fill" d="m0 -10a2 2 0 0 1 0 -4a2 2 0 0 1 0 4"/>\n\
</g>',
  hl: '<path id="hl" class="stroke" stroke-width="1" d="m-6 0h12"/>',
  hl1: '<path id="hl1" class="stroke" stroke-width="1" d="m-7 0h14"/>',
  hl2: '<path id="hl2" class="stroke" stroke-width="1" d="m-9 0h18"/>',
  ghl: '<path id="ghl" class="stroke" d="m-3.5 0h7"/>',
  rdots: '<g id="rdots" class="fill">\n\
	<circle cx="0" cy="-9" r="1.2"/>\n\
	<circle cx="0" cy="-15" r="1.2"/>\n\
</g>',
  grm: '<path id="grm" class="fill" d="m-5 -2.5\n\
	c5 -8.5 5.5 4.5 10 -2 -5 8.5 -5.5 -4.5 -10 2"/>',
  stc: '<circle id="stc" class="fill" cx="0" cy="-3" r="1.2"/>',
  sld: '<path id="sld" class="fill" d="m-7.2 4.8\n\
	c1.8 .7 4.5 -.2 7.2 -4.8 -2.1 5 -5.4 6.8 -7.6 6"/>',
  emb: '<path id="emb" class="stroke" stroke-width="1.2" stroke-linecap="round"\n\
	d="m-2.5 -3h5"/>',
  roll: '<path id="roll" class="fill" d="m-6 0\n\
	c0.4 -7.3 11.3 -7.3 11.7 0 -1.3 -6 -10.4 -6 -11.7 0"/>',
  upb: '<path id="upb" class="stroke" d="m-2.6 -9.4\n\
	l2.6 8.8 2.6 -8.8"/>',
  dnb: '<g id="dnb">\n\
	<path d="M-3.2 -2v-7.2m6.4 0v7.2" class="stroke"/>\n\
	<path d="M-3.2 -6.8v-2.4l6.4 0v2.4" class="fill"/>\n\
</g>',
  dplus: '<path id="dplus" class="stroke" stroke-width="1.7"\n\
	d="m0 -.5v-6m-3 3h6"/>',
  lphr: '<path id="lphr" class="stroke" stroke-width="1.2"\n\
	d="m0 0v18"/>',
  mphr: '<path id="mphr" class="stroke" stroke-width="1.2"\n\
	d="m0 0v12"/>',
  sphr: '<path id="sphr" class="stroke" stroke-width="1.2"\n\
	d="m0 0v6"/>',
  sfz: '<text id="sfz" x="-5" y="-7" \
style="font-family:serif; font-style:italic; font-size:14px">\n\
	s<tspan font-size="16" font-weight="bold">f</tspan>z</text>',
			return '<tspan dx="'+ m.x.toFixed(1) +
  trl: '<text id="trl" x="-2" y="-4"\n\
	style="font-family:serif; font-weight:bold; \
font-style:italic; font-size:16px">tr</text>',
  opend: '<circle id="opend" class="stroke"\n\
	cx="0" cy="-3" r="2.5"/>',
				'" dy="' + m.y.toFixed(1) + '">' +
  snap: '<path id="snap" class="stroke" d="m-3 -6\n\
	c0 -5 6 -5 6 0 0 5 -6 5 -6 0\n\
	M0 -5v6"/>',
  thumb: '<path id="thumb" class="stroke" d="m-2.5 -7\n\
	c0 -6 5 -6 5 0 0 6 -5 6 -5 0\n\
	M-2.5 -9v4"/>',
  wedge: '<path id="wedge" class="fill" d="m0 -1l-1.5 -5h3l-1.5 5"/>',
  ltr: '<path id="ltr" class="fill"\n\
	d="m0 -.4c2 -1.5 3.4 -1.9 3.9 .4 0.2 .8 .7 .7 2.1 -.4\n\
	v0.8c-2 1.5 -3.4 1.9 -3.9 -.4 -.2 -.8 -.7 -.7 -2.1 .4z"/>',
  custos: '<g id="custos">\n\
	<path class="fill" d="m-4 0l2 2.5 2 -2.5 2 2.5 2 -2.5\n\
		-2 -2.5 -2 2.5 -2 -2.5 -2 2.5"/>\n\
	<path class="stroke" d="m3.5 0l5 -7"/>\n\
</g>',
				m.c + '</tspan>'
  triangle: '<path id="triangle" class="fill" d="m-3.7 -3.2l7.4 0 -3.7 6.4 -3.7 -6.4"/>',
  diamond: '<path id="diamond" class="fill" d="m0 3.5l-3.7 -3.5 3.7 -3.5 3.7 3.5z"/>',
  oct: '<text id="oct" style="font-family:serif; font-size:12px">8</text>'
		})
}

// mark a glyph as used and add it in <defs>
function def_use(gl) {
	var	i, j, g

	if (defined_glyph[gl])
︙
299
300
301
302
303
304
305
306

307
308
309
310
311
312
313
293
294
295
296
297
298
299

300
301
302
303
304
305
306
307







-
+







	output += ">\n";
	stv_g.started = true
}

/* set the color */
function set_color(color) {
	if (color == stv_g.color)
		return null
		return undefined	// same color
	var	old_color = stv_g.color;
	stv_g.color = color;
	set_g()
	return old_color
}

/* -- set the staff scale (only) -- */
︙
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
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







-
+










-
+







// update the y offsets of delayed output
function delayed_update() {
	var st, new_out, text

	for (st = 0; st <= nstaff; st++) {
		if (staff_tb[st].sc_out) {
			output += '<g transform="translate(0,' +
					(posy - staff_tb[st].y).toFixed(2) +
					(posy - staff_tb[st].y).toFixed(1) +
					') scale(' +
					 staff_tb[st].staffscale.toFixed(2) +
					')">\n' +
				staff_tb[st].sc_out +
				'</g>\n';
			staff_tb[st].sc_out = ""
		}
		if (!staff_tb[st].output)
			continue
		output += '<g transform="translate(0,' +
				(-staff_tb[st].y).toFixed(2) +
				(-staff_tb[st].y).toFixed(1) +
				')">\n' +
			staff_tb[st].output +
			'</g>\n';
		staff_tb[st].output = ""
	}
}

︙
405
406
407
408
409
410
411
412

413
414
415
416
417
418
419
399
400
401
402
403
404
405

406
407
408
409
410
411
412
413







-
+







		return
	var	type = s.type,
		h = s.ymx - s.ymn + 4,
		wl = s.wl || 2,
		wr = s.wr || 2

	if (s.grace)
		type = GRACE
		type = C.GRACE

	f(t || anno_type[type], s.istart, s.iend,
		s.x - wl - 2, staff_tb[s.st].y + s.ymn + h - 2,
		wl + wr + 4, h, s);
}

function a_start(s, t) {
︙
433
434
435
436
437
438
439
440
441


442
443
444

445
446

447
448
449
450
451
452
453
427
428
429
430
431
432
433


434
435
436
437

438
439

440
441
442
443
444
445
446
447







-
-
+
+


-
+

-
+







//	A and B are replaced by a and b as string
//	F and G are replaced by a and b as float
function out_XYAB(str, x, y, a, b) {
	x = sx(x);
	y = sy(y);
	output += str.replace(/X|Y|A|B|F|G/g, function(c) {
		switch (c) {
		case 'X': return x.toFixed(2)
		case 'Y': return y.toFixed(2)
		case 'X': return x.toFixed(1)
		case 'Y': return y.toFixed(1)
		case 'A': return a
		case 'B': return b
		case 'F': return a.toFixed(2)
		case 'F': return a.toFixed(1)
//		case 'G':
		default: return b.toFixed(2)
		default: return b.toFixed(1)
		}
		})
}

// open / close containers
function g_open(x, y, rot, sx, sy) {
	out_XYAB('<g transform="translate(X,Y', x, y);
︙
476
477
478
479
480
481
482
483

484
485
486
487
488
489
490
470
471
472
473
474
475
476

477
478
479
480
481
482
483
484







-
+







	if (stv_g.g)
		return x
	return (x + posx) / stv_g.scale
}
Abc.prototype.sx = sx
function sy(y) {
	if (stv_g.g)
		return y
		return -y
	if (stv_g.scale == 1)
		return posy - y
	if (stv_g.st < 0)
		return (posy - y) / stv_g.scale	// voice scale
	return stv_g.dy - y			// staff scale
}
Abc.prototype.sy = sy;
︙
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
536
537
538
539
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







-
+

















-
+

-
+







		return h
	return h * stv_g.scale
}
// output scaled (x + <sep> + y)
function out_sxsy(x, sep, y) {
	x = sx(x);
	y = sy(y);
	output += x.toFixed(2) + sep + y.toFixed(2)
	output += x.toFixed(1) + sep + y.toFixed(1)
}
Abc.prototype.out_sxsy = out_sxsy

// define the start of a path
function xypath(x, y, fill) {
	out_XYAB('<path class="A" d="mX Y\n', x, y, fill ? "fill" : "stroke")
}
Abc.prototype.xypath = xypath

// output a glyph
function xygl(x, y, gl) {
// (avoid ps<->js loop)
//	if (psxygl(x, y, gl))
//		return
	var 	tgl = tgls[gl]
	if (tgl && !glyphs[gl]) {
		x += tgl.x * stv_g.scale;
		y += tgl.y
		y -= tgl.y
		if (tgl.sc)
			out_XYAB('<text transform="translate(X,Y) scale(F)">B</text>\n',
			out_XYAB('<text transform="translate(X,Y) scale(A)">B</text>\n',
				x, y, tgl.sc, tgl.c);
		else
			out_XYAB('<text x="X" y="Y">A</text>\n', x, y, tgl.c)
		return
	}
	if (!glyphs[gl]) {
		error(1, null, 'no definition of $1', gl)
︙
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
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







-
-
-
-
-
-
-
-


-
+










-
+










-
+

-
+







	} else {
		x -= 5;
		y -= 4
	}
	out_XYAB('<path class="stroke" d="mX YlF G"/>\n',
		x, y, dx, -dy)
}
// simple /dotted measure bar
function out_bar(x, y, h, dotted) {
	output += '<path class="stroke" stroke-width="1" ' +
		(dotted ? 'stroke-dasharray="5,5" ' : '') +
		'd="m' + (x + posx).toFixed(2) +
		' ' + (posy - y).toFixed(2) + 'v' + (-h).toFixed(2) +
		'"/>\n'
}
// tuplet value - the staves are not defined
function out_bnum(x, y, str) {
	out_XYAB('<text style="font-family:serif; font-style:italic; font-size:12px"\n\
	out_XYAB('<text style="font:italic 12px serif"\n\
	x="X" y="Y" text-anchor="middle">A</text>\n',
		x, y, str.toString())
}
// staff system brace
function out_brace(x, y, h) {
//fixme: '-6' depends on the scale
	x += posx - 6;
	y = posy - y;
	h /= 24;
	output += '<text transform="translate(' +
				x.toFixed(2) + ',' + y.toFixed(2) +
				x.toFixed(1) + ',' + y.toFixed(1) +
			') scale(2.5,' + h.toFixed(2) +
			')">' + tgls.brace.c + '</text>\n'
}

// staff system bracket
function out_bracket(x, y, h) {
	x += posx - 5;
	y = posy - y - 3;
	h += 2;
	output += '<path class="fill"\n\
	d="m' + x.toFixed(2) + ' ' + y.toFixed(2) + '\n\
	d="m' + x.toFixed(1) + ' ' + y.toFixed(1) + '\n\
	c10.5 1 12 -4.5 12 -3.5c0 1 -3.5 5.5 -8.5 5.5\n\
	v' + h.toFixed(2) + '\n\
	v' + h.toFixed(1) + '\n\
	c5 0 8.5 4.5 8.5 5.5c0 1 -1.5 -4.5 -12 -3.5"/>\n'
}
// hyphen
function out_hyph(x, y, w) {
	var	n, a_y,
		d = 25 + ((w / 20) | 0) * 3

︙
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

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

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







-
+




-
-




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

+












+
+



















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

+












+















-
-
-
-
-
-
-
-



















-
-
-
+
+
+






-
+







-
-
-
+
+
+

-
+


-
+













-
+




-
+











-
+




-
+







		slen = -h

	if (h < 0)
		dx = -dx;		// down
	x += dx * stv_g.scale
	if (stv_g.st < 0)
		slen /= stv_g.scale;
	out_XYAB('<path class="stroke" d="mX YvF"/>\n',	// stem
	out_XYAB('<path class="stroke sW" d="mX YvF"/>\n',	// stem
		x, y, slen)
	if (!nflags)
		return

	output += '<path class="fill"\n\
	d="';
	y += h
	if (h > 0) {				// up
		if (!straight) {
			if (!grace) {
				if (nflags == 1) {
				xygl(x, y, "flu" + nflags)
					out_XYAB('MX Yc0.6 5.6 9.6 9 5.6 18.4\n\
	1.6 -6 -1.3 -11.6 -5.6 -12.8\n', x, y)
				} else {
				return
					while (--nflags >= 0) {
						out_XYAB('MX Yc0.9 3.7 9.1 6.4 6 12.4\n\
	1 -5.4 -4.2 -8.4 -6 -8.4\n', x, y);
						y -= 5.4
					}
				}
			} else {		// grace
				output += '<path class="fill" d="'
				if (nflags == 1) {
					out_XYAB('MX Yc0.6 3.4 5.6 3.8 3 10\n\
	1.2 -4.4 -1.4 -7 -3 -7\n', x, y)
				} else {
					while (--nflags >= 0) {
						out_XYAB('MX Yc1 3.2 5.6 2.8 3.2 8\n\
	1.4 -4.8 -2.4 -5.4 -3.2 -5.2\n', x, y);
						y -= 3.5
					}
				}
			}
		} else {			// straight
			output += '<path class="fill" d="'
//fixme: to do
			if (!grace) {
//fixme: check endpoints
				y += 1
				while (--nflags >= 0) {
					out_XYAB('MX Yl7 3.2 0 3.2 -7 -3.2z\n',
						x, y);
					y -= 5.4
				}
			} else {		// grace
				while (--nflags >= 0) {
					out_XYAB('MX Yl3 1.5 0 2 -3 -1.5z\n',
						x, y);
					y -= 3
				}
			}
		}
	} else {				// down
		if (!straight) {
			if (!grace) {
				if (nflags == 1) {
				xygl(x, y, "fld" + nflags)
					out_XYAB('MX Yc0.6 -5.6 9.6 -9 5.6 -18.4\n\
	1.6 6 -1.3 11.6 -5.6 12.8\n', x, y)
				} else {
				return
					while (--nflags >= 0) {
						out_XYAB('MX Yc0.9 -3.7 9.1 -6.4 6 -12.4\n\
	1 5.4 -4.2 8.4 -6 8.4\n', x, y);
						y += 5.4
					}
				}
			} else {		// grace
				output += '<path class="fill" d="'
				if (nflags == 1) {
					out_XYAB('MX Yc0.6 -3.4 5.6 -3.8 3 -10\n\
	1.2 4.4 -1.4 7 -3 7\n', x, y)
				} else {
					while (--nflags >= 0) {
						out_XYAB('MX Yc1 -3.2 5.6 -2.8 3.2 -8\n\
	1.4 4.8 -2.4 5.4 -3.2 5.2\n', x, y);
						y += 3.5
					}
				}
			}
		} else {			// straight
			output += '<path class="fill" d="'
			if (!grace) {
//fixme: check endpoints
				y += 1
				while (--nflags >= 0) {
					out_XYAB('MX Yl7 -3.2 0 -3.2 -7 3.2z\n',
						x, y);
					y += 5.4
				}
//			} else {		// grace
//--fixme: error?
			}
		}
	}
	output += '"/>\n'
}
// thick measure bar
function out_thbar(x, y, h) {
	x += posx + 1.5;
	y = posy - y;
	output += '<path class="stroke" stroke-width="3" d="m' +
		x.toFixed(2) + ' ' + y.toFixed(2) +
		'v' + (-h).toFixed(2) + '"/>\n'
}
// tremolo
function out_trem(x, y, ntrem) {
	out_XYAB('<path class="fill" d="mX Y\n\t', x - 4.5, y)
	while (1) {
		output += 'l9 -3v3l-9 3z'
		if (--ntrem <= 0)
			break
		output += 'm0 5.4'
	}
	output += '"/>\n'
}
// tuplet bracket - the staves are not defined
function out_tubr(x, y, dx, dy, up) {
	var	h = up ? -3 : 3;

	y += h;
	dx /= stv_g.scale;
	output += '<path class="stroke" d="m';
	out_sxsy(x, ' ', y);
	output += 'v' + h.toFixed(2) +
		'l' + dx.toFixed(2) + ' ' + (-dy).toFixed(2) +
		'v' + (-h).toFixed(2) + '"/>\n'
	output += 'v' + h.toFixed(1) +
		'l' + dx.toFixed(1) + ' ' + (-dy).toFixed(1) +
		'v' + (-h).toFixed() + '"/>\n'
}
// tuplet bracket with number - the staves are not defined
function out_tubrn(x, y, dx, dy, up, str) {
    var	sw = str.length * 10,
	h = up ? -3 : 3;

	out_XYAB('<text style="font-family:serif; font-style:italic; font-size:12px"\n\
	out_XYAB('<text style="font:italic 12px serif"\n\
	x="X" y="Y" text-anchor="middle">A</text>\n',
		x + dx / 2, y + dy / 2, str);
	dx /= stv_g.scale
	if (!up)
		y += 6;
	output += '<path class="stroke" d="m';
	out_sxsy(x, ' ', y);
	output += 'v' + h.toFixed(2) +
		'm' + dx.toFixed(2) + ' ' + (-dy).toFixed(2) +
		'v' + (-h).toFixed(2) + '"/>\n' +
	output += 'v' + h.toFixed(1) +
		'm' + dx.toFixed(1) + ' ' + (-dy).toFixed(1) +
		'v' + (-h).toFixed(1) + '"/>\n' +
		'<path class="stroke" stroke-dasharray="' +
		((dx - sw) / 2).toFixed(2) + ' ' + sw.toFixed(2) +
		((dx - sw) / 2).toFixed(1) + ' ' + sw.toFixed(1) +
		'" d="m';
	out_sxsy(x, ' ', y - h);
	output += 'l' + dx.toFixed(2) + ' ' + (-dy).toFixed(2) + '"/>\n'
	output += 'l' + dx.toFixed(1) + ' ' + (-dy).toFixed(1) + '"/>\n'

}
// underscore line
function out_wln(x, y, w) {
	out_XYAB('<path class="stroke" stroke-width="0.8" d="mX YhF"/>\n',
		x, y + 3, w)
}

// decorations with string
var deco_str_style = {
crdc:	{
		dx: 0,
		dy: 5,
		style: 'font-family:serif; font-style:italic; font-size:14px'
		style: 'font:italic 14px serif'
	},
dacs:	{
		dx: 0,
		dy: 3,
		style: 'font-family:serif; font-size:16px',
		style: 'font:16px serif',
		anchor: ' text-anchor="middle"'
	},
fng:	{
		dx: 0,
		dy: 1,
		style: 'font-family:Bookman; font-size:8px',
		anchor: ' text-anchor="middle"'
	},
pf:	{
		dx: 0,
		dy: 5,
		style: 'font-family:serif; font-weight:bold; font-style:italic; font-size:16px'
		style: 'font:italic bold 16px serif'
	},
'@':	{
		dx: 0,
		dy: 5,
		style: 'font-family:sans-serif; font-size:12px'
		style: 'font: 12px sans-serif'
	}
}

function out_deco_str(x, y, name, str) {
	var	a, f,
		a_deco = deco_str_style[name]

︙
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
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
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
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
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
917
918
919
920
921
922
923
924
925
926

927
928
929
930
931
932
933
934







-


-
+










-
+

-
+






-
+

-
+








+
+
+
+
+
+
+




-
+








-
+







-
+








-
+







-
+








-
+







-
+








-
+









+

















-
+







	out_str(str);
	output += '</text>\n'
}

function out_arp(x, y, val) {
	g_open(x, y, 270);
	x = 0;
	y = -4;
	val = Math.ceil(val / 6)
	while (--val >= 0) {
		xygl(x, y, "ltr");
		xygl(x, 6, "ltr");
		x += 6
	}
	g_close()
}
function out_cresc(x, y, val, defl) {
	x += val;
	val = -val;
	out_XYAB('<path class="stroke"\n\
	d="mX YlA ', x, y + 5, val)
	if (defl.nost)
		output += '-2.2m0 -3.6l' + (-val).toFixed(2) + ' -2.2"/>\n'
		output += '-2.2m0 -3.6l' + (-val).toFixed(1) + ' -2.2"/>\n'
	else
		output += '-4l' + (-val).toFixed(2) + ' -4"/>\n'
		output += '-4l' + (-val).toFixed(1) + ' -4"/>\n'

}
function out_dim(x, y, val, defl) {
	out_XYAB('<path class="stroke"\n\
	d="mX YlA ', x, y + 5, val)
	if (defl.noen)
		output += '-2.2m0 -3.6l' + (-val).toFixed(2) + ' -2.2"/>\n'
		output += '-2.2m0 -3.6l' + (-val).toFixed(1) + ' -2.2"/>\n'
	else
		output += '-4l' + (-val).toFixed(2) + ' -4"/>\n'
		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
	}
}
function out_lped(x, y, val, defl) {
	y += 4;
	if (!defl.nost)
		xygl(x, y, "ped");
	if (!defl.noen)
		xygl(x + val, y, "pedoff")
}
function out_8va(x, y, val, defl) {
	if (!defl.nost) {
		out_XYAB('<text x="X" y="Y" \
style="font-family:serif; font-weight:bold; font-style:italic; font-size:12px">8\
style="font:italic bold 12px serif">8\
<tspan dy="-4" style="font-size:10px">va</tspan></text>\n',
			x - 8, y);
		x += 12;
		val -= 12
	} else {
		val -= 5
	}
	y += 6;
	out_XYAB('<path class="stroke" stroke-dasharray="6,6" d="mX YhA"/>\n',
	out_XYAB('<path class="stroke" stroke-dasharray="6,6" d="mX YhF"/>\n',
		x, y, val)
	if (!defl.noen)
		out_XYAB('<path class="stroke" d="mX Yv6"/>\n', x + val, y)
}
function out_8vb(x, y, val, defl) {
	if (!defl.nost) {
		out_XYAB('<text x="X" y="Y" \
style="font-family:serif; font-weight:bold; font-style:italic; font-size:12px">8\
style="font:italic bold 12px serif">8\
<tspan dy="-4" style="font-size:10px">vb</tspan></text>\n',
			x - 8, y);
		x += 4;
		val -= 4
	} else {
		val -= 5
	}
//	y -= 2;
	out_XYAB('<path class="stroke" stroke-dasharray="6,6" d="mX YhA"/>\n',
	out_XYAB('<path class="stroke" stroke-dasharray="6,6" d="mX YhF"/>\n',
		x, y, val)
	if (!defl.noen)
		out_XYAB('<path class="stroke" d="mX Yv-6"/>\n', x + val, y)
}
function out_15ma(x, y, val, defl) {
	if (!defl.nost) {
		out_XYAB('<text x="X" y="Y" \
style="font-family:serif; font-weight:bold; font-style:italic; font-size:12px">15\
style="font:italic bold 12px serif">15\
<tspan dy="-4" style="font-size:10px">ma</tspan></text>\n',
			x - 10, y);
		x += 20;
		val -= 20
	} else {
		val -= 5
	}
	y += 6;
	out_XYAB('<path class="stroke" stroke-dasharray="6,6" d="mX YhA"/>\n',
	out_XYAB('<path class="stroke" stroke-dasharray="6,6" d="mX YhF"/>\n',
		x, y, val)
	if (!defl.noen)
		out_XYAB('<path class="stroke" d="mX Yv6"/>\n', x + val, y)
}
function out_15mb(x, y, val, defl) {
	if (!defl.nost) {
		out_XYAB('<text x="X" y="Y" \
style="font-family:serif; font-weight:bold; font-style:italic; font-size:12px">15\
style="font:italic bold 12px serif">15\
<tspan dy="-4" style="font-size:10px">mb</tspan></text>\n',
			x - 10, y);
		x += 7;
		val -= 7
	} else {
		val -= 5
	}
//	y -= 2;
	out_XYAB('<path class="stroke" stroke-dasharray="6,6" d="mX YhA"/>\n',
	out_XYAB('<path class="stroke" stroke-dasharray="6,6" d="mX YhF"/>\n',
		x, y, val)
	if (!defl.noen)
		out_XYAB('<path class="stroke" d="mX Yv-6"/>\n', x + val, y)
}
var deco_val_tb = {
	arp:	out_arp,
	cresc:	out_cresc,
	dim:	out_dim,
	ltr:	out_ltr,
	lped:	out_lped,
	"8va":	out_8va,
	"8vb":	out_8vb,
	"15ma":	out_15ma,
	"15mb": out_15mb
}

function out_deco_val(x, y, name, val, defl) {
	if (deco_val_tb[name])
		deco_val_tb[name](x, y, val, defl)
	else
		error(1, null, "No function for decoration '$1'", name)
}

function out_glisq(x2, y2, de) {
	var	de1 = de.start,
		x1 = de1.x,
		y1 = de1.y + staff_tb[de1.st].y,
		ar = -Math.atan2(y2 - y1, x2 - x1),
		ar = Math.atan2(y1 - y2, x2 - x1),
		a = ar / Math.PI * 180,
		len = (x2 - x1) / Math.cos(ar);

	g_open(x1, y1, a);
	x1 = de1.s.dots ? 13 + de1.s.xmx : 8;
	len = (len - x1 - 6) / 6 | 0
	if (len < 1)
︙
976
977
978
979
980
981
982
983

984
985
986
987
988
989
990
948
949
950
951
952
953
954

955
956
957
958
959
960
961
962







-
+







		a = ar / Math.PI * 180,
		len = (x2 - x1) / Math.cos(ar);

	g_open(x1, y1, a);
	x1 = de1.s.dots ? 13 + de1.s.xmx : 8;
	len -= x1 + 8;
	xypath(x1, 0);
	output += 'l' + len.toFixed(2) + ' 0" stroke-width="1"/>\n';
	output += 'h' + len.toFixed(1) + '" stroke-width="1"/>\n';
	g_close()
}

var deco_l_tb = {
	glisq: out_glisq,
	gliss: out_gliss
}
︙
1029
1030
1031
1032
1033
1034
1035
1036

1037
1038
1039


1040
1041
1042

1043
1044
1045
1046
1047
1048
1049
1001
1002
1003
1004
1005
1006
1007

1008
1009


1010
1011
1012
1013

1014
1015
1016
1017
1018
1019
1020
1021







-
+

-
-
+
+


-
+







	}

	if (style || font_style || musicfont) {
		head += '<style type="text/css">' + style + font_style
		if (musicfont) {
			if (musicfont.indexOf('(') > 0) {
				head += '\n\
.music {font-family: music; font-size: 24px; fill: currentColor}\n\
.music {font:24px music;fill:currentColor}\n\
@font-face {\n\
  font-family: music;\n\
  src: ' + musicfont + '}';
  font-family:"music";\n\
  src:' + musicfont + '}';
			} else {
				head += '\n\
.music {font-family: '+ musicfont +'; font-size: 24px; fill: currentColor}'
.music {font:24px '+ musicfont +';fill:currentColor}'
			}
		}
		head += '\n</style>\n'
	}
	defs += fulldefs
	if (defs)
		head += '<defs>' + defs + '\n</defs>\n'
︙
1063
1064
1065
1066
1067
1068
1069

1070

1071
1072
1073
1074
1075
1076
1077
1035
1036
1037
1038
1039
1040
1041
1042

1043
1044
1045
1046
1047
1048
1049
1050







+
-
+








	user.img_out(head + output + g + "</svg>");
	output = ""

	font_style = ''
	if (cfmt.fullsvg) {
		defined_glyph = {}
		for (var i = 0; i < font_tb.length; i++)
		defined_font = {}
			font_tb[i].used = false
	} else {
		musicfont = '';
		style = '';
		fulldefs = ''
	}
	defs = '';
	posy = 0
︙
Changes to core/tail.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
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


-
+
















+




-




+

+
+
+
+
+
+
+
+
+
+
+

+







// abc2svg - tail.js
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-2019 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/>.

// PostScript hooks
function psdeco() { return false }
function psxygl() { return false }

// initialize
	font_init();
	init_tune()

// Abc functions used by the modules
Abc.prototype.add_style = function(s) { style += s };
Abc.prototype.calculate_beam = calculate_beam;
Abc.prototype.cfmt = function() { return cfmt };
Abc.prototype.clone = clone;
Abc.prototype.deco_cnv = deco_cnv;
Abc.prototype.do_pscom = do_pscom;
Abc.prototype.do_begin_end = do_begin_end;
Abc.prototype.draw_gchord = draw_gchord;
Abc.prototype.draw_note = draw_note;
Abc.prototype.draw_symbols = draw_symbols;
Abc.prototype.errs = errs;
Abc.prototype.font_class = font_class;
Abc.prototype.gch_build = gch_build;
Abc.prototype.gch_tr1 = gch_tr1;
Abc.prototype.get_a_gch = function() { return a_gch };
Abc.prototype.get_bool = get_bool;
Abc.prototype.get_cur_sy = function() { return cur_sy };
Abc.prototype.get_curvoice = function() { return curvoice };
Abc.prototype.get_delta_tb = function() { return delta_tb };
Abc.prototype.get_decos = function() { return decos };
Abc.prototype.get_fname = function() { return parse.fname };
Abc.prototype.get_font = get_font;
Abc.prototype.get_font_style = function() { return font_style };
︙
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
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







+

+

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

-
-
-
+
+
+
-
-

+


+
+
+
+
+









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

















-
+
-

-
+









		return true
	}
};
Abc.prototype.get_posy = function() { var t = posy; posy = 0; return t };
Abc.prototype.get_staff_tb = function() { return staff_tb };
Abc.prototype.get_top_v = function() { return par_sy.top_voice };
Abc.prototype.get_tsfirst = function() { return tsfirst };
Abc.prototype.get_unit = get_unit;
Abc.prototype.get_voice_tb = function() { return voice_tb };
Abc.prototype.goto_tune = goto_tune;
Abc.prototype.info = function() { return info };
Abc.prototype.new_block = new_block;
Abc.prototype.new_note = new_note;
Abc.prototype.out_arp = out_arp;
Abc.prototype.out_deco_str = out_deco_str;
Abc.prototype.out_deco_val = out_deco_val;
Abc.prototype.out_ltr = out_ltr;
Abc.prototype.output_music = output_music;
Abc.prototype.param_set_font = param_set_font;
Abc.prototype.parse = parse;
Abc.prototype.psdeco = psdeco;
Abc.prototype.psxygl = psxygl;
Abc.prototype.set_bar_num = set_bar_num;
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_format = set_format;
Abc.prototype.set_pitch = set_pitch;
Abc.prototype.set_scale = set_scale;
Abc.prototype.set_stem_dir = set_stem_dir;
Abc.prototype.set_stems = set_stems;
Abc.prototype.set_sym_glue = set_sym_glue;
Abc.prototype.set_tsfirst = function(s) { tsfirst = s };
Abc.prototype.set_xhtml = function(wt) {
    var wto = write_text;
	write_text = wt
Abc.prototype.set_vp = set_vp;
Abc.prototype.set_v_param = set_v_param;
Abc.prototype.set_width = set_width;
	return wto
};
Abc.prototype.sort_pitch = sort_pitch;
Abc.prototype.strwh = strwh;
Abc.prototype.stv_g = function() { return stv_g };
Abc.prototype.svg_flush = svg_flush;
Abc.prototype.syntax = syntax;
Abc.prototype.unlksym = unlksym;
Abc.prototype.use_font = use_font;
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) {
	    var	of, h
		for (var k = 0; k < hs.length; k++) {
			h = hs[k]
		for (var k = 0; k < hs.length; k++)
			hs[k](self)
			if (typeof h == "string") {
				if (!self[h])
					eval("self." + h + "=" + h)
			} else {
				eval("of=" + h[0] + ";" +
					h[0] + "=" + h[1] + ".bind(self,of)")
			}
		}
	} // 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()
    var	self = this

}	// end of Abc()
} // end of abc2svg

// compatibility
var Abc = abc2svg.Abc

// nodejs
if (typeof module == 'object' && typeof exports == 'object') {
	exports.abc2svg = abc2svg;
	exports.Abc = Abc
}
Changes to core/tune.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - tune.js - tune generation
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-2019 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.
︙
33
34
35
36
37
38
39
40

41
42
43
44
45
46
47
33
34
35
36
37
38
39

40
41
42
43
44
45
46
47







-
+







		if (!parse.voice_opts.hasOwnProperty(opt))
			continue
		sel = new RegExp(opt)
		if (sel.test(curvoice.id)
		 || sel.test(curvoice.nm)) {
			for (i in parse.voice_opts[opt])
			    if (parse.voice_opts[opt].hasOwnProperty(i))
				do_pscom(parse.voice_opts[opt][i])
				self.do_pscom(parse.voice_opts[opt][i])
		}
	}
}

/* -- link a ABC symbol into the current voice -- */
function sym_link(s) {
	if (!s.fname)
︙
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
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







-
-
+
+
-
-









-
+

-
+


-
+
-
-







function mrest_expand(s) {
	var	p_voice, s2, next,
		nb = s.nmes,
		dur = s.dur / nb

	/* change the multi-rest (type bar) to a single rest */
	var a_dd = s.a_dd;
	s.type = REST;
	s.dur = dur;
	s.type = C.REST;
	s.dur = s.dur_orig = dur;
	s.head = FULL;
	s.nflags = -2;

	/* add the bar(s) and rest(s) */
	next = s.next;
	p_voice = s.p_v;
	p_voice.last_sym = s;
	p_voice.time = s.time + dur;
	p_voice.cst = s.st;
	s2 = s
	while (--nb > 0) {
		s2 = sym_add(p_voice, BAR);
		s2 = sym_add(p_voice, C.BAR);
		s2.bar_type = "|";
		s2 = sym_add(p_voice, REST);
		s2 = sym_add(p_voice, C.REST);
		if (s.invis)
			s2.invis = true;
		s2.dur = dur;
		s2.dur = s2.dur_orig = dur;
		s2.head = FULL;
		s2.nflags = -2;
		p_voice.time += dur
	}
	s2.next = next
	if (next)
		next.prev = s2;

	/* copy the mrest decorations to the last rest */
︙
201
202
203
204
205
206
207
208

209
210
211
212
213
214
215
197
198
199
200
201
202
203

204
205
206
207
208
209
210
211







-
+







			w = w_tb[s.type]
			if (s.time < time) {
				time = s.time;
				wmin = w
			} else if (w < wmin) {
				wmin = w
			}
			if (s.type == MREST) {
			if (s.type == C.MREST) {
				if (s.nmes == 1)
					mrest_expand(s)
				else if (multi > 0)
					mrest_time = time
			}
		}

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







-
+
















-
+














-
+







				v = vn[ir]
				if (v == undefined)
					break
				s = vtb[v]
				if (!s || s.time != time
				 || w_tb[s.type] != wmin)
					continue
				if (s.type != MREST) {
				if (s.type != C.MREST) {
					mrest_time = -1 /* some note or rest */
					break
				}
				if (nb == 0) {
					nb = s.nmes
				} else if (nb != s.nmes) {
					mrest_time = -1	/* different duration */
					break
				}
			}
			if (mrest_time < 0) {
				for (ir = 0; ir < nv; ir++) {
					v = vn[ir]
					if (v == undefined)
						break
					s = vtb[v]
					if (s && s.type == MREST)
					if (s && s.type == C.MREST)
						mrest_expand(s)
				}
			}
		}

		/* link the vertical sequence */
		for (ir = 0; ir < nv; ir++) {
			v = vn[ir]
			if (v == undefined)
				break
			s = vtb[v]
			if (!s || s.time != time
			 || w_tb[s.type] != wmin)
				continue
			if (s.type == STAVES) {
			if (s.type == C.STAVES) {
				new_sy = s.sy;

				// set all voices of previous and next staff systems
				// as reachable
				for (ir2 = 0; ir2 < nv; ir2++) {
					if (vn[ir2] == undefined)
						break
︙
343
344
345
346
347
348
349
350

351
352
353
354
355
356
357
339
340
341
342
343
344
345

346
347
348
349
350
351
352
353







-
+







	} // end set_feathered_beam()

	/* if Q: from tune header, put it at start of the music */
	s = glovar.tempo
	if (s && staves_found <= 0) {	// && !s.del) {		- play problem
		v = par_sy.top_voice;
		p_voice = voice_tb[v];
		if (p_voice.sym && p_voice.sym.type != TEMPO) {
		if (p_voice.sym && p_voice.sym.type != C.TEMPO) {
			s = clone(s);
			s.v = v;
			s.p_v = p_voice;
			s.st = p_voice.st;
			s.time = 0;
			s.next = p_voice.sym
			if (s.next)
︙
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
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







-
-
+
+


-
+






-
+

-
+







			p_voice.ignore = false
		for (s = p_voice.sym; s; s = s.next) {
			if (s.time >= staves_found)
				break
		}
		for ( ; s; s = s.next) {
			switch (s.type) {
			case GRACE:
				// with w_tb[BAR] = 2,
			case C.GRACE:
				// with w_tb[C.BAR] = 2,
				// the grace notes go after the bar;
				// if before a bar, change the grace time
				if (s.next && s.next.type == BAR)
				if (s.next && s.next.type == C.BAR)
					s.time--

				if (!cfmt.graceword)
					continue
				for (s2 = s.next; s2; s2 = s2.next) {
					switch (s2.type) {
					case SPACE:
					case C.SPACE:
						continue
					case NOTE:
					case C.NOTE:
						if (!s2.a_ly)
							break
						s.a_ly = s2.a_ly;
						s2.a_ly = null
						break
					}
					break
︙
416
417
418
419
420
421
422
423

424
425
426
427
428
429
430
412
413
414
415
416
417
418

419
420
421
422
423
424
425
426







-
+







//fixme: there may be other symbols before the %%staves at this same time
			if (s.time >= staves_found)
				break
		}
		p_voice2.clef = clone(p_voice.clef);
		curvoice = p_voice2
		for ( ; s; s = s.next) {
			if (s.type == STAVES)
			if (s.type == C.STAVES)
				continue
			s2 = clone(s)
			if (s.notes) {
				s2.notes = []
				for (i = 0; i <= s.nhd; i++)
					s2.notes.push(clone(s.notes[i]))
			}
︙
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
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







+



-
+
-




+













+











-
+

-
-
-
+
+
+

-
+







	if (init) {				/* first staff system */
		cur_sy = par_sy = sy_new
		return
	}

	// update the previous system
	for (v = 0; v < voice_tb.length; v++) {
	    if (par_sy.voices[v].range >= 0) {
		st = par_sy.voices[v].st
		var	sy_staff = par_sy.staves[st],
			p_voice = voice_tb[v]
		if (p_voice.stafflines != undefined)

			sy_staff.stafflines = p_voice.stafflines
		if (p_voice.staffnonote != undefined)
			sy_staff.staffnonote = p_voice.staffnonote
		if (p_voice.staffscale)
			sy_staff.staffscale = p_voice.staffscale;
	    }
		sy_new.voices[v] = clone(par_sy.voices[v]);
		sy_new.voices[v].range = -1;
		delete sy_new.voices[v].second
	}
	for (st = 0; st < par_sy.staves.length; st++) {
		sy_new.staves[st] = clone(par_sy.staves[st]);
		sy_new.staves[st].flags = 0
	}
	par_sy.next = sy_new;
	par_sy = sy_new
}

/* -- set the bar numbers -- */
// (possible hook)
function set_bar_num() {
	var	s, s2, tim, bar_time, bar_num, rep_dtime,
		v = cur_sy.top_voice,
		wmeasure = voice_tb[v].meter.wmeasure,
		bar_rep = gene.nbar

	/* don't count a bar at start of line */
	for (s = tsfirst; ; s = s.ts_next) {
		if (!s)
			return
		switch (s.type) {
		case METER:
		case C.METER:
			wmeasure = s.wmeasure
		case CLEF:
		case KEY:
		case STBRK:
		case C.CLEF:
		case C.KEY:
		case C.STBRK:
			continue
		case BAR:
		case C.BAR:
			if (s.bar_num) {
				gene.nbar = s.bar_num	/* (%%setbarnb) */
				break
			}
			if (s.text			// if repeat bar
			 && !cfmt.contbarnb) {
				if (s.text[0] == '1') {
︙
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
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







-
+














-
+




-
+


-
+


-
-
-
+
+
+
-
-
-














-
+




-
+
















+
+
+
+
+














-
+







		break
	}

	// at start of tune, check for an anacrusis
	bar_time = s.time + wmeasure
	if (s.time == 0) {
		for (s2 = s.ts_next; s2; s2 = s2.ts_next) {
			if (s2.type == BAR && s2.time) {
			if (s2.type == C.BAR && s2.time) {
				if (s2.time < bar_time) {	// if anacrusis
					s = s2;
					bar_time = s.time + wmeasure
				}
				break
			}
		}
	}

	// set the measure number on the top bars
	bar_num = gene.nbar

	for ( ; s; s = s.ts_next) {
		switch (s.type) {
		case METER:
		case C.METER:
			wmeasure = s.wmeasure
			if (s.time < bar_time)
				bar_time = s.time + wmeasure
			break
		case MREST:
		case C.MREST:
			bar_num += s.nmes - 1
			while (s.ts_next
			    && s.ts_next.type != BAR)
			    && s.ts_next.type != C.BAR)
				s = s.ts_next
			break
		case BAR:
			if (s.bar_num) {
				bar_num = s.bar_num		/* (%%setbarnb) */
		case C.BAR:
			if (s.bar_num)
				bar_num = s.bar_num	// (%%setbarnb)
				if (s.time < bar_time)
					delete s.bar_num
			}
			if (s.time < bar_time) {	// incomplete measure
				if (s.text && s.text[0] == '1') {
					bar_rep = bar_num;
					rep_dtime = bar_time - s.time
				}
				break
			}

			/* check if any repeat bar at this time */
			tim = s.time;
			s2 = s
			do {
				if (s2.dur)
					break
				if (s2.type == BAR && s2.text)	// if repeat bar
				if (s2.type == C.BAR && s2.text)	// if repeat bar
					break
				s2 = s2.next
			} while (s2 && s2.time == tim);
			bar_num++
			if (s2 && s2.type == BAR && s2.text) {
			if (s2 && s2.type == C.BAR && s2.text) {
				if (s2.text[0] == '1') {
					rep_dtime = 0;
					bar_rep = bar_num
				} else {			// restart bar numbering
					if (!cfmt.contbarnb)
						bar_num = bar_rep
					if (rep_dtime) {	// [1 inside measure
						if (cfmt.contbarnb)
							bar_num--;
						bar_time = tim + rep_dtime
						break
					}
				}
			}
			s.bar_num = bar_num;
			bar_time = tim + wmeasure

			// skip the bars of the other voices
			while (s.ts_next
			    && !s.ts_next.seqst)
				s = s.ts_next
			break
		}
	}
	if (cfmt.measurenb < 0)		/* if no display of measure bar */
		gene.nbar = bar_num	/* update in case of more music to come */
}

// note mapping
// %%map map_name note [print [note_head]] [param]*
function get_map(text) {
	if (!text)
		return

	var	i, note, notes, map, tmp, ns,
		a = info_split(text, 2)
		a = info_split(text)

	if (a.length < 3) {
		syntax(1, "Not enough parameters in %%map")
		return
	}
	ns = a[1]
	if (ns.indexOf("octave,") == 0
︙
644
645
646
647
648
649
650
651
652

653
654
655
656
657
658
659
660
661
662
663
664
644
645
646
647
648
649
650


651





652
653
654
655
656
657
658







-
-
+
-
-
-
-
-







		tmp = new scanBuf();
		tmp.buffer = a[1];
		note = parse_acc_pit(tmp)
		if (!note) {
			syntax(1, "Bad note in %%map")
			return
		}
		ns = 'abcdefg'[(note.pit + 77) % 7]
		if (note.acc)
		ns = note2abc(note)
			ns = ['__', '_', '', '^', '^^', '='][note.acc + 2] + ns
		for (i = note.pit; i >= 28; i -= 7)
			ns += "'"
		for (i = note.pit; i < 21; i += 7)
			ns += ","
	}

	notes = maps[a[0]]
	if (!notes)
		maps[a[0]] = notes = {}
	map = notes[ns]
	if (!map)
︙
685
686
687
688
689
690
691


692
693
694
695
696
697
698
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694







+
+








	for (; i < a.length; i++) {
		switch (a[i]) {
		case "heads=":
			map[0] = a[++i].split(',')
			break
		case "print=":
			if (cfmt.sound == "play")
				break
			tmp = new scanBuf();
			tmp.buffer = a[++i];
			map[1] = parse_acc_pit(tmp)
			break
//		case "transpose=":
//			switch (a[++i][0]) {
//			case "n":
︙
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
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
760
761
762







-
+













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

+







		if (curvoice.key.k_none)
			curvoice.key.k_sf = 0
		return
	}

	// set the transposition in the previous K:
	while (1) {
		if (s.type == KEY)
		if (s.type == C.KEY)
			break
		if (!s.prev) {
			s = curvoice.key
			break
		}
		s = s.prev
	}
	key_transp(s);
	curvoice.ckey = clone(s)
	if (curvoice.key.k_none)
		s.k_sf = 0
}

function set_ottava(dcn) {
	if (cfmt.sound)
		return
	switch (dcn) {
	case "15ma(":
		curvoice.ottava = -14
		break
	case "8va(":
		curvoice.ottava = -7
		break
	case "8vb(":
		curvoice.ottava = 7
		break
	case "15mb(":
		curvoice.ottava = 14
		break
	case "15ma)":
	case "8va)":
	case "8vb)":
	case "15mb)":
		curvoice.ottava = 0
		break
	}
}

/* -- process a pseudo-comment (%% or I:) -- */
// (possible hook)
function do_pscom(text) {
	var	h1, val, s, cmd, param, n, k, b,
		lock = false

	if (text.slice(-5) == ' lock') {
		lock = true;
		text = text.slice(0, -5).trim()
︙
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
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







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




















-



-
+













-
+







			goto_tune()
		}
		n = parseInt(param)
		if (isNaN(n) || n < -2 || n > 2) {
			syntax(1, errs.bad_val, "%%ottava")
			return
		}
		switch (curvoice.ottava) {
		case 14: b = "15mb)"; break
		case 7: b = "8vb)"; break
		case -7: b = "8va)"; break
		case -14: b = "15ma)"; break
		}
		if (b) {
			if (!a_dcn)
				a_dcn = []
			a_dcn.push(b);
			set_ottava(b)
		parse.ottava = n
		}
		switch (n) {
		case -2: b = "15mb("; break
		case -1: b = "8vb("; break
		case 0: return
		case 1: b = "8va("; break
		case 2: b = "15ma("; break
		}
		if (!a_dcn)
			a_dcn = []
		a_dcn.push(b);
		set_ottava(b)
		return
	case "repbra":
		if (parse.state >= 2) {
			if (parse.state == 2)
				goto_tune();
			curvoice.norepbra = !get_bool(param)
		}
		return
	case "repeat":
		if (parse.state != 3)
			return
		if (!curvoice.last_sym) {
			syntax(1, "%%repeat cannot start a tune")
			return
		}
		if (!param.length) {
			n = 1;
			k = 1
		} else {
			b = param.split(/\s+/);

			n = parseInt(b[0]);
			k = parseInt(b[1])
			if (isNaN(n) || n < 1
			 || (curvoice.last_sym.type == BAR
			 || (curvoice.last_sym.type == C.BAR
			  && n > 2)) {
				syntax(1, "Incorrect 1st value in %%repeat")
				return
			}
			if (isNaN(k)) {
				k = 1
			} else {
				if (k < 1) {
					syntax(1, "Incorrect 2nd value in %%repeat")
					return
				}
			}
		}
		parse.repeat_n = curvoice.last_sym.type == BAR ? n : -n;
		parse.repeat_n = curvoice.last_sym.type == C.BAR ? n : -n;
		parse.repeat_k = k
		return
	case "sep":
		var	h2, len, values, lwidth;

		set_page();
		lwidth = img.width - img.lm - img.rm;
︙
980
981
982
983
984
985
986
987

988
989
990
991
992
993

994
995
996
997
998
999
1000
929
930
931
932
933
934
935

936
937
938
939
940
941

942
943
944
945
946
947
948
949







-
+





-
+







			s.sk2 = h2
			return
		}
		blk_out();
		vskip(h1);
		output += '<path class="stroke"\n\td="M';
		out_sxsy((lwidth - len) / 2 / cfmt.scale, ' ', 0);
		output += 'h' + (len / cfmt.scale).toFixed(2) + '"/>\n';
		output += 'h' + (len / cfmt.scale).toFixed(1) + '"/>\n';
		vskip(h2);
		blk_flush()
		return
	case "setbarnb":
		val = parseInt(param)
		if (isNaN(val))
		if (isNaN(val) || val < 1)
			syntax(1, "Bad %%setbarnb value")
		else if (parse.state >= 2)
			glovar.new_nbar = val
		else
			cfmt.measurefirst = val
		return
	case "staff":
︙
1024
1025
1026
1027
1028
1029
1030
1031

1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048

1049
1050
1051
1052
1053
1054
1055
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







-
+
















-
+







	case "staffbreak":
		if (parse.state != 3) {
			if (parse.state != 2)
				return
			goto_tune()
		}
		s = {
			type: STBRK,
			type: C.STBRK,
			dur:0
		}
		if (param[0] >= '0' && param[0] <= '9') {
			s.xmx = get_unit(param)
			if (param.slice(-1) == 'f')
				s.stbrk_forced = true
		} else {
			s.xmx = 14
			if (param[0] == 'f')
				s.stbrk_forced = true
		}
		sym_link(s)
		return
	case "stafflines":
	case "staffscale":
	case "staffnonote":
		set_v_param(cmd, param)
		self.set_v_param(cmd, param)
		return
	case "staves":
	case "score":
		if (parse.state == 0)
			return
		get_staves(cmd, param)
		return
︙
1082
1083
1084
1085
1086
1087
1088
1089

1090
1091
1092
1093
1094

1095
1096
1097
1098
1099
1100
1101
1031
1032
1033
1034
1035
1036
1037

1038
1039
1040
1041
1042

1043
1044
1045
1046
1047
1048
1049
1050







-
+




-
+







			return
//		case 2:
//			goto_tune()
//			break
		}
		for (s = curvoice.last_sym; s; s = s.prev) {
			switch (s.type) {
			case NOTE:		// insert a key
			case C.NOTE:		// insert a key
				s = clone(curvoice.okey);
				s.k_old_sf = curvoice.ckey.k_sf;
				sym_link(s)
				break
			case KEY:
			case C.KEY:
				break
			default:
				continue
			}
			break
		}
		do_info('V', curvoice.id + ' shift=' + param)
︙
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
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







-
+



+















+
-
+







		if (cmd == "newpage") {
			blk_flush();
			block.newpage = true;
			return
		}
		break
	}
	set_format(cmd, param, lock)
	self.set_format(cmd, param, lock)
}

// treat the %%beginxxx / %%endxxx sequences
// (posible hook)
function do_begin_end(type,
			opt,
			text) {
	var i, j, action, s

	switch (type) {
	case "js":
		js_inject(text)
		break
	case "ml":
		if (parse.state >= 2) {
			s = new_block(type);
			s.text = text
		} else {
			svg_flush();
			if (user.img_out)
			user.img_out(text)
				user.img_out(text)
		}
		break
	case "svg":
		j = 0
		while (1) {
			i = text.indexOf('<style type="text/css">\n', j)
			if (i < 0)
︙
1222
1223
1224
1225
1226
1227
1228
1229

1230
1231
1232
1233
1234
1235
1236
1237
1238

1239
1240
1241
1242
1243
1244
1245
1173
1174
1175
1176
1177
1178
1179

1180
1181
1182
1183
1184
1185
1186
1187
1188

1189
1190
1191
1192
1193
1194
1195
1196







-
+








-
+







	if (voice_tb.length == 0)
		return
	voice_adj();
	dupl_voice();
	sort_all()			/* define the time / vertical sequences */
	if (!tsfirst)
		return
	set_bar_num()
	self.set_bar_num()
	if (!tsfirst)
		return				/* no more symbol */

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

	if (user.img_out)		// if SVG generation
		output_music()
		self.output_music()

	/* reset the parser */
	for (v = 0; v < voice_tb.length; v++) {
		p_voice = voice_tb[v];
		p_voice.time = 0;
		p_voice.sym = p_voice.last_sym = null;
		p_voice.st = cur_sy.voices[v].st;
︙
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
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







-
+






-
+













-
+







	if (!s)
		return //undefined;

	time = s.time

	for (; s; s = s.prev) {
		switch (s.type) {
		case BAR:
		case C.BAR:
			if (s.time < time)
				return //undefined // no same pitch
			while (1) {
				s = s.prev
				if (!s)
					return //undefined
				if (s.type == NOTE) {
				if (s.type == C.NOTE) {
					if (s.time + s.dur == time)
						break
					return //undefined
				}
				if (s.time < time)
					return //undefined
			}
			for (i = 0; i <= s.nhd; i++) {
				if (s.notes[i].pit == pitch
				 && s.notes[i].ti1)
					return s.notes[i].acc
			}
			return //undefined
		case NOTE:
		case C.NOTE:
			for (i = 0; i <= s.nhd; i++) {
				if (s.notes[i].pit == pitch)
					return s.notes[i].acc
			}
			break
		}
	}
︙
1421
1422
1423
1424
1425
1426
1427
1428

1429
1430
1431
1432
1433
1434
1435
1372
1373
1374
1375
1376
1377
1378

1379
1380
1381
1382
1383
1384
1385
1386







-
+







			if (par_sy.voices[v].range >= 0) {
				curvoice = voice_tb[v]
				break
			}
		}
		curvoice.time = maxtime;
		s = {
			type: STAVES,
			type: C.STAVES,
			dur: 0
		}

		sym_link(s);		// link the staves in this voice
		par_sy.nstaff = nstaff;
		new_syst();
		s.sy = par_sy
︙
1601
1602
1603
1604
1605
1606
1607

1608
1609
1610
1611
1612
1613
1614
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566







+







		delete p_voice.snm
		delete p_voice.new_name
		delete p_voice.lyric_restart
		delete p_voice.lyric_cont
		delete p_voice.ly_a_h;
		delete p_voice.sym_restart
		delete p_voice.sym_cont
		delete p_voice.have_ly

		voice_tb.push(p_voice)
		return p_voice
	} // clone_voice()

	/* treat the end of overlay */
	if (curvoice.ignore)
︙
1691
1692
1693
1694
1695
1696
1697
1698

1699
1700
1701
1702
1703
1704
1705
1643
1644
1645
1646
1647
1648
1649

1650
1651
1652
1653
1654
1655
1656
1657







-
+







	if (!vover) {				/* first '&' in a measure */
		vover = {
			bar: true,
			p_voice: curvoice
		}
		time = p_voice2.time
		for (s = curvoice.last_sym; /*s*/; s = s.prev) {
			if (s.type == BAR
			if (s.type == C.BAR
			 || s.time <= time)	/* (if start of tune) */
				break
		}
		vover.time = s.time
	} else {
		if (curvoice != vover.p_voice
		 && curvoice.time != vover.p_voice.time) {
︙
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
1684
1685
1686
1687
1688
1689
1690





















1691






1692
1693
1694
1695
1696
1697
1698







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








	if (is_voice_sig()) {
		curvoice.clef = s
		return
	}

	// clef change
	/* the clef must appear before a key signature or a bar */
	for (s2 = curvoice.last_sym;
	     s2 && s2.prev && s2.time == curvoice.time;
	     s2 = s2.prev) {
		if (w_tb[s2.type] != 0)
			break
	}
	if (s2 && s2.prev
	 && s2.time == curvoice.time		// if no time skip
	 && ((s2.type == KEY && !s2.k_none) || s2.type == BAR)) {
		for (s3 = s2; s3.prev; s3 = s3.prev) {
			switch (s3.prev.type) {
			case KEY:
			case BAR:
				continue
			}
			break
		}
		s2 = curvoice.last_sym;
		curvoice.last_sym = s3.prev;
		sym_link(s);
	sym_link(s);
		s.next = s3;
		s3.prev = s;
		curvoice.last_sym = s2
	} else {
		sym_link(s)
	}
	s.clef_small = true
}

// treat K: (kp = key signature + parameters)
function get_key(parm) {
	var	v, p_voice, s, transp,
//		[s_key, a] = new_key(parm)	// KO with nodejs
︙
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
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







-




-
+














+
-
+







		}
		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.okey = clone(s_key);
		parse.ckey = s_key
		if (a.length != 0)
			memo_kv_parm('*', a)
		if (!glovar.ulen)
			glovar.ulen = BASE_LEN / 8;
			glovar.ulen = C.BLEN / 8;
		parse.state = 2;		// in tune header after K:

		set_page();
		write_heading();
		reset_gen();
		gene.nbar = cfmt.measurefirst	// measure numbering
		return
	case 2:					// K: at start of tune body
		goto_tune(true)
		break
	}
	if (a.length != 0)
		set_kv_parm(a);

	if (!curvoice.ckey.k_bagpipe && !curvoice.ckey.k_drum)
	transp = (cfmt.transp || 0) +
	    transp = (cfmt.transp || 0) +
		(curvoice.transp || 0) +
		(curvoice.shift || 0)

	if (s_key.k_sf == undefined) {
		if (!s_key.k_a_acc
		 && !transp)
			return
︙
1837
1838
1839
1840
1841
1842
1843
1844

1845
1846
1847
1848
1849
1850
1851
1763
1764
1765
1766
1767
1768
1769

1770
1771
1772
1773
1774
1775
1776
1777







-
+







		if (s_key.k_none)
			curvoice.key.k_sf = 0
		return
	}

	/* the key signature must appear before a time signature */
	s = curvoice.last_sym
	if (s && s.type == METER) {
	if (s && s.type == C.METER) {
		curvoice.last_sym = s.prev
		if (!curvoice.last_sym)
			curvoice.sym = null;
		sym_link(s_key);
		s_key.next = s;
		s.prev = s_key;
		curvoice.last_sym = s
︙
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906



1907
1908
1909
1910

1911
1912
1913
1914
1915
1916
1917
1823
1824
1825
1826
1827
1828
1829



1830
1831
1832
1833
1834
1835

1836
1837
1838
1839
1840
1841
1842
1843







-
-
-
+
+
+



-
+







			vol: 0
		},
		scale: 1,
//		st: 0,
//		cst: 0,
		ulen: glovar.ulen,
		dur_fact: 1,
		key: clone(parse.ckey),
		ckey: clone(parse.ckey),
		okey: clone(parse.okey),
		key: clone(parse.ckey),	// key at start of tune (parse) / line (gene)
		ckey: clone(parse.ckey),	// current key (parse)
		okey: clone(parse.ckey),	// key without transposition (parse)
		meter: clone(glovar.meter),
		wmeasure: glovar.meter.wmeasure,
		clef: {
			type: CLEF,
			type: C.CLEF,
			clef_auto: true,
			clef_type: "a",		// auto
			time: 0
		},
		hy_st: 0
	}

︙
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1855
1856
1857
1858
1859
1860
1861

1862
1863
1864
1865
1866
1867
1868







-







	nstaff = -1;
	voice_tb = [];
	curvoice = null;
	new_syst(true);
	staves_found = -1;
	gene = {}
	a_de = []			// remove old decorations
	od = {}				// no ottava decorations anymore
}

// treat V: with many voices
function do_cloning(vs) {
    var	i, eol,
	file = parse.file,
	start = parse.eol + 1,		// next line after V:
︙
1966
1967
1968
1969
1970
1971
1972
1973

1974
1975
1976
1977
1978
1979
1980
1891
1892
1893
1894
1895
1896
1897

1898
1899
1900
1901
1902
1903
1904
1905







-
+







	}
	include--
}

// treat a 'V:' info
function get_voice(parm) {
	var	v, transp, vtransp, vs,
		a = info_split(parm, 1),
		a = info_split(parm),
		vid = a.shift();

	if (!vid)
		return				// empty V:

	if (vid.indexOf(',') > 0) {		// if many voices
		vs = vid.split(',');
︙
2004
2005
2006
2007
2008
2009
2010
2011

2012
2013
2014
2015
2016
2017
2018
1929
1930
1931
1932
1933
1934
1935

1936
1937
1938
1939
1940
1941
1942
1943







-
+







		delete curvoice.new
		if (staves_found < 0) {		// if no %%score/%%staves
			curvoice.st = curvoice.cst = ++nstaff;
			par_sy.nstaff = nstaff;
			par_sy.voices[v].st = nstaff;
			par_sy.voices[v].range = v;
			par_sy.staves[nstaff] = {
				stafflines: "|||||",
				stafflines: curvoice.stafflines || "|||||",
				staffscale: 1
			}
		}
	
		if (par_sy.voices[v].range < 0) {
//			if (cfmt.alignbars)
//				syntax(1, "V: does not work with %%alignbars")
︙
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
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







-
+








-
+

















-
+


-
+













-
+










-
-


}

// change state from 'tune header after K:' to 'in tune body'
// curvoice is defined when called from get_voice()
function goto_tune(is_K) {
	var	v, p_voice,
		s = {
			type: STAVES,
			type: C.STAVES,
			dur: 0,
			sy: par_sy
		}

	parse.state = 3;			// in tune body

	// if no voice yet, create the default voice
	if (voice_tb.length == 0) {
		curvoice = new_voice("1");
		get_voice("1");
		curvoice.clef.istart = curvoice.key.istart;
		curvoice.clef.iend = curvoice.key.iend;
//		nstaff = 0;
		curvoice.default = true
	} else if (!curvoice) {
		curvoice = voice_tb[staves_found < 0 ? 0 : par_sy.top_voice]
	}

	if (!curvoice.init && !is_K) {
		set_kv_parm([]);
		set_transp()
	}

	// 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.key.k_bagpipe
		if (p_voice.ckey.k_bagpipe
		 && !p_voice.pos.stm) {
			p_voice.pos = clone(p_voice.pos);
			p_voice.pos.stm = SL_BELOW
			p_voice.pos.stm = C.SL_BELOW
		}
	}

	// initialize the voices when no %%staves/score	
	if (staves_found < 0) {
		nstaff = voice_tb.length - 1
		for (v = 0; v <= nstaff; v++) {
			p_voice = voice_tb[v];
			delete p_voice.new;		// old voice
			p_voice.st = p_voice.cst =
				par_sy.voices[v].st =
					par_sy.voices[v].range = v;
			par_sy.staves[v] = {
				stafflines: '|||||',
				stafflines: p_voice.stafflines || "|||||",
				staffscale: 1
			}
		}
		par_sy.nstaff = nstaff
	}

	// link the first %%score in the top voice
	p_voice = curvoice;
	curvoice = voice_tb[par_sy.top_voice];
	sym_link(s)
	if (staves_found < 0)
		s.default = true;
	curvoice = p_voice
}
Changes to edit-de.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
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












+
+
+
+
+





-





-








+







//JS - abc2svg edit - Text in Deutsch
function loadtxt() {
	texts = {
		bad_nb: 'fehlerhafte Zeilennummer',
		fn: 'Filename: ',
		load: 'Bitte öffne die eingebundene Datei ',
		play: 'Wiedergabe',
		stop: 'Stop',
	}
	var text_kv = {
		a: 'Über ...',
		b: 'ABC-Files:',
		cmpa: 'Alles',
		cmpt: 'Stück',
		cmps: 'Auswahl',
		cmpl: 'Schleife',
		cmpc: 'Weiter',
//		df: 'abc2svg features',
//		dp: 'abc2svg parameters',
		er: 'Fehler',
		f: 'File',
		fl: 'Lade File',
		fo: 'Follow music',
		fs: 'Schriftgröße',
		gv: 'Lautstärke',
		h: 'Hilfe',
		ha: 'Hilfe',
		lg: 'Sprache',
    		playbutton: 'Wiedergabe',
		pr: 'Einstellungen',
		saveas: 'Speichere File',
		sful: 'Sound font URL',
		sp: 'Speed'
	}

	for (var k in text_kv)
		document.getElementById(k).innerHTML = text_kv[k];
  document.getElementById('ctxMenu').title = 'Wiedergabe';

	document.getElementById("hlp").outerHTML = '<ul id="hlp">\n\
<li>Du kannst entweder:\n\
    <ul>\n\
	<li>im Textfeld direkt ABC-Code direkt eintragen, oder</li>\n\
	<li>ABC-Code im Textfeld aus der Zwischenablage einfügen, oder</li>\n\
	<li>ein lokales ABC-File laden (\'ABC | Lade File\' Taste), oder</li>\n\
︙
Changes to edit-en.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
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






-
-




+
+
+
+
+





-





-








+













+
+
+
+
+
+


//JS - abc2svg edit - text in English
function loadtxt() {
	texts = {
		bad_nb: 'Bad line number',
		fn: 'File name: ',
		load: 'Please, load the included file ',
		play: 'Play',
		stop: 'Stop',
	}
	var text_kv = {
		a: 'About',
		b: 'ABC files:',
		cmpa: 'All',
		cmpt: 'Tune',
		cmps: 'Selection',
		cmpl: 'Loop',
		cmpc: 'Continue',
//		df: 'abc2svg features',
//		dp: 'abc2svg parameters',
		er: 'Errors',
		f: 'File',
		fl: 'Load file',
		fo: 'Follow music',
		fs: 'Font size',
		gv: 'Volume',
		h: 'Help',
		ha: 'Help',
		lg: 'Language',
		playbutton: 'Play',
		pr: 'Preferences',
		saveas: 'Save file',
		sful: 'Soundfont URL',
		sp: 'Speed'
	}

	for (var k in text_kv)
		document.getElementById(k).innerHTML = text_kv[k];
	document.getElementById('ctxMenu').title = 'Play';

	document.getElementById("hlp").outerHTML = '<ul id="hlp">\n\
<li>You may either:\n\
    <ul>\n\
	<li>directly write ABC code in the text area, or</li>\n\
	<li>paste ABC code in the text area, or</li>\n\
	<li>load a local ABC file (\'ABC | Load file\' button), or</li>\n\
	<li>drag &amp; drop a local file from your file manager\n\
		or a selected text to the text area.</li>\n\
    </ul></li>\n\
	<li>You may change at will the ABC code in the text area.<br/>\n\
	Rendering is done 2 seconds later.</li>\n\
	<li>The \'Print\' button of the browser outputs the rendering area.</li>\n\
<li>You may select a part of the tunes either from the source text area\
	(click and move), or from the rendered area.<br/>\n\
	In the latter case, a left click on a music element defines the\
	start of the selection. A right click defines its end.<br/>\
	Also, if your browser can play the music, a right click\
	outside the music displays the play menu.</li>\
</ul>'
}
Changes to edit-fr.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
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






-
-




+
+
+
+
+





-





-








+













+
+
+
+
+
+


//JS - abc2svg edit - textes en français
function loadtxt() {
	texts = {
		bad_nb: 'Mauvais numéro de ligne',
		fn: 'Nom de fichier: ',
		load: 'SVP, ouvrez le fichier à inclure ',
		play: 'Jouer',
		stop: 'Arrêter',
	}
	var text_kv = {
		a: 'A propos',
		b: 'Fichiers ABC:',
		cmpa: 'Tout',
		cmpt: 'Morceau',
		cmps: 'Selection',
		cmpl: 'Boucle',
		cmpc: 'Continuer',
//		df: 'abc2svg features',
//		dp: 'abc2svg parameters',
		er: 'Erreurs',
		f: 'Fichier',
		fl: 'Ouvrir un fichier',
		fo: 'Suivre la musique',
		fs: 'Taille police',
		gv: 'Volume son',
		h: 'Aide',
		ha: 'Aide',
		lg: 'Langue',
		playbutton: 'Jouer',
		pr: 'Préférences',
		saveas: 'Sauver le fichier',
		sful: 'URL police de sons',
		sp: 'Vitesse'
	}

	for (var k in text_kv)
		document.getElementById(k).innerHTML = text_kv[k];
	document.getElementById('ctxMenu').title = 'Jouer';

	document.getElementById("hlp").outerHTML = '<ul  id="hlp">\n\
<li>Vous pouvez, soit:\n\
    <ul>\n\
	<li>écrire directement du code ABC dans la zone d\'édition, ou</li>\n\
	<li>coller du code ABC dans la zone d\'édition, ou</li>\n\
	<li>charger un fichier ABC local (bouton \'Ouvrir un fichier\'), ou</li>\n\
	<li>glisser-déposer un fichier ABC local\n\
		ou une sélection de texte dans la zone d\'édition.</li>\n\
    </ul></li>\n\
<li>Vous pouvez modifier le code ABC comme vous voulez.<br/>\n\
	Le rendu se fait 2 secondes après.</li>\n\
<li>Le bouton \'Imprimer\' de votre browser n\'imprime que la zone de rendu.</li>\n\
<li>Vous pouvez sélectionner une partie des morceaux, ou bien depuis la zone\
	d\'édition (click et déplacement), ou bien depuis la zone de rendu.<br/>\
	Dans le dernier cas, un click gauche sur un élément de musique définit\
	le début de la sélection. Un click droit définit la fin.<br/>\
	Si votre navigateur peut jouer la musique, un click droit\
	en dehors de la musique affiche le menu associé.</li>\
</ul>';
}
Changes to edit-it.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
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






-
-




+
+
+
+
+





-





-








+













+
+
+
+
+
+


//JS - abc2svg edit - text in Italian
function loadtxt() {
	texts = {
		bad_nb: 'Numero di linea errato',
		fn: 'Nome file: ',
		load: 'Carica il file da includere ',
		play: 'Suona',
		stop: 'Ferma',
	}
	var text_kv = {
		a: 'A proposito',
		b: 'File ABC:',
		cmpa: 'Tutto',
		cmpt: 'Brano',
		cmps: 'Selezione',
		cmpl: 'Loop',
		cmpc: 'Continua',
//		df: 'Caratteristiche di abc2svg',
//		dp: 'Parametri di abc2svg',
		er: 'Errori',
		f: 'File',
		fl: 'Carica file',
		fo: 'Segui la musica',
		fs: 'Dimensione del font',
		gv: 'Volume',
		h: 'Aiuto',
		ha: 'Aiuto',
		lg: 'Lingua',
		playbutton: 'Suona',
		pr: 'Preferenze',
		saveas: 'Salva il file',
		sful: 'URL del Soundfont',
		sp: 'Velocità'
	}

	for (var k in text_kv)
		document.getElementById(k).innerHTML = text_kv[k];
	document.getElementById('ctxMenu').title = 'Suonare';

	document.getElementById("hlp").outerHTML = '<ul id="hlp">\n\
<li>Opzioni:\n\
    <ul>\n\
	<li>scrivere direttamente codice ABC nell\'area di testo, oppure</li>\n\
	<li>incollare codice ABC nell\'area di testo, oppure</li>\n\
	<li>caricare un file ABC locale (menu \'ABC | Carica file\'), oppure</li>\n\
	<li>trascinare un file locale da file manager\n\
		o del testo selezionato nell\'area di testo.</li>\n\
    </ul></li>\n\
	<li>Puoi modificare il codice ABC nell\'area di testo;<br/>\n\
	dopo 2 secondi la musica viene visualizzata o aggiornata.</li>\n\
	<li>L\'opzione \'Stampa\' del browser stampa la musica.</li>\n\
<li>Puoi selezionare parte di un brano sia nell\'area di testo\
	(fai click e seleziona), o nell\'area dello spartito.<br/>\n\
	In questo caso, un click su un elemento musicale inizia la selezione,\
	mentre un click col tasto destro la termina.<br/>\
	Inoltre, se il browser può suonare la musica, un click col tasto destro\
	al di fuori della musica mostra il menu Suonare.</li>\
</ul>'
}
Changes to edit-pt_BR.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
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






-
-




+
+
+
+
+





-





-
+


-
-
+
+




+














+
+
+
+
+
+


//JS - abc2svg edit - texto em português do Brasil
function loadtxt() {
	texts = {
		bad_nb: 'Número de linha incorreto',
		fn: 'Nome do arquivo: ',
		load: 'Por favor, inclua o arquivo ',
		play: 'Tocar',
		stop: 'Parar',
	}
	var text_kv = {
		a: 'Sobre',
		b: 'Arquivos ABC:',
		cmpa: 'Todo',
		cmpt: 'Peça',
		cmps: 'Selecção',
		cmpl: 'Loop',
		cmpc: 'Continua',
//		df: 'abc2svg features',
//		dp: 'abc2svg parameters',
		er: 'Erros',
		f: 'Arquivo',
		fl: 'Abrir arquivo ABC',
		fo: 'Follow music',
		fs: 'Tamanho da fonte',
		gv: 'Volume',
		h: 'Ajuda',
		ha: 'Ajuda',
		lg: 'Língua',
    		playbutton: 'Tocar',
//    		playbutton: 'Tocar',
		pr: 'Opções',
		saveas: 'Salvar arquivo',
		sful: 'Sound font URL',
		sp: 'Speed'
		sful: 'Sound font',
		sp: 'Velocidade'
	}

	for (var k in text_kv)
		document.getElementById(k).innerHTML = text_kv[k];
	document.getElementById('ctxMenu').title = 'Tocar';

	document.getElementById("hlp").outerHTML = '<ul  id="hlp">\n\
<li>Você pode:\n\
    <ul>\n\
	<li>escrever música em notação ABC diretamente na área de edição, ou</li>\n\
	<li>colar notação ABC na área de edição, ou</li>\n\
	<li>abrir um arquivo ABC local\n\
		(usando o botão \'Arquivo | Abrir arquivo\'), ou</li>\n\
	<li>arrastar e soltar na área de edição um arquivo ABC do seu gerenciador de arquivos\n\
		ou algum texto selecionado.</li>\n\
    </ul></li>\n\
<li>Você pode modificar o código ABC à vontade na área de edição.\n\
	Após 2 segundos, a partitura será gerada.</li>\n\
<li>A função \'Imprimir\' do seu navegador imprimirá apenas a partitura.</li>\n\
<li>Você pode selecionar uma parte da música ou da área de edição<br/>\
	(clicar e mover) ou da área da partitura.<br/>\
        Nesse último caso, um clique esquerdo num elemento musical\
        definirá o início da seleção. Um clique direito determinará o seu fim.<br/>\
        Um clique direito fora da música mostrará o menu de execução,\
        se o seu navegador for capaz de tocar a música.</li>\
</ul>';
}
Changes to editor/edit.css.
︙
65
66
67
68
69
70
71














72








73
74

75
76
77
78
79
80
81
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







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

-
+







		color: red;
	}
	#abckbd td {
		border: 1px solid black;
		padding: 0.5rem;
		text-align: center;
	}
	#ctxMenu {
		position:absolute;
		display:none;
		left:0px;
		top:0px;
		height:20px;
		width:40px;
		padding:0;
		margin:0;
		border:1px solid;
		background-color:white;
		font-weight:normal;
		white-space:nowrap;
		z-index:100;
}
	}
	#ctxMenu:hover > .droplinks {
		display:block;
	}
	#ctxMenu:before {
		content:attr(title);
	}
}
@media print {
	#dleft, .popup { display: none }
	#dleft, #ctxMenu, .popup { display: none }
	body {
		margin:0; padding:0; border:0;
		background-color: white;
	}
	#dright { margin:0; padding:0; border:0 }
	.newpage { page-break-before: always }
	.nobrk { page-break-inside: avoid }
︙
Changes to editor/edit.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// edit.js - file used in the abc2svg editor
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-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.
︙
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
28
29
30
31
32
33
34





35
36
37
38
39



40

41






42
43
44
45
46
47
48







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

-
+
-
-
-
-
-
-







		alert("window error: " + msg)
	return false
}

var	abc_images,			// image buffer
	abc_fname = ["noname.abc", ""],	// file names
	abc,				// Abc object
	ref,				// source reference array
	elt_ref = {},			// pointers to page elements
	colcl = [],			// colorized classes
	colcl_sav,			// (saved while playing/printing)
	abcplay,			// play engine
	srcend,				// source symbol end index
	elt_ref = {},			// pointers to page HTML elements
	selx = [0, 0],			// selected source indexes
	selx_sav = [],			// (saved while playing/printing)
	play = {},			// play data
	a_pe,				// playing events
	playing,
	selrec = {},
	pop,				// current popup message
	texts = {			// language specific texts
	texts = {},			// language specific texts
		bad_nb: 'Bad line number',
		fn: 'File name: ',
		load: 'Please, load the included file ',
		play: 'Play',
		stop: 'Stop'
	},
	jsdir = document.currentScript ?
		document.currentScript.src.match(/.*\//) :
		(function() {
			var scrs = document.getElementsByTagName('script');
			return scrs[scrs.length - 1].src.match(/.*\//) || ''
		})()

︙
79
80
81
82
83
84
85
86

87
88
89
90
91
92
93
70
71
72
73
74
75
76

77
78
79
80
81
82
83
84







-
+







		abc_images += str
	},
	// -- optional methods
	// annotations
	anno_stop: function(type, start, stop, x, y, w, h) {
		if (["beam", "slur", "tuplet"].indexOf(type) >= 0)
			return
		ref[start] = stop;		// keep the source reference
		srcend[start] = stop;	// source index of the end of the element

		// create a rectangle
		abc.out_svg('<rect class="abcr _' + start +
			'_" x="');
		abc.out_sxsy(x, '" y="', y);
		abc.out_svg('" width="' + w.toFixed(2) +
			'" height="' + abc.sh(h).toFixed(2) + '"/>\n')
︙
141
142
143
144
145
146
147
148
149






150
151
152
153
154
155
156
132
133
134
135
136
137
138


139
140
141
142
143
144
145
146
147
148
149
150
151







-
-
+
+
+
+
+
+







	if (!no_memo)
		storage(true, "lang", lang == "en" ? 0 : lang)
}

// show/hide a popup message
function popshow(area, visible) {
	var e = document.getElementById(area)
	if (pop)
		pop.style.visibility = 'hidden';
	if (pop) {
		if (pop == e)
			visible = false
		else
			pop.style.visibility = 'hidden'
	}
	e.style.visibility = visible ? 'visible' : 'hidden';
	pop = visible ? e : null
}

// load the (ABC source or include) file in the textarea
function loadtune() {
	var files = document.getElementById("abcfile").files
︙
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

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

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







-
+

















+



-
-
-
+













-
+






+
+



-
+








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















-
+


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

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

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


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



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

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


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



-
+












-
+














-
+


















-
-
-
-
-


-
+







-
+






-
+


-

+
+
+
+
+
+
+
+

-
+
+
+

+


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

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


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

-
+

-
+

-
+


-
+


-
-
+
+


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







}

// render the textarea content to the right side
function render() {
    var	i, j,
	content = elt_ref.source.value;

	a_pe = null
	play.a_pe = null
	if (!content)
		return			// empty source

	// if include file not loaded yet, ask it
	i = content.indexOf('%%abc-include ')
	if (i >= 0) {
		var sl = elt_ref.s1
		if (!sl.value) {
			sl.style.display = "inline";
			j = content.indexOf('\n', i);
			sl.value = content.slice(i + 14, j);
			selsrc(1);
			alert(texts.load + sl.value)
			return
		}
	}
	elt_ref.diverr.innerHTML = '';
	selx[0] = selx[1] = 0;
	render2()
}
function render2() {
    var	i,
	target = document.getElementById("target"),
	content = elt_ref.source.value
    var	content = elt_ref.source.value

	// load the required modules
	if (!abc2svg.modules.load(content + elt_ref.src1.value, render2))
		return

	user.img_out = user.my_img_out;
	user.get_abcmodel = null;

	abc = new abc2svg.Abc(user);
	abc_images = '';
	abc.tosvg('edit', '%%bgcolor white');

//	document.body.style.cursor = "wait";
	ref = []
	srcend = []
	try {
		abc.tosvg(abc_fname[0], content)
	} catch(e) {
		alert(e.message + '\nabc2svg tosvg bug - stack:\n' + e.stack)
		return
	}
	abc2svg.abc_end()		// close the page if %%pageheight

//	document.body.style.cursor = "auto";

	try {
		target.innerHTML = abc_images
		elt_ref.target.innerHTML = abc_images
	} catch(e) {
		alert(e.message + '\nabc2svg image bug - abort')
		return
	}

	// show the 'Error' button if some error
	document.getElementById("er").style.display =
				elt_ref.diverr.innerHTML ? 'inline' : 'none';

}
	// set the callbacks in the SVG images
	setTimeout(function(){
		var	elts = target.getElementsByClassName('abcr'),
			i = elts.length,
			elt
		elts = target.getElementsByTagName("svg");
		i = elts.length
		while (--i >= 0) {
			elt = elts[i];
			elt.onmousedown = svgsel
		}

	}, 300)
}

// select a source ABC element
// select a source ABC element on error
function gotoabc(l, c) {
	var	s = elt_ref.source,
		idx = 0;
	selsrc(0)
	while (--l >= 0) {
		idx = s.value.indexOf('\n', idx) + 1
		if (idx <= 0) {
			alert(texts.bad_nb);
			idx = s.value.length - 1;
			c = 0
			break
		}
	}
	c = Number(c) + idx;
	s.focus();
	s.setSelectionRange(c, c + 1)
	s.setSelectionRange(c, srcend[c] || c + 1)
}

// highlight the music element on mouse over
function m_over(elt) {
	if (selrec.rect)
		return
	if (colcl.length > 1)
		return
	colorsel(false)
	var cl = elt.getAttribute('class');
	colcl = [cl.split(' ')[1]];	// cl[0]:'abcr', cl[1]:elt ref
	colorsel(true)
}

// click in the target
// select elements in an image
function svgsel(evt) {
var	pt, nr, i, elts, elt, x, y, cl,
	svg = evt.target

function selsvg(evt) {
    var	v,
	elt = evt.target,
	cl = elt.getAttribute('class'),
	while (svg.tagName != 'svg') {
		svg = svg.parentNode
		if (!svg)
			return
	}

	ctxMenu = document.getElementById("ctxMenu");
	switch (evt.type) {
	case "mousedown":
		if (selrec.rect) {
			selrec.rect.parentNode.removeChild(selrec.rect);
			selrec.rect = null
		}
		colorsel(false);

	play.loop = false;
		window.getSelection().removeAllRanges();
		svg.onmousemove = svgsel;
		svg.onmouseup = svgsel;
		pt = svg.createSVGPoint();
		pt.x = evt.clientX;
		pt.y = evt.clientY;
		cl = pt.matrixTransform(svg.getScreenCTM().inverse());
		selrec.xs = cl.x;
		selrec.ys = cl.y;

		evt.stopImmediatePropagation();
		evt.preventDefault()
		break
	case "mousemove":
		pt = svg.createSVGPoint();
		pt.x = evt.clientX;
		pt.y = evt.clientY;
		cl = pt.matrixTransform(svg.getScreenCTM().inverse());
		selrec.x = cl.x;
		selrec.y = cl.y

		if (!selrec.rect) {
			nr = true;
	evt.stopImmediatePropagation();
	evt.preventDefault()

	// remove the context menu if active
	if (ctxMenu && ctxMenu.style.display == "block") {
		ctxMenu.style.display = "none"
		return false
	}

	// stop playing
	if (play.playing && !play.stop) {
		play.stop = -1;
		play.abcplay.stop()
		return false
	}

	// highlight the clicked element or clear the selection start
	s = elt_ref.source;
			selrec.rect = document.createElementNS("http://www.w3.org/2000/svg",
								'rect');
			selrec.rect.setAttribute("x", selrec.xs);
	if (cl && cl.substr(0, 4) == 'abcr') {
		v = Number(cl.slice(6, -1));
		s.setSelectionRange(v, srcend[v])
	} else {
		s.setSelectionRange(0, 0)
			selrec.rect.setAttribute("y", selrec.ys);
		}
	}
		if (selrec.x > selrec.xs && selrec.y > selrec.ys) {
			selrec.rect.setAttribute("width", selrec.x - selrec.xs);
			selrec.rect.setAttribute("height",selrec.y - selrec.ys)
		}
	s.blur();
	s.focus()
}
		if (nr) {
			selrec.rect.setAttribute("fill", "none");
			selrec.rect.setAttribute("stroke", "blue");
			svg.appendChild(selrec.rect)
		}

// set/clear a selection
function setsel(idx, v) {
    var i, elts, s,
	old_v = selx[idx];

		evt.stopImmediatePropagation();
		evt.preventDefault()
		break
	if (v == old_v)
		return
	case "mouseup":
//	case "mouseout":
		svg.onmousemove = null;
		svg.onmouseup = null
		if (!selrec.rect) {
			svg = evt.target
	if (old_v) {
		elts = document.getElementsByClassName('_' + old_v + '_');
		i = elts.length
			cl = svg.getAttribute('class')
			if (cl && cl.substr(0, 4) == 'abcr')
				m_over(svg)
			break
		}
		while (--i >= 0)
			elts[i].style.fillOpacity = 0
	}
		svg.removeChild(selrec.rect);

	if (v) {
		// define the selection
// (svg.getEnclosureList does not work)
		elts = svg.getElementsByClassName("abcr");
		elts = document.getElementsByClassName('_' + v + '_');
		i = elts.length
		while (--i >= 0) {
			elt = elts[i];
		while (--i >= 0)
			elts[i].style.fillOpacity = 0.4
			x = Number(elt.getAttribute("x"))
			y = Number(elt.getAttribute("y"))
			if (x < selrec.xs
			 || y < selrec.ys
			 || x + Number(elt.getAttribute("width")) > selrec.x
			 || y + Number(elt.getAttribute("height")) > selrec.y)
				continue
			cl = elt.getAttribute("class");
			colcl.push(cl.split(' ')[1])
		}
	}
		selrec.rect = null;
		colorsel(true);
		evt.stopImmediatePropagation();
		evt.preventDefault()
		break
	}

	selx[idx] = v
}

// colorize the selection
function colorsel(on, nosel) {
var	i, j, elts, d,
function do_scroll(elt) {
    var	r,
	i1 = 1000000,	// (hope a ABC file is smaller than that!)
	i2 = 0,
	dr = elt_ref.target.parentElement,		// <div> 'dright'
	n = colcl.length

	drh = dr.getBoundingClientRect().height,	// height of the view
	for (i = 0; i < n; i++) {
		elts = document.getElementsByClassName(colcl[i]);
		j = elts.length
	ty = elt_ref.target.getBoundingClientRect().y	// y offset of <div> 'target'
		while (--j >= 0)
			elts[j].style.fillOpacity = on ? 0.4 : 0
		if (on) {
			d = colcl[i].split('_')
			if (d[1] < i1)
				i1 = d[1]
			if (ref[d[1]] > i2)
				i2 = ref[d[1]]
		}

	}
	if (!nosel && i1 < i2) {
		var s = elt_ref.source;
		selsrc(0);
		elt = elt.parentNode;
	r = elt.getBoundingClientRect()
		s.setSelectionRange(i1, i2);
		s.blur();
		s.focus()
	}
	if (!on)
		colcl = []
// upper -> top, lower -> bottom
	if (r.y < 0)				// y offset of the svg container
		dr.scrollTo(0, r.y - ty)
	else if (r.y + r.height > drh)
		dr.scrollTo(0, r.y - ty - drh + r.height)
// in the middle
//	if (r.y < 0				// y offset of the svg container
//	 || r.y + r.height > drh)
//		dr.scrollTo(0, r.y - ty - drh / 2 + r.height)
}

// source text selection callback
function seltxt(elt) {
	var	start, end, s, z, elts
	if (colcl.length != 0)
function seltxt(evt) {
    var	s, elts,
	e = 0,
		colorsel(false);
	if (elt.selectionStart == undefined)
		return
	start = elt.selectionStart;
	elt = elt_ref.source,
	start = elt.selectionStart,
	end = elt.selectionEnd

	play.loop = false

	if (start == 0
	 && end == elt_ref.source.value.length)
		return				// select all
	if (ref) {
		ref.forEach(function(e, o) {
			if (o >= start && e <= end)
	if (!start) {
		if (end == elt.value.length)
			return			// select all
		setsel(0, 0);			// clear selection
		setsel(1, 0)
		return
	}

	if (srcend) {
		srcend.forEach(function(ie, is) {
			if (!s) {
				if (is >= start)
				colcl.push('_' + o + '_')
					s = is
			} else if (ie <= end) {
				e = is
			}
		})
	}
	if (colcl.length != 0) {
		colorsel(true, true);
	if (!s)
		return
	if (selx[0] != s)
		setsel(0, s)
		s = document.getElementById("dright");
	  z = window.document.defaultView.getComputedStyle(s).getPropertyValue('z-index')
		if (z != 10) {			// if select from textarea
			elts = document.getElementsByClassName(colcl[0]);
			if (elts[0])
				elts[0].scrollIntoView() // move the element on the screen
	if (selx[1] != e)
		setsel(1, e);
	elts = document.getElementsByClassName('_' + s + '_')
	if (elts[0])
		do_scroll(elts[0])	// move the element in the screen
		}
	}
}

// open a new window for file save
function saveas() {      
function saveas() {
	var	s = srcidx == 0 ? "source" : "src1",
		source = elt_ref[s].value,
		uriContent = "data:text/plain;charset=utf-8," +
				encodeURIComponent(source),

	// create a link for our script to 'click'
		link = document.createElement("a");

	elt_ref["s" + srcidx].value =
		link.download =
			abc_fname[srcidx] =
				prompt(texts.fn, abc_fname[srcidx]);
	link.innerHTML = "Hidden Link";	
	link.innerHTML = "Hidden Link";
	link.href = uriContent;

	// open in a new tab
	link.target = '_blank';

	// when link is clicked call a function to remove it from
	// the DOM in case user wants to save a second file.
	link.onclick = destroyClickedElement;

	// make sure the link is hidden.
	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)
}

// set the size of the font of the textarea
function setfont() {
    var	fs = document.getElementById("fontsize").value.toString();
	elt_ref.source.style.fontSize =
		elt_ref.src1.style.fontSize = fs + "px";
	storage(true, "fontsz", fs == "14" ? 0 : fs)
}

// playing
// set 'follow music'
function set_follow(e) {
	abcplay.set_follow(e.checked)
	storage(true, "follow", e.checked == "1" ? 0 : "0")
}
// set soundfont URL
function set_sfu(v) {
	abcplay.set_sfu(v)
	play.abcplay.set_sfu(v)
	storage(true, "sfu", v == "Scc1t2" ? 0 : v)
}
// set_speed value = 1..20, 10 = no change
function set_speed(iv) {
    var	spvl = document.getElementById("spvl"),
	v = Math.pow(3,			// max 3 times lower/faster
			(iv - 10) * .1);
	abcplay.set_speed(v);
	play.abcplay.set_speed(v);
	spvl.innerHTML = v
}
// set volume
function set_vol(v) {
    var	gvl = document.getElementById("gvl");
	gvl.innerHTML = v.toFixed(2);
	abcplay.set_vol(v)
	play.abcplay.set_vol(v)
	storage(true, "volume", v == 0.7 ? 0 : v.toFixed(2))
}
//fixme: do tune/start-stop selection of what to play
function notehlight(i, on) {
	if (play.stop) {
		if (on)				// (should not occur anymore)
			return
		if (play.stop < 0)		// if first stop
			play.stop = i		// keep the last note reference
		if (i == selx[1])		// if end selection
			return			// don't remove highlight
	}
	var elts = document.getElementsByClassName('_' + i + '_');
	if (elts && elts[0])
	if (elts && elts[0]) {
		if (on)
			do_scroll(elts[0]);
		elts[0].style.fillOpacity = on ? 0.4 : 0
	}
}
function endplay() {
	document.getElementById("playbutton").innerHTML = texts.play;
	playing = false;
	if (play.loop) {
	colcl = colcl_sav;
	colorsel(true)
}
function play_tune() {
		play.abcplay.play(play.si, play.ei, play.a_pe)
		return
	}
	play.playing = false;
    var	pe

	function build_pe() {
	// redisplay the selection
	    var	i, e,
		set = {}

	selx[0] = selx[1] = 0;
	setsel(0, selx_sav[0]);
		pe = []
		for (i = 0; i < colcl.length; i++) {
			e = colcl[i].slice(1, -1)
	setsel(1, selx_sav[1])
			set[e] = true
		}
}
		for (i = 0; i < a_pe.length; i++) {
			e = a_pe[i]
			if (set[e[0]])
				pe.push(e)
		}
	} // build_pe()

	if (playing) {
		abcplay.stop();

// start playing
//	-1: All
//	0: Tune
//	1: Selection
//	2: Loop
//	3: Continue
function play_tune(what) {
	if (play.playing) {
		if (!play.stop) {
			play.stop = -1;
			play.abcplay.stop()
		}
		return
	}

	// search a playing event from a source index
	function get_se(si) {			// get highest starting event
	    var	i, s, tim,
		sih = 1000000,
		pa = play.a_pe,
		ci = 0

		if (si <= pa[0][0])
			return 0
		if (si >= pa[pa.length - 1][0])
			return pa.length

		si = go_note(si);

		i = pa.length
		while (--i > 0) {
			s = pa[i][0]
			if (s < si)
				continue
			if (s == si) {
				ci = i
				break
			}
			if (s < sih) {
				ci = i;
				sih = s
			}
		}

		// go to the first voice at this time
		if (ci < pa.length) {
			tim = pa[ci][1]
			while (--ci >= 0) {
				if (pa[ci][1] != tim)
					break
			}
		}
		return ci + 1
	} // get_se()

	function get_ee(si, i) {		// get lowest ending event
	    var	s, tim,
		sil = 0,
		pa = play.a_pe,
		ci = 0

		if (si <= pa[0][0])
			return 0
		if (si >= pa[pa.length - 1][0])
			return pa.length

		si = go_note(si)

		for ( ; i < pa.length; i++) {
			s = pa[i][0]
			if (s > si)
				continue
			if (s == si) {
				ci = i
				break
			}
			if (s > sil) {
				ci = i;
				sil = s
			}
		}

		// go to after the last voice at this time
		if (ci > 0) {
			tim = pa[ci++][1]
			for ( ; ci < pa.length; ci++) {
				if (pa[ci][1] != tim)
					break
			}
		}
		return ci
	} // get_ee()

	// start playing
	function play_start(si, ei) {
		selx_sav[0] = selx[0];		// remove the colors
		selx_sav[1] = selx[1];
		setsel(0, 0);
		setsel(1, 0);

		play.stop = 0;
		play.abcplay.play(si, ei, play.a_pe)	// start playing
	}

	// play tune()
    var	abc, i, si, ei, elt, tim,
	s = elt_ref.source.value,
	ctxMenu = document.getElementById("ctxMenu");

	// search a note/rest in the source from a selection
	function go_note(si) {
		for (var i = si; ; i++) {
			if (!s[i])
				return si
			if ('ABCDEFGabcdefg[^_='.indexOf(s[i]) >= 0)
				break
		}
		return i
	}

	ctxMenu.style.display = "none";	// remove the play menu

	playing = true;
	if (!a_pe) {			// if no playing event
	play.playing = true;
	if (!play.a_pe) {		// if no playing event
		user.img_out = null	// get the schema and stop SVG generation
		user.get_abcmodel = abcplay.add	// inject the model in the play engine
		user.get_abcmodel = play.abcplay.add // inject the model in the play engine

		var abc = new abc2svg.Abc(user);
		abc = new abc2svg.Abc(user);

		abcplay.clear();
		play.abcplay.clear();
		abc.tosvg("play", "%%play")
		try {
			abc.tosvg(abc_fname[0], elt_ref.source.value)
			abc.tosvg(abc_fname[0], s)
		} catch(e) {
			alert(e.message + '\nabc2svg tosvg bug - stack:\n' + e.stack);
			playing = false;
			a_pe = null
			play.playing = false;
			play.a_pe = null
			return
		}
		a_pe = abcplay.clear()	// keep the playing events
	}
	document.getElementById("playbutton").innerHTML = texts.stop;

	if (colcl.length <= 1)
		pe = a_pe
	else
		build_pe();
	colcl_sav = colcl;
	colorsel(false);
	abcplay.play(0, 1000000, pe)
		play.a_pe = play.abcplay.clear(); // keep the playing events

		play.si = play.ei = play.stop = 0;
		play.loop = false
	}

	// play all
	if (what < 0) {
		play.loop = false;
		play.si = 0;
		play.ei = play.a_pe.length;
		play_start(play.si, play.ei)
		return
	}

	// if loop again
	if (what == 2 && play.loop) {
		play_start(play.si, play.ei)
		return
	}

	// get the starting and ending play indexes, and start playing
	if (what == 3 && play.stop > 0) {	// if stopped and continue
		play_start(get_se(play.stop), play.ei)
		return
	}
	if (what != 0 && selx[0] && selx[1]) {	// if full selection
		si = get_se(selx[0]);
		ei = get_ee(selx[1], si)
	} else if (what != 0 && selx[0]) {	// if selection without end
		si = get_se(selx[0]);
		i = s.indexOf('\nX:', selx[0]);
		ei = i < 0 ? play.a_pe.length : get_ee(i, si)
	} else if (what != 0 && selx[1]) {	// if selection without start
		i = s.lastIndexOf('\nX:', selx[1]);
		si = i < 0 ? 0 : get_se(i);
		ei = get_ee(selx[1], si)
	} else {				// no selection => tune
		si = play.click.svg.getElementsByClassName('abcr');
		elt = play.click.svg		// (dummy)
		for (i = 0; ; i++) {
			if (!si[i]) {
				elt = null
				break
			}
			if (si[i].parentNode == elt.parentNode)
				continue		// same container
			elt = si[i];
			ei = elt.parentNode.getBoundingClientRect()
			if (ei.y < play.click.Y
			 && ei.y + ei.height > play.click.Y)
				break
		}
		i = elt ? Number(elt.getAttribute('class').slice(6, -1)) : 0;
		si = ei = 0
		if (s[0] == 'X' && s[1] == ':')
			si = 1
		while (1) {		// search the start and end of the tune
			ei = s.indexOf('\nX:', ei)
			if (ei < 0 || ei > i)
				break
			si = s.indexOf('\nK:', ++ei)
			if (si < 0)
				break
			ei = s.indexOf('\n', si + 1) + 1
		}
		if (si <= 0) {
			play.playing = false
			return		// no tune!
		}

		si = get_se(si);
		ei = ei < 0 ? play.a_pe.length : get_ee(ei, si)
	}

	if (what != 3) {		// if not continue
		play.si = si;
		play.ei = ei;
		play.loop = what == 2
	}

	play_start(si, ei)
}

// set the version and initialize the playing engine
function edit_init() {

	// loop until abc2svg is fully loaded
	if (typeof abc2svg != "object"
︙
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
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
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
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







+
+
+









-
+
-
-
+






-
+






-
+
-
-
-
-
+
+
+
+
-


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





-
+



-
-
-

-




-
-
+

-
+

-
+

-
+

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







			s.onload = relay;
		s.onerror = onerror || function() {
			alert('error loading ' + fn)
		}
		document.head.appendChild(s)
	}

	// accept page formatting
	abc2svg.abc_end = function() {}

	function set_pref() {
	    var	v = storage(true, "fontsz")
		if (v) {
			elt_ref.source.style.fontSize =
				elt_ref.src1.style.fontSize =
					v + "px";
			document.getElementById("fontsize").value =
					Number(v)
		}
		v = storage(true, "lang")
		v = storage(true, "lang");
		if (v)
			loadlang(v, true)
		loadlang(v || 'en', true)
	}

	document.getElementById("abc2svg").innerHTML =
		'abc2svg-' + abc2svg.version + ' (' + abc2svg.vdate + ')'

	// keep references on the page elements
	var a = ["diverr", "source", "src1", "s0", "s1"]
	var a = ["diverr", "source", "src1", "s0", "s1", "target"]
	for (var i = 0; i < a.length; i++) {
		var e = a[i];
		elt_ref[e] = document.getElementById(e)
	}

	// set the callback functions
	e = document.getElementById("saveas");
	document.getElementById("saveas").onclick = saveas;
	e.addEventListener("click", saveas);
	e = elt_ref.s0;
	e.addEventListener("click", function(){selsrc(0)});
	e = elt_ref.s1;
	elt_ref.s0.onclick = function(){selsrc(0)};
	elt_ref.s1.onclick = function(){selsrc(1)};
	elt_ref.target.onclick = selsvg;
	elt_ref.source.onselect = seltxt;
	e.addEventListener("click", function(){selsrc(1)})

	// remove the selection on print
	window.addEventListener("beforeprint", function() {
		colcl_sav = colcl;
		colorsel(false)
	});
	window.addEventListener("afterprint", function() {
		colcl = colcl_sav;
		colorsel(true)
	window.onbeforeprint = function() {
		selx_sav[0] = selx[0];		// remove the colors
		selx_sav[1] = selx[1];
		setsel(0, 0);
		setsel(1, 0)
	};
	window.onafterprint = function() {
		setsel(0, selx_sav[0]);
		setsel(1, selx_sav[1])
	})
	}

	// if playing is possible, load the playing script
	if (window.AudioContext || window.webkitAudioContext
	 || navigator.requestMIDIAccess) {
		abc2svg.loadjs("play-@MAJOR@.js", function() {
			abcplay = AbcPlay({
			play.abcplay = AbcPlay({
					onend: endplay,
					onnote:notehlight,
					});
			var e = document.getElementById("playbutton");
			e.addEventListener("click", play_tune);
			e.style.display = "inline-block";
			document.getElementById("playdiv1").style.display =
				document.getElementById("playdiv2").style.display =
				document.getElementById("playdiv3").style.display =
				document.getElementById("playdiv4").style.display =
					"list-item";

			document.getElementById("fol").checked = abcplay.set_follow();
			document.getElementById("sfu").value = abcplay.set_sfu();
			document.getElementById("sfu").value = play.abcplay.set_sfu();
//			document.getElementById("spv").innerHTML =
//				Math.log(abcplay.set_speed()) / Math.log(3);
//				Math.log(play.abcplay.set_speed()) / Math.log(3);
			document.getElementById("gvol").setAttribute("value",
				abcplay.set_vol() * 10)
				play.abcplay.set_vol() * 10)
			document.getElementById("gvl").setAttribute("value",
				(abcplay.set_vol() * 10).toFixed(2))
				(play.abcplay.set_vol() * 10).toFixed(2))
		});

		var e = elt_ref.target;
		e.oncontextmenu = function(evt) {
		    var	x, y,
			elt = evt.target,
			cl = elt.getAttribute('class');

			evt.stopImmediatePropagation();
			evt.preventDefault()

			// if right click on an element, select it
			if (cl && cl.substr(0, 4) == 'abcr') {
				setsel(1, Number(cl.slice(6, -1)))
				return false
			}

			// otherwise, display the play menu
			play.click = {	// keep the click references for 'play tune'
				svg: elt,
				Y: evt.pageY
			}

			var ctxMenu = document.getElementById("ctxMenu");
			ctxMenu.style.display = "block";
			x = evt.pageX - elt_ref.target.parentNode.offsetLeft
					+ elt_ref.target.parentNode.scrollLeft;
			y = evt.pageY + elt_ref.target.parentNode.scrollTop;
			ctxMenu.style.left = (x - 30) + "px";
			ctxMenu.style.top = (y - 10) + "px"
			return false
		} // oncontextmenu
	}
	set_pref()	// set the preferences from local storage
}

// drag and drop
function drag_over(evt) {
	evt.stopImmediatePropagation();
︙
716
717
718
719
720
721
722
723

724
725
726
727
728
860
861
862
863
864
865
866

867
868
869
870
871
872







-
+





	}
}

// render the music after 2 seconds on textarea change
var timer
function src_change() {
	clearTimeout(timer);
	if (!playing)
	if (!play.playing)
		timer = setTimeout(render, 2000)
}

// wait for scripts to be loaded
setTimeout(edit_init, 500)
Changes to editor/edit.xhtml.
︙
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
33
34
35
36
37
38
39





40
41
42
43
44
45
46







-
-
-
-
-







			</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="playdiv2" style="display: none">
				<label id="fo">Follow music</label>
				 <input id="fol" type="checkbox" checked="false"
					onclick="set_follow(this)"/>
			</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">
︙
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
57
58
59
60
61
62
63

64
65
66
67
68
69
70







-







		<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" id="playbutton" style="display: none">Play</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.xhtml">abc2svg features</a>
			</li>
			<li><a id="dp" target="_blank"
︙
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
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







-










+
+
+
+
+
+
+
+
+
+
+







-
















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









+
+
+
+
+
+
+
+



<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"
	onselect="seltxt(this)"
	ondrop="dropped(event)" ondragenter="drag_over(event)"
	ondragover="drag_over(event)"
	oninput="src_change()"></textarea>
<textarea id="src1" rows="40" cols="73" wrap="off"
	style="font: 14px monospace; display: none"
	oninput="src_change()"></textarea>
</div>

<!-- right - needed for the scrollbars -->
<div id="dright">

<!-- context menu -->
<div id="ctxMenu" title="Play">
	<ul class="droplinks">
	<li id="cmpa" onclick="play_tune(-1)">All</li>
	<li id="cmpt" onclick="play_tune(0)">Tune</li>
	<li id="cmps" onclick="play_tune(1)">Selection</li>
	<li id="cmpl" onclick="play_tune(2)">Loop</li>
	<li id="cmpc" onclick="play_tune(3)">Continue</li>
	</ul>
</div>

<!-- rendering area -->
<div id="target">
<svg xmlns="http://www.w3.org/2000/svg"
	xmlns:xlink="http://www.w3.org/1999/xlink"
	xml:space="preserve"
	width="8.3in" height="2in" viewBox="0 0 595 144">
<title>(void)</title>
<text x="250" y="100" font-family="serif" font-size="12">(void)</text>
</svg>
</div>
</div>

<!-- error popup window -->
<div id="errlist" class="popup" style="width: 500px">
<div class="close" onclick="popshow('errlist')">x</div>
<div id="diverr">
</div>
</div>

<!-- help popup window -->
<div id="help" class="popup" style="width: 550px">
<div class="close" onclick="popshow('help')">x</div>
<ul id="hlp">
<li>You may either:
    <ul>
	<li>directly write ABC code in the text area, or</li>
	<li>paste ABC code in the text area, or</li>
	<li>load a local ABC file ('Load a ABC file' button), or</li>
	<li>drag &amp; drop a local file from your file manager
		or a selected text to the text area.</li>
    </ul></li>
<li>(dynamically loaded)</li>
<li>You may change at will the ABC code in the text area.<br/>
	Rendering is done 2 seconds later.</li>
<li>The 'Print' button of the browser outputs the rendering area.</li>
</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-2018 Jean-François Moine</p>
</div>

<!-- javascript must be enabled -->
<div id="okjs" class="popup" style="width:50%;background:#ff8080;visibility:visible">
Please enable Javascript.
</div>
<script>
document.getElementById('okjs').style.visibility = 'hidden'
</script>

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

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



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

// abc2svg music font
var musicfont = 'url("data:application/font-ttf;base64,\
AAEAAAANAIAAAwBQRkZUTX30pOoAACfYAAAAHE9TLzJYnlnxAAABWAAAAFZjbWFwN+qJgQAAAsAA\
AAIqY3Z0IAAiAogAAATsAAAABGdhc3D//wADAAAn0AAAAAhnbHlmirg/swAABXwAAB4caGVhZAsO\
geEAAADcAAAANmhoZWEIoQEcAAABFAAAACRobXR4cVoAlAAAAbAAAAEObG9jYQpbAnAAAATwAAAA\
im1heHAAiwDcAAABOAAAACBuYW1lNpjajAAAI5gAAAGDcG9zdA9CdgsAACUcAAACsQABAAAAAQAA\
tjNVVF8PPPUACwQAAAAAANGXIhcAAAAA1qodLf+6/QwD9ASUAAAACAACAAAAAAAAAAEAAASU/QwA\
XAQN/7r/vwP0AAEAAAAAAAAAAAAAAAAAAABDAAEAAABEAKsABQAAAAAAAgAAAAEAAQAAAEAALgAA\
AAAAAQG7AZAABQAIApkCzAAAAI8CmQLMAAAB6wAzAQkAAAIABQMAAAAAAAAAAAAAEAAAAAAAAAAA\
AAAAUGZFZABAAADpXAMz/zMAXASUAvQAAAABAAAAAAAAAXYAIgAAAAABVQAAAZAAAABXAAAB4P/c\
A14AegMLAAAC0gAAAr//ugHWAAADCwAAAw4AAAMn/8gBrgAAASIAAAGQAAABfAAAAZAAAAGQAAAB\
gQAAAZAAAAGQAAABgQAAAZkACQGYAAkB9AAAAQQAFAEEAAoCEQAAAhwAAAHAAAABSQAAAUoAAAFK\
//4BLAAAAjAAAAHgAAABDQAyAMgAAAENAAABCwAUAW4AAAENADIBQP/9ARgAAAJYAAAAtgAAAIIA\
AACCAAABLAAAASwAAADuAAAA/wAAAUkAAAGPAAAB2AAAAdgAAANTAAACM//wAyD/4QG1AAABtQAA\
AkQADQJEAA0EDQAAAhwADAAAAAAAAAADAAAAAwAAABwAAQAAAAABJAADAAEAAAAcAAQBCAAAAD4A\
var musicfont = 'url("data:application/x-font-ttf;base64,\
AAEAAAAOAIAAAwBgRkZUTYGiLYcAAFMIAAAAHEdERUYAFQAUAABS7AAAABxPUy8yWLxbCQAAAWgA\
AABWY21hcM7xzSEAAAPMAAADKmN2dCAAIgKIAAAG+AAAAARnYXNw//8AAwAAUuQAAAAIZ2x5ZvUw\
oLYAAAgEAABCqGhlYWQNXJHdAAAA7AAAADZoaGVhCWn/CwAAASQAAAAkaG10eM2n+wQAAAHAAAAC\
CmxvY2HVL+UYAAAG/AAAAQhtYXhwAMoBPQAAAUgAAAAgbmFtZcjHNnAAAEqsAAADGHBvc3TQFqwa\
AABNxAAABR8AAQAAAAEAAGk1jGtfDzz1AAsEAAAAAADRlyIXAAAAANgjLVL/OPzvBUsEiAAAAAgA\
AgAAAAAAAAABAAAEiPzvAFwEJf84/XQFSwABAAAAAAAAAAAAAAAAAAAAggABAAAAgwEMAAUAAAAA\
AAIAAAABAAEAAABAAC4AAAAAAAEBlwGQAAUACAKZAswAAACPApkCzAAAAesAMwEJAAACAAUDAAAA\
AAAAAAAAARAAAAAAAAAAAAAAAFBmRWQAQAAA6qQDM/8zAFwEiAMRAAAAAQAAAAAAAAF2ACIAAAAA\
AVUAAAGQAAACWAAAAFcAAAFK/7ACE/+wANL/sAAjAAAAIwAAACMAAABkAAAEIwAABCUAAAHg/9wD\
XgB6AwsAAALSAAACv/+6AdYAAAMLAAADDgAAAyf/yADIAAABrgAAASIAAAGQAAABfAAAAZAAAAGQ\
AAABgQAAAZAAAAGQAAABgQAAAZkACQGYAAkB9AAAAQQAFAEEAAoCawAkAhIAAAHCAAABSQAAAUAA\
AAFK//4BLAAAAjAAAAFKAAABSgAAAGQAAAE7AAABOwAAATsAAAE7AAABOwAAATsAAAE7AAABOwAA\
ATsAAAE7AAABDQAAAMgAAAD/AAABCwAUAW4AAAENADIBbv/1AKkAAAE6AAABQP/9AFAAAAFAAAAB\
QAAAARgAAAJYAAAAtgAAAIIAAACCAAABLAAAASwAAADuAAAA/wAAAUkAAAGPAAAB2AAAAdgAAANT\
AAACM//wAyD/4QIz/7QBuP/bAV//fgIzAAACM//kAr//tAIz/7QCv/+0Ayv/2wFf/9sCaf9+AV//\
fgJp/34BXwAAAf0ABQG1AAABtQAAAkQADQJEAA0BGAAAATYAAAEs//8BLAAAAPoAAADIAAABGP84\
IAAEAB4AAOAA4EjgUOBc4GLgaeB84IzgleCk4Kngs+EB4efiZOKA5KDkrOTA5M7k6uTu5QHlZ+Vp\
5W3mUOZV6Vz//wAAAADgAOBH4FDgXOBi4GngeuCA4JTgoOCp4LPhAeHn4mDigOSg5KzkwOTO5OHk\
APoAAADIAAAEDQAAAhwADAH0AAAB9AAAAfQAAAH0AAAB9AAAAfQAAAB4AAAALQAAAhwAAAD6AAD/\
6gAAAAAAAwAAAAMAAAAcAAEAAAAAAiQAAwABAAAAHAAEAggAAAB+AEAABQA+AAAAIOAA4CTgMOA5\
4EPgSOBQ4FzgYuBp4H3gjOCV4KTgqeCz4QHhueG74efiSeJk4oPkoOSi5KTkqOSs5MDkzuTq5O7l\
AeUi5SXlLeUx5TnlZ+Vp5W3lguXQ5eLmEOYS5hTmGOYk5jDmUOZV6RLpFekY6SDpJeld6gLqpP//\
AAAAAAAg4ADgIuAw4DjgQ+BF4FDgXOBi4GngeuCA4JTgoOCp4LPhAeG54bvh5+JA4mDigOSg5KLk\
7uUA5WflaeVs5lDmVelc//8AAyAEH74ftx+sH6cfoR+RH44fhx99H3kfcB8jHj4dxh2rG4wbgRtu\
G2EbTxtMGzsa1hrVGtMZ8RntFucAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBgAAAwAAAAAAAAABAgAAAAIAAAAAAAAAAAAA\
AAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
pOSo5KzkwOTO5OHk7uUA5SDlJOUp5S/lOeVm5WnlbOWC5dDl4uYQ5hLmFOYY5iTmMOZQ5lXpEOkU\
6RjpIOkl6V3qAuqk//8AA//kIAUf5B/ZH9IfyR/IH8Efth+xH6sfmx+ZH5IfiB+EH3sfLh53HnYe\
Sx3zHd0dwhumG6UbpBuhG54bixt+G2wbaRtYGzobORs2GzUbLhsCGwEa/xrrGp4ajRpgGl8aXhpb\
GlAaRRomGiIXaBdnF2UXXhdaFyMWfxXeAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGAAADAAAAAAAAAAECAAAA\
AgAAAAAAAAAAAAAAAAAAAAEAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAACICiAAAACoAKgAqADYAZgDOARABpgI4ApICpgNCA9QELAROBGIEtAUEBSQFagWqBeQG\
MAZwBrYHEAckB0oHcAesB8gH9ggiCDwIVgiMCJoIrAjSCOwJHAlGCaIJyAnwCgAKKApOCloKZgpy\
Cn4KoArGCvwLSguqDB4MNAxaDIgMzA0WDTANVA40DvAPDgAAAAIAIgAAATICqgADAAcALrEBAC88\
sgcEAO0ysQYF3DyyAwIA7TIAsQMALzyyBQQA7TKyBwYB/DyyAQIA7TIzESERJzMRIyIBEO7MzAKq\
/VYiAmYAAAEAAAAAAZEBkAADAAAxESERAZEBkP5wAAEAAAAAAFcEAwAgAAARNTY1NCcmNTQ3BhUU\
AAAAAAAAAAAAAAAAAAAAAAAAIgKIAAAAKgAqACoANgA+AG4AfACKAJgApACwAL4A3AFQAawCHAJe\
AvADggPkA/gElAUmBX4FvAXeBfIGRAaUBrQG+gc6B3QHwAgACEYIoAi0CNoJAAkyCU4JcAmcCbIJ\
zAoCChAKHAooCjoKVApuCqIK1gsqC3QL1AwyDKgNHA1CDVwNjA22Dg4ONA6ODq4O7A8UDygPNA9C\
D1IPeg+gD6wPuA/ED9AP8hAYEE4QnBD8EXARhhGsEdoSPhK2ExQTXBO4FRIWHhbYF5gYaBkEGeIa\
/hwAHEIchhzQHOodDh0iHTYdZh12HYgdpB26Hd4eDh7wH6wf1B/yICQgYiCUINYg6CD2IRIhLCFU\
AAIAIgAAATICqgADAAcALrEBAC88sgcEAO0ysQYF3DyyAwIA7TIAsQMALzyyBQQA7TKyBwYB/Dyy\
AQIA7TIzESERJzMRIyIBEO7MzAKq/VYiAmYAAAEAAAAAAZEBkAADAAAxESERAZEBkP5wAAEAAAAA\
FxYVFAcWFRQHBhUUFyY1NDc2NTQ1IxJXPxUlTU0lFT9XEiMCAwIYQzZgOTRmOjJLIjlhTWEYGGZM\
YDklSjI6ZjQ5YDZIAAP/3AACAd4CswAHAA8ARwAAACImNDYyFhQEIiY0NjIWFBc0NjMyFhUUBxYz\
MjY1NCcmJwMnEyY1NDc2MhYVFAYjIiY1NDcmIyIGFRQXFhcTFwMWFRQHBiImAZ4gGBggGP5+IBgY\
IBhbGxQTHiwYKCdBMDxBzyvTmDgoYDgbFBMeLBgoJ0EwQTvUK9eYOChgOAFSGCAYGCBUGCAYGCDY\
EhwaER0OGC8lKDAtOP7eIAEmj2A1LxQzIRIcGhEdDhgvJSgwMTQBJh/+1pBgNS8UMwAFAHr/NANe\
AlQAFwAbAB8AIwAnAAABMxUeARczFSMOAQcVIzUuAScjNTM+ATcRIxYXNxU2NyczJicHNQYHAdgo\
VXgHiooHeFUoVXgHiooHeFVwBWsoawVwcAVrKGsFAlSJCItgKGCLCImJCItgKGKJCP7lug7IyA66\
KLoOyMkOuwAAAAAEAAD9gQKnBJQAPwBGAFoAZwAAATYzMhYXFhUUBwYHFxYVFAYjIiY1NDYzMhYV\
FAYHFjMyNTQvAQYjIiY1NDc+ATc+AjcuAjU0NjceARUUBgcbATY1NCYjCwEOARUUFy4BNTQ2NycO\
AQcSITIDBhUUFz4BNTQmJw4BAY8SCzVnID98QisQAkVPUWBAMi5CPjAbKmUBEQscr8E5El4mBi0w\
AAAAAAAAAAAxAAABAAAAAABXBAMAIAAAETU2NTQnJjU0NwYVFBcWFRQHFhUUBwYVFBcmNTQ3NjU0\
NSMSVz8VJU1NJRU/VxIjAgMCGEM2YDk0ZjoySyI5YU1hGBhmTGA5JUoyOmY0OWA2SAAB/7D/7AGa\
ABQAAwAAJyEVIVAB6v4WFCgAAAAAAf+w/+wCYgAUAAMAACchFSFQArL9ThQoAAAAAAH/sP/sASIA\
FAADAAAnIRUhUAFy/o4UKAAAAAABAAAAAAAjA+gAAwAAETMRIyMjA+j8GAABAAAB9AAjA+gAAwAA\
ETMRIyMjA+j+DAABAAAC+AAjBFYAAwAAETcRIyMjBEwK/qIAAAAAAgAAAUAAZAKeAAcADwAAEiIm\
NDYyFhQCIiY0NjIWFEcqHR0qHR0qHR0qHQI6HSodHSr+6R0qHR0qAAAABQAAAAAEJAGuAC8ANwA/\
AEcAUwAAITUzHgEzMjY1NCcuBDU0NjMyFhc3MxcjLgEjIgYVFB4DFx4BFRQGIyInByAiJjQ2MhYU\
BCImNDYyFhQBETMyNjQmIwM1MxEjNTMyFhUUIwJOHhVPMik7lBkaKhYRWT0kJxkeHgceD0owHzkQ\
IhkyCE5NW09FLiMBmyodHSod/eoqHR0qHf6JKDxGRjzcRkbccYn6oDxLICEtKAcIFBQjFUNNCw4Z\
mzpIKBsPFw8JCwIVNzM6TiAgHSodHSodHSodHSoBaf6YYaZh/noeAWgeZ2vSAAUAAAAABCQBrgAa\
ACIAKgAyAD4AACEiJjU0NjMyFhc3MxcHJiMiBhQWMzI2NxcOATIiJjQ2MhYUBCImNDYyFhQBETMy\
NjQmIwM1MxEjNTMyFhUUIwMCZ3WCWiUpGx4eCCEkXjg2Njg2TREjFFmxKh0dKh396iodHSod/oko\
PEZGPNxGRtxxifprZ2V3DBIepgSMbZhtST4KSlEdKh0dKh0dKh0dKgFp/phhpmH+eh4BaB5na9IA\
AAAD/9wAAgHeArMABwAPAE0AAAAiJjQ2MhYUBCImNDYyFhQXNDYzMhYVFAcWMzI2NTQvAQMnEy4B\
NTQ+ATc2MzIWFRQGIyImNTQ3JiMiBhUUHwETFwMeARUUDgEHBiMiJgGeIBgYIBj+fiAYGCAYWxsU\
Ex4sFykmNiZ7zyvRWkgcExQmMzA4GxQTHiwXKSY2JnrUK9VaSBwTFCYzMDgBUhggGBggVBggGBgg\
0xIcGhEdDhctJi0mZf7eIAElR3E4Fi0RERM4IRIcGhEdDhctJi0mZQEmH/7XR3I4Fi0RERM4AAUA\
ev80A14CVAAXABsAHwAjACcAAAEzFR4BFzMVIw4BBxUjNS4BJyM1Mz4BNxEjFhc3FTY3JzMmJwc1\
BgcB2ChVeAeKigd4VShVeAeKigd4VXAFayhrBXBwBWsoawUCVIkIi2AoYIsIiYkIi2AoYokI/uW6\
DsjIDrooug7IyQ67AAAAAAQAAP1vAqcEiAALAEgAUgBnAAABBhUUFz4BNTQnDgETFxQVFAYjIiY1\
FwMKBW9ROx5beR8fq25OFSA3Ry8yM2BJEY9sAQUBLwQpBAdJcBgaO0UBCgIqJkR7lDwiBLsgDlBN\
WEEsQEQtKzIBD4ASCr4Bt6yEZiNkHgUoKBEhdUgdip4YQHlyiahf/rX+nieRQGr+ngFeCkAwLToM\
WjpGYhS9cpdn/tYEDiEuUiMxj0gpTw8HdwACAAD9/ALSAgAAZABoAAABMjY1NCcmIyIHDgIHJicm\
JxEjETMRNjc2Nx4DFxYzMjY1NCcmIyIHFhcUFhUUBisBJjU0NzY3NjMyFxYXFRQGBwYjIicHFzYz\
MhYXFh0BBgcGIyImNTQ3MzIWFRQGFQYHFgEzESMB3j5KDRpJRjwCBgoEIhoeLhwcLh4aIgYUDBkP\
NDYzMhYUBgcWMzI2NTQ1JwYjIi4CNTQ3PgY/ASY1NDY3FhUUBgcXNjMyFhUUJzQmIyIGIxM+AScO\
ARUUFhcuATU0NycOAQceATMyNwFsBwVIdTY5QksXT01SX0AyL0E/Ly0YLkEXFBVJhmc9Og0kIC4d\
MRIXFg1sSWJceRQQD3GITmJQAgcCIVtB4jZGJx09P6YRj2wBAqB6EBADUzYuF2YxlUhyDQde+2zs\
AQJMXFNBLUg7WDcBGT1FAgHpAjNbh0+FZhcwJS0aJw4REJZmjKEHOuWIqV/PAp1yzro9ZwH+nRJd\
8gtGMSBCEg5FR6kuvXKXZ42jAgAAAAACAAD9/ALSAgAAZABoAAABMjY1NCcmIyIHDgIHJicmJxEj\
ETMRNjc2Nx4DFxYzMjY1NCcmIyIHFhcUFhUUBisBJjU0NzY3NjMyFxYXFRQGBwYjIicHFzYzMhYX\
Fh0BBgcGIyImNTQ3MzIWFRQGFQYHFgEzESMB3j5KDRpJRjwCBgoEIhoeLhwcLh4aIgYUDBkPJyUx\
PRIkUi8xMg0CMyEFRAUaVScjXlU3CFpIHy00PyIiPzRCZh4oCDdWXUxyRAUhMwIPMDX+TXt7/iB4\
Si0tbEkFDhsKYicrH/4EBAD+ER8rJ2ILKhcdCRt7QjE2YhoQKAMNBB4rGTIUC0QZDU80UxJObxwN\
F0tKFz4sOUMSUzRQTjwyGSseBA4EJhAcA978AAAAA/+6/aUCwwD/ACsANwBDAAA3NDYzMhYXFhUU\
BgcOAQc+ATc+ATc2NTQmJy4BIyIGBz4BMzIWFRQHBiMiJgUiJjU0NjMyFhUUBiciJjU0NjMyFhUU\
BhOLZ1VrKy9CVWjVkXevSDEsEw4RHR80MD9iERcjHC49JyExM0UCghYdGhQVHhoaFxscFRQcGx1i\
gDQ5PnJ/sE9iVQggVUgxVFA7akdQIyQdTE0dFEEvMiAeUYocFxYcHRUWHfIeGRUaGxQZHgAAAAIA\
AP8GAXIA+gADAAcAADczEyMDMxMj3JQCltyUApb6/gwB9P4MAAAEAAD+CgIfA6oACQAgAGIAbQAA\
JRYXPgE1NCYjIgMCJw4BFRQXLgE1NDY3JicOAQceATMyFx4BHwEdARQjIiY1NDYzMhYVFAYHFjMy\
NjU0LwEGIyImNTQ3PgE3PgI3JjU0NjceARUUBgceARc2MzIXFhUUBwYDBhUUFz4BNTQnBgFJEwZN\
R1ZCDg0YASw5HyAqTDsFCXFVAQVtggMiAwYCAno2UzMoJTUxJxUiIywBDQkVjZkuDkweBSMnEg5Z\
QC8ZSWECCAQSCFw5MmM2ZAMGN14pX3XEWxJPMzZW/uABCxAJNCcpJhJBKThOED5aWnlTcX4aIEAX\
FxsHf0gxJDM3JCIoAQwzNQ8JjQGSimpRHFAYBCAhDcIHbn8TM2JbbYdMEW4kAkM2YncwGwNWHiI5\
JCV7M0YmJgACAAD+YwJCAZoAYwBnAAABMjY1NCcmIyIHDgEHJicmJxEjETMRNjc2Nx4DFxYzMjY1\
NCcmIyIHFhcUFhUUBisBJjU0NzY3NjMyFxYXFRQGBwYjIicHFzYzMhYXFh0BBgcGIyImNTQ3MzIW\
JyUxPRIkUi8xMg0CMyEFRAUaVScjXlU3CFpIHy00PyIiPzRCZh4oCDdWXUxyRAUhMwIPMDX+TXt7\
/iB4Si0tbEkFDhsKYicrH/4EBAD+ER8rJ2ILKhcdCRt7QjE2YhoQKAMNBB4rGTIUC0QZDU80UxJO\
bxwNF0tKFz4sOUMSUzRQTjwyGSseBA4EJhAcA978AAAAA/+6/aUCwwD/ACYAMQA9AAA3NDYzMhcW\
FRQHDgEHNjc2NzY1NCcuASMiBgc+ATMyFhUUBwYjIiYFIiY1NDYyFhUUBiciJjU0NjMyFhUUBhOM\
FRQGFQYHFgEzESMBfjI7ChU6ODACDAQdExglFhYlGBMdBBEKEwwgHScxDhxDJScoCgIqGgQ2BBVE\
IxhJRi0GSDoYJSsxGxs0KDVSGCAGLUZJPVs2BBoqAgwmK/6jYmL+gGA7JCRXOwUdC1IcIhn+agMz\
/nQZIhxSCCISFwgWYjUrKE4VDSACCwMYIhQoEAk1FQtAK0EOPloWChI8OxMyIy41D0ErQD8wKBQj\
GAMLAx8NFgMY/M0AAAAAA//I/h4CNgDMACYALwA7AAA3NDYzMhcWFRQHDgEHNjc2NzY1NCcuASMi\
Bgc+ATMyFhUUBwYjIiYFIiY0NjIWFAYnIiY1NDYzMhYVFAYPcFKCPCN4Q8ZpwF5HHgktGC0gMFIK\
ZqNLLJdU9oTwdVskCzgeOSg8Zg0XGxwuRychLThGAoIWHRkqHhoaFxsaFxQcGylgdm1Bb/aISm4H\
QH1erj0xfkEhGFJEHRBLLzIgHmeSHBcWHB0VFh3yHhkWGRsUGR4AAAAAAgAA/wYBcgD6AAMABwAA\
NzMTIwMzEyPclAKW3JQClvr+DAH0/gwAAAQAAP4KAh8DqgAJACAAYgBtAAAlFhc+ATU0JiMiAwIn\
DgEVFBcuATU0NjcmJw4BBx4BMzIXHgEfAR0BFCMiJjU0NjMyFhUUBgcWMzI2NTQvAQYjIiY1NDc+\
EhYWJTkgGSUsOQICEhcUIhgVFRIWFRIRFhUhTV5XM1rGbDtXBjNkSowvKWYzGhRCNhcNPCYoGhhT\
dRckFhciGMIYFBEUFRATGQAAAAADAAAAAADIAPAACQATACkAADcGFRQWMzI2NTQnIgYVFBc2NTQm\
ATc+AjcmNTQ2Nx4BFRQGBx4BFzYzMhcWFRQHBgMGFRQXPgE1NCcGAUkTBk1HVkIODRgBLDkfICpM\
OwUJcVUBBW2CAyIDBgICejZTMyglNTEnFSIjLAENCRWNmS4OTB4FIycSDllALxlJYQIIBBIIXDky\
YzZkAwY3XilfdcRbEk8zNlb+4AELEAk0JykmEkEpOE4QPlpaeVNxfhogQBcXGwd/SDEkMzckIigB\
DDM1DwmNAZKKalEcUBgEICENwgdufxMzYltth0wRbiQCQzZidzAbA1YeIjkkJXszRiYmAAIAAP5j\
AkIBmgBjAGcAAAEyNjU0JyYjIgcOAQcmJyYnESMRMxE2NzY3HgMXFjMyNjU0JyYjIgcWFxQWFRQG\
KwEmNTQ3Njc2MzIXFhcVFAYHBiMiJwcXNjMyFhcWHQEGBwYjIiY1NDczMhYVFAYVBgcWATMRIwF+\
MjsKFTo4MAIMBB0TGCUWFiUYEx0EEQoTDCAdJzEOHEMlJygKAioaBDYEFUQjGElGLQZIOhglKzEb\
GzQoNVIYIAYtRkk9WzYEGioCDCYr/qNiYv6AYDskJFc7BR0LUhwiGf5qAzP+dBkiHFIIIhIXCBZi\
NSsoThUNIAILAxgiFCgQCTUVC0ArQQ4+WhYKEjw7EzIjLjUPQStAPzAoFCMYAwsDHw0WAxj8zQAA\
AAAD/8j+HgI2AMwAJgAvADsAADc0NjMyFxYVFAcOAQc2NzY3NjU0Jy4BIyIGBz4BMzIWFRQHBiMi\
JgUiJjQ2MhYUBiciJjU0NjMyFhUUBg9wUoI8I3hDxmnAXkceCS0YLSAwUgoSFhYlOSAZJSw5AgIS\
ByImNTQ2Ny4BNTQ2MzIWFRQHFhUUBlAjGxARFAIOEyAjEzAlNSMiEQwoHiQ2PCg0dxQdFB4bERaG\
EQ4XGQshDxTcKB4XGgsPExAaIiAcIxAgGyAmAAAAAgAA/wYBrgD6AAsAFAAAMxQWMzI2NTQmIyIG\
BzQ2MhYUBiImiiojIisnJiUoin20fX20fWJ4eWFldXZhZ5CR0pGSAAABAAD/BgEiAPoACQAAMTcz\
ERcVIzU3EWR9QfBB+v4+HhQUHgEsAAAAAQAA/wYBjwD6ADwAADcyFRQHDgMHNjMyFjMyNz4CMw4C\
BwYHBiMiJiMiBiMiNTQnPgU1NCciBzIWFRQGIyI1ND4Bx8gFDTZAbzYTIBtkHBgeBRAMAQEFBQEH\
EBopGnQVH1YCBwECLD5HPChTThocKTceTDxY+n4aDiEuHUQtDCMOAw0LBRYWAykOGCcmEAECIUU4\
PDI4GGIBNSUeHylnKDkZAAABAAD/BgF1APoAOQAANzIWFRQGIyImNTQ3NjMyFxYVFAYHHgEVFAcG\
IyImJyY0NjMyFhUUBiMWMzI2NTQmJyY0Nz4BNCYjImYbIichGzIfM1lGJkRGPT5RSyRNJ1cYIzIg\
FxQiGBUVEhYVEhEWFSFNXlczWsZsO1cGM2RKjC8pZjMaFEI2Fw08JigaGFN1FyQWFyIYwhgUERQV\
EBMZAAAAAAIAAP8GAa4A+gALABQAADMUFjMyNjU0JiMiBgc0NjIWFAYiJooqIyIrJyYlKIp9tH19\
tH1ieHlhZXV2YWeQkdKRkgAAAQAA/wYBIgD6AAkAADE3MxEXFSM1NxFkfUHwQfr+Ph4UFB4BLAAA\
AAEAAP8GAY8A+gA8AAA3MhUUBw4DBzYzMhYzMjc+AjMOAgcGBwYjIiYjIgYjIjU0Jz4FNTQnIgcy\
FhUUBiMiNTQ+AcfIBQ02QG82EyAbZBwYHgUQDAEBBQUBBxAaKRp0FR9WAgcBAiw+RzwoU04aHCk3\
Hkw8WPp+Gg4hLh1ELQwjDgMNCwUWFgMpDhgnJhABAiFFODwyOBhiATUlHh8pZyg5GQAAAQAA/wYB\
dQD6ADkAADcyFhUUBiMiJjU0NzYzMhcWFRQGBx4BFRQHBiMiJicmNDYzMhYVFAYjFjMyNjU0Jicm\
IiolGww/JCtILhYWL0spJDyqHBcbIysjLxoqEyJILkQLC0UtQycTFhQdTC4hGxkeKTEnJjoIBCIE\
CTdQMAAAAQAA/wYBkAD6ABEAAAUXIzc1IzU2NTMBMz8BETMVIwFFMsgy4ZOj/vuwAWNLS9EpKTEo\
8oD+jpaR/tkoAAAAAAEAAP8HAX4A+gAvAAAXNjMyFhUUBiMWMzI3PgE1NCcmIyIHEyEOASsBBzYz\
MhceARUUBw4CIyInLgE1NBIcIRsqIBwaJDEcEwkeHChOSAoBYgs1JdUGOUJTMSErQxZAKyU8KxAe\
XyAgFxwgIR4UHyA5HBo1ASIkOnkeHxVBJU8vEBACFAkyEiMAAAAAAgAA/wYBgQD6AAkALAAAFzI2\
NTQmIyIHFhMWFRQGIyImNTQ2MyYjIgYVPgIzMhYVFAYjIiYnPgEzMhbIKS0qKCwwB90bIxgeIhsQ\
Fjc1LxUYLR5MT3FIYWYBAWxbMD/SRSwiMCWeAZ8aJhkoHhsMHiN4XwsKCUA2RFmCeGmREgABAAD/\
BgGQAPsAKAAANyIOAwc3PggzMhYzMjY3DgQVIzY3Njc2NwYjIiZhFBoUCREFCgEMAgsFCwkNEAkv\
dSMaOxEbRRoeCIIBCBFoHi0RHiVgoQUOCRsGdAELAgkBBgEDASYXDkOnQVxCK0UbNocnOQooAAMA\
AP8GAYQA+gAOABwANAAAFw4BFRQWMzI2NTQuAzc+ATU0JiIGFRQeAwcuATU0NjcyFhUUBgceARUU\
BiMiJjU0Npo2LFgsKj8PIB0xPjMjRFIzChwSMXAxKWZKS2UqMDoydU1MdjkqGSQbHTApHw4XEg0T\
WhoiHB0wKCAPFxMKFT8YPDUzTQFGMic0Fxo6NTdKSDAkNQAAAgAA/wYBgQD6AAkALAAANyIGFRQW\
MzI3JgMmNTQ2MzIWFRQGIxYzMjY1DgIjIiY1NDYzMhYXDgEjIia5KS0qKCwwB90bIxgeIhsQFjc1\
LxUYLR5MT3FIYWYBAWxbMD/SRSwiMCWe/mEaJhkoHhsMHiN4XwsKCUA2RFmCeGmREgABAAn/CgGZ\
APkAMAAAJTAXNjU0JiMOARUUFxYzMjc2NxQeARUOAQciJyYnNCY1NDcyFhcWFRQGIyImNT4BMwEv\
EgQ8HzJBJyEwKygcKgkIG1VWTzs7BAHbJEARIiQcICkCIBqkAwUIFCICZWuOMyoiGFgBBAMBVVAB\
OTlmAisC5gIeFCckJTkuHBYmAAIACf6iAZkBXgA4AD8AACUwFzY1NCYjIgcRFjMyNzY3FB4BFQ4B\
ByMVIzUmJyYnNCY1NDc1MxUyNjMyFhcWFRQGIyImNT4BMwMRBhUUFxYBLxIEPB8DEAwMKygcKgkI\
G1FVASM9LjsEAasjAwcDJEARIiQcICkCIBp6PScKpAMFCBQiBP5LBCIYWAEEAwFUUQFoawktOWYC\
KwLLGWlmAR4UJyQlOS4cFib+lwGWLpGOMw0AAAEAAP8GAfQA+gALAAA1MzUzFTMVIxUjNSPXRtfX\
Rtcj19dG19cAAAABABT+BgDjAgAAEwAAExYHBicmAjU0Ejc2FxYHBgIVFBLcBw0JBUlra0kJCwYG\
PEZH/hYIBQMGVwEgfXwBIlYLBwYISf7niIb+5QAAAQAK/gIA3AH9ABMAABM2EjU0AicmNzYXFhIV\
FAIHBicmFDtHRjwJDAoHSWtrSQgLBv4WSQEbhogBGUkLBAQJVv7efH3+4FcJCQQAAAQAJP9WAkwA\
qgALAA8AEwAeAAAFNCYjIgYVFBYzMjY3MxEjATMRIyQUBiMiJjU0NjMyAahUPCA0Vz0hL3IyMv4K\
MjIB9XtmZXx5aGYgNU4nHzVLI+r+rAFU/qzmeEZJOT9DAAACAAD/JAISANwAAwAPAAA3FSE1JTMV\
ITUzESM1IRUjHgHW/gweAdYeHv4qHkGCgps3N/5INzcAAAIAAP9/AcIAgQALABMAAAU0JiMiBhUU\
FjMyPgEUBiImNDYyAVFaNiA0XTchL3F9yH19yB40TycfNEwjdGxLS2xLAAAAAgAA/2wBSACUAA0A\
GwAAJSYjIgYVFBcWMzI2NTQ3FhUUBiMiJyY1NDYzMgEkDSU8lwYLJjyXEA9+SE8kD35IT0QXYSsK\
NDc+ATQmIyJmGyInIRsyHzNZRiZERj0+UUskTSdXGCMyICIqJRsMPyQrSC4WFi9LKSQ8qhwXGyMr\
Iy8aKhMiSC5ECwtFLUMnExYUHUwuIRsZHikxJyY6CAQiBAk3UDAAAAEAAP8GAZAA+gARAAAFFyM3\
NSM1NjUzATM/AREzFSMBRTLIMuGTo/77sAFjS0vRKSkxKPKA/o6Wkf7ZKAAAAAABAAD/BwF+APoA\
LwAAFzYzMhYVFAYjFjMyNz4BNTQnJiMiBxMhDgErAQc2MzIXHgEVFAcOAiMiJy4BNTQSHCEbKiAc\
GiQxHBMJHhwoTkgKAWILNSXVBjlCUzEhK0MWQCslPCsQHl8gIBccICEeFB8gORwaNQEiJDp5Hh8V\
QSVPLxAQAhQJMhIjAAAAAAIAAP8GAYEA+gAJACwAABcyNjU0JiMiBxYTFhUUBiMiJjU0NjMmIyIG\
FT4CMzIWFRQGIyImJz4BMzIWyCktKigsMAfdGyMYHiIbEBY3NS8VGC0eTE9xSGFmAQFsWzA/0kUs\
IjAlngGfGiYZKB4bDB4jeF8LCglANkRZgnhpkRIAAQAA/wYBkAD7ACgAADciDgMHNz4IMzIWMzI2\
Nw4EFSM2NzY3NjcGIyImYRQaFAkRBQoBDAILBQsJDRAJL3UjGjsRG0UaHgiCAQgRaB4tER4lYKEF\
DgkbBnQBCwIJAQYBAwEmFw5Dp0FcQitFGzaHJzkKKAADAAD/BgGEAPoADgAcADQAABcOARUUFjMy\
NjU0LgM3PgE1NCYiBhUUHgMHLgE1NDY3MhYVFAYHHgEVFAYjIiY1NDaaNixYLCo/DyAdMT4zI0RS\
MwocEjFwMSlmSktlKjA6MnVNTHY5KhkkGx0wKR8OFxINE1oaIhwdMCggDxcTChU/GDw1M00BRjIn\
NBcaOjU3SkgwJDUAAAIAAP8GAYEA+gAJACwAADciBhUUFjMyNyYDJjU0NjMyFhUUBiMWMzI2NQ4C\
IyImNTQ2MzIWFw4BIyImuSktKigsMAfdGyMYHiIbEBY3NS8VGC0eTE9xSGFmAQFsWzA/0kUsIjAl\
nv5hGiYZKB4bDB4jeF8LCglANkRZgnhpkRIAAQAJ/woBmQD5ADAAACUwFzY1NCYjDgEVFBcWMzI3\
NjcUHgEVDgEHIicmJzQmNTQ3MhYXFhUUBiMiJjU+ATMBLxIEPB8yQSchMCsoHCoJCBtVVk87OwQB\
2yRAESIkHCApAiAapAMFCBQiAmVrjjMqIhhYAQQDAVVQATk5ZgIrAuYCHhQnJCU5LhwWJgACAAn+\
ogGZAV4AOAA/AAAlMBc2NTQmIyIHERYzMjc2NxQeARUOAQcjFSM1JicmJzQmNTQ3NTMVMjYzMhYX\
FhUUBiMiJjU+ATMDEQYVFBcWAS8SBDwfAxAMDCsoHCoJCBtRVQEjPS47BAGrIwMHAyRAESIkHCAp\
AiAaej0nCqQDBQgUIgT+SwQiGFgBBAMBVFEBaGsJLTlmAisCyxlpZgEeFCckJTkuHBYm/pcBli6R\
jjMNAAABAAD/BgH0APoACwAANTM1MxUzFSMVIzUj10bX10bXI9fXRtfXAAAAAQAU/gYA4wIAABMA\
ABMWBwYnJgI1NBI3NhcWBwYCFRQS3AcNCQVJa2tJCQsGBjxGR/4WCAUDBlcBIH18ASJWCwcGCEn+\
54iG/uUAAAEACv4CANwB/QATAAATNhI1NAInJjc2FxYSFRQCBwYnJhQ7R0Y8CQwKB0lra0kICwb+\
FkkBG4aIARlJCwQECVb+3nx9/uBXCQkEAAAEAAD/TAIRAKoAAwAHABsAJQAAJTMRIwEzESM3BhUU\
Fx4BFzMyNzY0Jy4BJzAjIgQUBiMiJjU0NjIB6Sgo/hcnJ5cFAwpVLg0zEwUDCVYuDTYBQXlnZnp5\
CRdhKwkXHh1DZ0MeHUNnAAAAAAEAAP95AUAAhwALAAAlFAYjIiY1NDYzMhYBQHlZMjx6WDI8KEZp\
OCdFajgAAf/+/28BTACRAAsAACc3FzcXBxcHJwcnNwIbjIwbhoYci4schnEgdnUgcHAhdXUhcAAA\
AAUAAP9qASwAlgAFAAsAEQAXAB8AABcHFjMyNy8BBhUUFz8BJiMiBx8BNjU0JwY0NjIWFAYilkcd\
KikfXUcdHVxIHykqHVxHHR3yWHxYWHwSSB0dWkkfKSodWEgdHVpIHykqHYV8WFh8WAAAAAEAAP8G\
AjAA+gADAAAVATMBAbh4/kf6AfT+DAABAAD/dAFKAIwAAwAAMTcXB6WlpYyMjAABAAD/dAFKAIwA\
AgAAFRsBpaWMARj+6AABAAD/zgBkADIABwAAFiImNDYyFhRHKh0dKh0yHSodHSoAAAABAAD87wE7\
AAAADwAAFTUzHgQVFAc2NTQmJx4GP1FQNy4SkXDv7zVwZWyJSWBpQUmP3yoAAQAAAAABOwMRAA8A\
ADE1Mz4BNTQnFhUUDgMHHnCSEy43UFE/Bu8f4ZNHSGdeSIptZ3E1AAIAAP1EATwAAAAWACMAABkB\
Mx4EFRQHFhUUBzY1NC4DIzUeAxc2NTQuAx4JQlBONBITHgUoPklAFglETVYVASk+SUD+qQFXJFBK\
T2IzKi0qKjU6HR03ZEUzGaskVENdKQsJOGRFNBgAAgAA//8BPAK8ABYAIwAAFREzMj4DNTQnFhUU\
BxYVFA4DBzUyPgM1NCcOAx4WQEk+KAUeExI0TlBCCRZAST4pARVWTUQBAVcZM0VkNx0dOjUqKi0q\
M2JPSlAkqxg0RWQ4CQopXUNTAAADAAD9KgE8AJEAGwArADsAABkBMx4GFRQHFhUUBxYVFAc2NTQu\
AiM1HgMXNDY1NCcmJyYjIiceAxc0NjU0JyYnJiMiHgYnMzs4LhwSEhITHgU9V1UcCURNVhUBckZA\
BwUBAQlETVYVAXJGQAcFAf6QAgEbOTM3Oj1IJSwrJy0sKykrNjkZIUR3SCmpJFRBXSkEDQOIXzsI\
AaskU0JdKQQNA4hfOwgBAAADAAD/VgE8Ar0AGQAmADMAABEzMj4DNTQnFhUUBxYUBxYVFA4DByM3\
Mj4DNTQnDgMnMj4DNTQnDgMeFkBJPigFHhMSEhI0TlBCCR4eFkBJPikBFVZNRAkWQEk+KQEVVk1E\
AVcZM0VkNx0dOjUqKixVKi0qM2JPSlAkqhk0RWQ4CgopXUNUhhk0RWQ4CgopXUNUAAAABAAA/UIB\
PAFUABwAKQA2AEMAABkBMx4EFRQHFhQHFhQHFhUUBzY1NC4DIzUeAxc2NTQuAyceAxc2NTQuAyce\
Axc2NTQuAx4JQlBONBISEhISEx4FKD5JQBYJRE1WFQEpPklAFglETVYVASk+SUAWCURNVhUBKT5J\
QP6oAqwkUEpPYjMqLSpVLCpVLCoqNTodHTdkRTMZqyRUQ10pCwk4ZEU0GKskVENdKQsJOGRFNBir\
JFRDXSkLCThkRTQYAAAABAAA/o4BPAKgABwAKQA2AEMAABkBMzI+AzU0JxYVFAcWFAcWFAcWFRQO\
Awc1Mj4DNTQnDgMnMj4DNTQnDgMnMj4DNTQnDgMeFkBJPigFHhMSEhISEjROUEIJFkBJPikBFVZN\
RAkWQEk+KQEVVk1ECRZAST4pARVWTUT+jgKsGTNFZDcdHTo1KiosVSosVSotKjNiT0pQJKoZNEVk\
OAoKKV1DVIYZNEVkOAoKKV1DVIYZNEVkOAoKKV1DVAAFAAD9VQE8AhIAIAAtADoARwBUAAAZATMe\
BRUUBxYUBxYUBxYUBxYVFAc2NTQuAyM1HgMXNjU0LgMnHgMXNjU0LgMnHgMXNjU0LgMnHgMXNjU0\
LgMeBzI/RjolEhISEhISEhMeBSg+SUAWCURNVhUBKT5JQBYJRE1WFQEpPklAFglETVYVASk+SUAW\
CURNVhUBKT5JQP67A1cfQzpGQVQrKi0qVSwqVSwqVSwqKjU6HR03ZEUzGaskVENdKQsJOGRFNBir\
JFRDXSkLCThkRTQYqyRUQ10pCwk4ZEU0GKskVENdKQoKOGRFNBgAAAUAAP28ATwCeQAfACwAOQBG\
AFMAABkBMzI+AzU0JxYVFAcWFAcWFAcWFAcWFRQOAwc1Mj4DNTQnDgMnMj4DNTQnDgMnMj4DNTQn\
DgMnMj4DNTQnDgMeFkBJPigFHhMSEhISEhISNE5QQgkWQEk+KQEVVk1ECRZAST4pARVWTUQJFkBJ\
PikBFVZNRAkWQEk+KQEVVk1E/bwDVxkzRWQ3HR06NSoqLFUqLFUqLFUqLSozYk9KUCSqGTRFZDgK\
CildQ1SGGTRFZDgKCildQ1SGGTRFZDgKCildQ1SGGTRFZDgKCildQ1QAAAACAAD/ZADhAbAACgAW\
AAA3IgYdATY3NjU0JjcyFhUUBwYjETMRNmcUKyImKx0HIzlLUkQoI3omE7kPODsvGyYmMiNJTFIC\
TP68NAAAAgAA/oYAxQF6AAMADAAAFzc1BxEVNxEjNQcRNxyQkKkZrAFlLZYtAUnoNP3A4jMCQwEA\
AAIAAP6YAP8BaAADAB8AADcVNzUDIzUHNTc1BzU3NTMVNzUzFTcVBxU3FQcVIzUHU1paHjU1NTUe\
Wh01NTU1HVpGpxun/jejD1wPpw9aD6ifHKujD1wPpw9aD6ifHAAAAAEAFP+EAQsAegAeAAAXNSYn\
BzAVIzUzNycwIzUzFRYXNzA1MxUjBgcXMDMVwygMM0g5MzM5SCESNEg5IRM0OXw7Jg0zO0oyMkg5\
IhEzOUciETRIAAQAAP9qAWwBsAAOABwAKwA6AAA3DgEdATI3Njc2NTQnJiM3MhYVFAcGBwYjETMR\
NhcOAR0BMjc2NzY1NCcmIzcyFhUUBwYHDgEjETMRNk4RHg4eHwwEChARGR0rCRgrNS8fGdERHRAe\
HQsGCxAPFh8qCxkoFjcWHht9AR4QxikrNA0ZHhQVJjkhEiA5NEACRv7BMiYBHRHGKS8wExMcFhUm\
NiQWHD4vGyUCRv7BMgAAAgAy/2QBDQGwAAoAFgAANyIGFRQXFhc1NCYnMhcRMxEiJyY1NDarFyAu\
LhoqMzojIzpSTzl6JhswRUIDyxIeJjQBRP20UlBFIzIAAAT/9f9qAWwBsAAOAB0ALAA7AAA3IyIH\
BhUUFxYXFjM1NCYnMhcRMxEiJicmJyY1NDYXDgEdATI3Njc2NTQnJiM3MhYVFAcGBw4BIxEzETZX\
AREQCgQMHx4OHiswGR8WNxcrGAkr6REdEB4dCwYLEA8WHyoLGSgWNxYeG30VFB4ZDTQrKcYQHicy\
AT/9uiUbNDkgEiE5JgEdEcYpLzATExwWFSY2JBYcPi8bJQJG/sEyAAAAAAEAAP7AAKkBQAATAAAT\
MxU3FQcVNxUHFSM1BzU3NQc1N0QeR0dHRx5EREREAUCiDlwOfw5aD6iiDlwOfw5aDwADAAD+mAE6\
AWgAIwAnACsAADc1MxU3FQcVNxUHFSM1BxUjNQ8BIzUHNTc1BzU3NTMVNzUzFQM1BxU3FTc16R4z\
MzMzHj0ePAEeMzMzMx49Hh49Wz3AqJ4PXA+fD1oPtaoSrKQQqJ4PXA+fD1oPtaoSrKT+/Z4Rn7ie\
zqr+ogFe/qLzDA4LCyJHBCMJHAsiRwQmeEVEOD9HAAACAAD/JAIcANwAAwAPAAA3FSE1JTMVITUz\
ESM1IRUjGQHq/f0ZAeoZGf4WGUaMjJYyMv5IMjIAAAIAAP9/AcAAgQATAB0AADcGFRQXHgEXMzI3\
NjQnLgEnMCMiBBQGIyImNTQ2Mm8FAwpVLg0zEwUDCVYuDTYBQXlnZnp5zj8MDgsLIkcEIwkcCyJH\
EZ8AAf/9AAABPwD0ABgAADcGIyImNTQ/ATYvASY1NDYzMjEXBRYVFAcSAgMHCQbPDg7NCAsHAQIB\
BCZ4RUQ4P0cAAgAA/2wBSACUAA0AGwAAJSYjIgYVFBcWMzI2NTQ3FhUUBiMiJyY1NDYzMgEkDSU8\
lwYLJjyXEA9+SE8kD35IT0QXYSsKCRdhKwkXHh1DZ0MeHUNnAAAAAAEAAP90AUoAiwAOAAAVNDY3\
NjMyFhUUBwYjIiZdSB4RM0OlGBsxQSE+VBMHODJ1MAg5AAAB//7/bwFMAJEACwAAJzcXNxcHFwcn\
Byc3AhuMjBuGhhyLixyGcSB2dSBwcCF1dSFwAAAABQAA/2oBLACWAAUACwARABcAHwAAFwcWMzI3\
LwEGFRQXPwEmIyIHHwE2NTQnBjQ2MhYUBiKWRx0qKR9dRx0dXEgfKSodXEcdHfJYfFhYfBJIHR1a\
SR8pKh1YSB0dWkgfKSodhXxYWHxYAAAAAQAA/wYCMAD6AAMAABUBMwEBuHj+R/oB9P4MAAEAAP/O\
AGQAMgAHAAAWIiY0NjIWFEcqHR0qHTIdKh0dKgAAAAIAMv9kAQ0BsAAKABYAADciBh0BNjc2NTQm\
NzIWFRQHBiMRMxE2lBUqHCwuIAciOU9SOiMjeh4SywNCPzYbJiYyI0VQUgJM/rw0AAACAAD+hgDF\
AXoAAwAMAAAXNzUHERU3ESM1BxE3HJCQqRmsAWUtli0BSeg0/cDiMwJDAQAAAgAA/o8BDAF1AAMA\
HwAANxU3NQMjNQc1NzUHNTc1MxU3NTMVNxUHFTcVBxUjNQdSZmYZOTk5ORlmGDw8PDwYZk20HLX+\
Ja8RVQ63EFcOsqoat68PUxK0D1MPsaodAAAAAQAU/4QBCwB6AB4AABc1JicHMBUjNTM3JzAjNTMV\
Fhc3MDUzFSMGBxcwMxXDKAwzSDkzMzlIIRI0SDkhEzQ5fDsmDTM7SjIySDkiETM5RyIRNEgABAAA\
/2oBbAGwABAAHgAtADwAADcOAR0BMjc2NzY3NjU0JyYjNzIWFRQHBgcGIxEzETYXDgEdATI3Njc2\
NTQnJiM3MhYVFAcGBw4BIxEzETZOER4LGwQCHwwEChARGR0rCRgrNS8fGdERHQ0hHQsGCxAPFh8q\
CxkoFjcWHht9AR4QyyYFAys0DRkeFBUmOSESIDk0QAJG/sEyJgEdEcsuLzATExwWFSY2JBYcPi8b\
JQJG/sEyAAAAAAIAMv9kAQ0BsAAKABYAADciBhUUFxYXNTQmJzIXETMRIicmNTQ2qxcgLi4aKjM6\
IyM6Uk85eiYbMEVCA8sSHiY0AUT9tFJQRSMyAAAB//0AAAE/APQAGAAANwYjIiY1ND8BNi8BJjU0\
NjMyMRcFFhUUBxICAwcJBs8ODs0ICwcBAgEfDg4BARAICgNJBwZPAwsKEgFrBg4NBQAAAAEAAAAA\
ARgBNQAFAAAxGwEjJweMjEFYWgE1/svGxgAAAgAAAAACWAFKAA4AGQAAMTQ2MzIeAhUjLgEiBgch\
IiY0NjMyFhUUBrN5OWtVMwoLpuKmCwEhFyUlFxkjI5iyLFGATW6Ghm4kMCQkGBkjAAABAAAAAAC2\
AS0AFwAAEzIWFxYVFAcOASMnJjU0NjU0Iy4BNTQ2VhsbEBoyGUQQBgFHFBsoLQEtDBEdMD08HS0D\
AQIIaxMPASYcHjEAAQAA/wYAggD6AAMAADUzEyOAAoL6/gwAAQAAAAAAggD6AAMAADUzFSOCgvr6\
AAAAAQAA/4MBLAAAAAMAADEhFSEBLP7UfQAAAQAAAAABLAB9AAMAADUhFSEBLP7UfX0AAQAA/n4A\
6wGHABMAABMXBxcmIyIGFRQXJjU0NjMyFyc3Kb1nbDI0HyY4eDQlIiKHZAGH5dnPLiQdNTRLTSMt\
Fby0AAABAAD/DQEAAMAAFgAANw4CIyImNTQ2MhYVFAcyNjc2MhcDJ6sDGRoTKzcmOCkXIjMhAhUD\
ljA8AQcEKSgfIB4ZHRshLAIC/m8QAAAAAQAA/gwBSADAACQAABcGIyImNTQ2MzIWFRQHMj8BBiMi\
JjU0NjMyFhUUBzI3NjIXAyerKCErNycbHCkXQQs8NhgrNycbHCkXSC4CFQPFLcQMKCggIB8ZHRsi\
ygwpKB8gHhkdG00CAv1uDAAAAQAA/gwBjwHAADYAADcGIyImNTQ2MzIWFRQHMj8BIg4BIyImNTQ2\
Hw4OAQEQCAoDSQcGTwMLChIBawYODQUAAAABAAAAAABQAFAACQAANTQ2MhYUBiMiJhciFxcREBgo\
ERcXIhcYAAAAAQAAAAABQAAoAAMAADE1IRUBQCgoAAAAAQAAAAAAZAEYAAMAADMDMwMoKGQoARj+\
6AAAAAEAAAAAARgBNQAFAAAxGwEjJweMjEFYWgE1/svGxgAAAgAAAAACWAFKAA4AGQAAMTQ2MzIe\
AhUjLgEiBgchIiY0NjMyFhUUBrN5OWtVMw8LouCiCwEcFyUlFxkjI5iyLFGATW6Ghm4kMCQkGBkj\
AAABAAAAAAC2AS0AFwAAEzIWFxYVFAcOASMnJjU0NjU0Iy4BNTQ2VhsbEBoyGUQQBgFHFBsoLQEt\
DBEdMD08HS0DAQIIaxMPASYcHjEAAQAA/wYAggD6AAMAADUzESOCgvr+DAAAAQAAAAAAggD6AAMA\
ADUzFSOCgvr6AAAAAQAA/4MBLAAAAAMAADEhFSEBLP7UfQAAAQAAAAABLAB9AAMAADUhFSEBLP7U\
fX0AAQAA/n4A6wGHABMAABMXBxcmIyIGFRQXJjU0NjMyFyc3Kb1nbDI0HyY4eDQlIiKHZAGH5dnP\
LiQdNTRLTSMtFby0AAABAAD/DQEAAMAAFgAANw4CIyImNTQ2MhYVFAcyNjc2MhcDJ6sDGRoTKzcm\
OCkXIjMhAhUDljA8AQcEKSgfIB4ZHRshLAIC/m8QAAAAAQAA/gwBSADAACQAABcGIyImNTQ2MzIW\
FRQHMj8BBiMiJjU0NjMyFhUUBzI3NjIXAyerKCErNycbHCkXQQs8NhgrNycbHCkXSC4CFQPFLcQM\
KCggIB8ZHRsiygwpKB8gHhkdG00CAv1uDAAAAQAA/gwBjwHAADYAADcGIyImNTQ2MzIWFRQHMj8B\
Ig4BIyImNTQ2MzIWFRQHMjc2MhcBJxMGIyImNTQ2MzIWFRQHMjf2KB8rNycbHCkXPws6ASAcEys3\
JxscKRdILgEWA/70LVUoISs3JxscKRdBCzwMKCggIB8ZHRsiywkEKSgfIB4ZHRtNAgL8bgwBJAwo\
KCAgHxkdGyIAAAAAAQAA/QwB2gHAAEUAABMGIyImNTQ2MzIWFRQHMj8BBiMiJjU0NjMyFhUUBzI/\
AQYjIiY1NDYzMhYVFAcyPwEiDgEjIiY1NDYyFhUUBzI3NjIXASerKCErNycbHCkXQQs6KCErNycb\
HCkXQQs6KB8rNycbHCkXPws6ASAcEys3JjgpF0guAhUD/qkt/jwMKCggIB8ZHRsiygwoKCAgHxkd\
GyLKDCgoICAfGR0bIssJBCkoHyAeGR0bTQIC+24MAAAAAQAA/QwCGQKuAFYAACUGIyImNTQ2MzIW\
FRQHMj8BBiMiJjU0NjMyFhUUBzI/ASIOASMiJjU0NjMyFhUUBzI3NjIXAScTBiMiJjU0NjMyFhUU\
BzI/AQYjIiY1NDYzMhYVFAcyNwE/KCErNycbHCkXQQs2KB8rNycbHCkXPws0ASAcEys3JxscKRdI\
LgEWA/5qLVUoISs3JxscKRdBCzooISs3JxscKRdBCzQMKCggIB8ZHRsixAwoKCAgHxkdGyLHCQQp\
KB8gHhkdG00CAvqADAEkDCgoICAfGR0bIsgMKCggIB8ZHRsiAAEAAP8aA1IA5gALAAA1MxUhNTMR\
IzUhFSMZAyAZGfzgGeZ9ff40fX0AAAAAA//w/wYCJgD6AAcADwATAAA2IiY0NjIWFAAiJjQ2MhYU\
BQEzAVAyIyMyIwGIMiMjMiP90gG4fv5HSyMyIyMy/s8jMiMjMloB9P4MAAT/4f8GAwcA+gAHAA8A\
EwAXAAA2IiY0NjIWFAAiJjQ2MhYUBQEzATMBMwFBMiMjMiMCdzIjIzIj/OMBuHv+R3kBuHv+R0sj\
MiMjMv7PIzIjIzJaAfT+DAH0/gwAAv+0/4gBfAEYABkASAAANxYzMjY3PgU1NCYnJiMiBgcGFRQe\
ARciJwczMhQrASI0OwETPgI1NC4CIyIOAwcGJjc2NzYzMhYXPgEzMhYVFAbFAwQSMg4CAwMDAQEH\
CAMDEzQLDwQHCBYZLTQLC+ELC0toAQMCAQIFAwgMDwsZCgUbBTEPGCQjJAcdJiMeLWsoATUkBQsM\
DAwMBhAXAwEzHCYlDBQNKiB6Hh4BHQIIDgYDBQUCBxQSLBAIDwlYEBkTGh4PNDBHbQAB/9v/9gG+\
ARgAVwAANwYHBisBIj8BNiYjIgYHBiY3PgMzMhc2MzIXPgEzMh4DFRQPAQYVFDMyNz4FNzYWBw4C\
IyImNTQ2PwI0IyIPAQYHJwYmPwE2NTQmIyIHUAcIBAQ1DQ1CBAYIDRYkBRUEFBAiHxI3CyQkLQkL\
KRMKEg8LBwUvBAgCAwULBwwDDQEGFQYSFy0fFRkCAzQBFRsIQQgPJg0IBEMBDAkbCBURAwEapw0P\
GjkIDAklGjASKCgoEBgGCw8TCg0NfQsJDgIDCQYPBRIBCQ0LHx8aFRQGDQeIBg4UqxYBAQEPCKsD\
AwYIFAAB/37/YAFeAbgASAAAByImNTQ2MzIWFRQHBhUUMzI+BzcjIiY1ND4DOwE+ATMyFhUUBiMi\
JjU0NzY0IyIOBwczMhYUBisBDgEyIDAXExIXEgoZCxAPCw0KDg0UCjUJCgEDBAYDQRRpNCAwFxMS\
FxIKGQcMCgcIBQYDBgE2CQoKCT8hdqAmIBoiFA8OCwcNDgYREyUkPDdVJwwJAwUFBAJLXyYgGiIU\
Dw4LBhwFCwoUDRoNHgYMEAzFwQAAAAEAAAAAANoBGAA0AAAzIiY1NDYzMhYVFAcWMzI2NTQuAicm\
NTQ2MzIWFRQGIyIuATU0NyYjIgYVFB4CFx4BFRRQHjISDA4XDAYYFiEJCxgGPDctIjYWEAgQCwUQ\
Dg8ZERIeBRsXKxsQFg0LGAwSFhILDwcNBCYqIy0kGBAYCQ8KCAgUEQ0JEwwRAxIfFVoAAAH/5P//\
AOcBEAA/AAAnBi4BPwEuASMqASMiDgEHBicmNz4BNxYzMj4BMzIXFhQPAQ4BFRQeARcWNicuATU0\
NjMyFRQHBgciJiMuASMiCgYLAQWwCBcRBQwHBREUBQ8EAwgMCwEwIhkgEQcFCAsHngEBECwXCAwD\
AyQUDCYkERIDBQIXNAkSAwQIDQbBBAMbIQQNCwkSHjACAwMEAQERB6cDAwIFAQkLBA8JCAgUCxM3\
KhUJAQEDDQAF/7T/iAVLARgAGwA1ANkA8AELAAAlFjMyPgE3PgY1NCYnJiMiBgcOAhUUBRYzMjY3\
PgU1NCYnJiMiBgcGFRQeARciJwczMhQrASI0OwETPgI1NC4CIyIOAwcGJjc2NzYzMhYXPgEzMhc+\
ATMyFhc+ATMyFz4BMzIWFz4BMzIXPgEzMhYXPgEzMhYVFAYjIicHMzIUKwEiNDsBEz4CNTQmIyIG\
BxUUBiMiJwczMhQrASI0OwETPgI1NCYjIgYHFRQGIyInBzMyFCsBIjQ7ARM0PgM0NTQmIyIGBxUU\
BiUWMzI2Nz4ENTQmJyYjIgYHBhUUBRYzMjY3PgY1NCYnJiMiDgEHBhUUFgIKAwQMHx4JAgMCAgIB\
AQcIAwMTNAsFBwP+ywMEEjIOAgMDAwEBBwgDAxM0Cw8EBwgWGS00CwvhCwtLaAEDAgECBQMIDA8L\
GQoFGwUxDxgkIyQHHSYjLxMSIhsjJAcdJiMvExIiGyMkBx0mIy8TEiIbIyQHHSYjHi1rSRYZLTQL\
C+ELC0toAQMCBQYOFBRrSRYZLTQLC+ELC0toAQMCBQYOFBRrSRYZLTQLC+ELC0toAQIBAgUGDhQU\
awODAwQSMg4CBAMDAQcIAwMTNAsP/ssDBBIyDgIDAgICAQEHCAMDDCEeBw8JKAEYKhcECgkLCgoL\
BRAXAwEzHA0bGAsoBwE1JAULDAwMDAYQFwMBMxwmJQwUDSogeh4eAR0CCA4GAwUFAgcUEiwQCA8J\
WBAZExoeDzIcFhMaHg8yHBYTGh4PMhwWExoeDzQwR20geh4eAR0CCA4GBwgYIwFHbSB6Hh4BHQII\
DgYHCBgjAUdtIHoeHgEdAQMFBQYHAwcIGCMBR20oATUkBg0PDg8HEBcDATMcJiUoBwE1JAQKCQsK\
CgsFEBcDARglEiYlEhoAAAT/tP+IBAYBGAB9AJgAtADOAAAhIicHMzIUKwEiNDsBEz4CNTQmIyIG\
BxUUBiMiJwczMhQrASI0OwETND4DNDU0JiMiBgcVFAYjIicHMzIUKwEiNDsBEz4CNTQuAiMiDgMH\
BiY3Njc2MzIWFz4BMzIXPgEzMhYXPgEzMhc+ATMyFhc+ATMyFhUUBicWMzI2Nz4GNTQmJyYjIg4B\
BwYVFBYFFjMyPgE3PgY1NCYnJiMiBgcOAhUUBRYzMjY3PgU1NCYnJiMiBgcGFRQeAQNSFhktNAsL\
4QsLS2gBAwIFBg4UFGtJFhktNAsL4QsLS2gBAgECBQYOFBRrSRYZLTQLC+ELC0toAQMCAQIFAwgM\
DwsZCgUbBTEPGCQjJAcdJiMvExIiGyMkBx0mIy8TEiIbIyQHHSYjHi1rTAMEEjIOAgMCAgIBAQcI\
AwMMIR4HDwn+wgMEDB8eCQIDAgICAQEHCAMDEzQLBQcD/ssDBBIyDgIDAwMBAQcIAwMTNAsPBAcg\
eh4eAR0CCA4GBwgYIwFHbSB6Hh4BHQEDBQUGBwMHCBgjAUdtIHoeHgEdAggOBgMFBQIHFBIsEAgP\
CVgQGRMaHg8yHBYTGh4PMhwWExoeDzQwR20oATUkBAoJCwoKCwUQFwMBGCUSJiUSGgMBGCoXBAoJ\
CwoKCwUQFwMBMxwNGxgLKAcBNSQFCwwMDAwGEBcDATMcJiUMFA0AA/+0/4gCwQEYAFcAcQCNAAAz\
IicHMzIUKwEiNDsBEz4CNTQuAiMiDgMHBiY3Njc2MzIWFz4BMzIXPgEzMhYXPgEzMhYVFAYjIicH\
MzIUKwEiNDsBEzQ+AzQ1NCYjIgYHFRQGJxYzMjY3PgU1NCYnJiMiBgcGFRQeAQUWMzI+ATc+BjU0\
JicmIyIGBw4CFRTIFhktNAsL4QsLS2gBAwIBAgUDCAwPCxkKBRsFMQ8YJCMkBx0mIy8TEiIbIyQH\
HSYjHi1rSRYZLTQLC+ELC0toAQIBAgUGDhQUa0wDBBIyDgIDAwMBAQcIAwMTNAsPBAcBSgMEDB8e\
CQIDAgICAQEHCAMDEzQLBQcDIHoeHgEdAggOBgMFBQIHFBIsEAgPCVgQGRMaHg8yHBYTGh4PNDBH\
bSB6Hh4BHQEDBQUGBwMHCBgjAUdtKAE1JAULDAwMDAYQFwMBMxwmJQwUDQIBGCoXBAoJCwoKCwUQ\
FwMBMxwNGxgLKAAAAv/b/4gDKwEYAHoAjwAAJTY3NjMyFhc+ATMyFhUUBiMiJwczMhQrASI0OwET\
PgM1NCYjIg4DBw4BIyImNTQ2PwI0IyIPAQYHJwYmPwE2NTQmIyIPAQYHBisBIj8BNiYjIgYHBiY3\
PgMzMhc2MzIXPgEzMh4DFRQPAQYVFDMyNz4BFxYzMjY3PgE1NCYnJiMiBgcGFRQWAa0xFBgiIyQH\
HSYjHi1rSRYZLTQLC+ELC0toAQEDAQUGBw8SDhgIGjwtFRkCAzQBFRsIQQgPJg0IBEMBDAkbCEQH\
CAQENQ0NQgQGCA0WJAUVBBQQIh8SNwskJC0JCykTChIPCwcFLwQIAgMPJdEDBBIyDgYHBwgDAxM0\
Cw8Jd2wYHRMaHg80MEdtIHoeHgEdAgUJCQUHCA0fGzUQNjgVFAYNB4gGDhSrFgEBAQ8IqwMDBggU\
rBEDARqnDQ8aOQgMCSUaMBIoKCgQGAYLDxMKDQ19CwkOAgg1OQE1JA8mERAXAwEzHCYlEhoAAv/b\
/2ADGQG4AFcAnwAANwYHBisBIj8BNiYjIgYHBiY3PgMzMhc2MzIXPgEzMh4DFRQPAQYVFDMyNz4F\
NzYWBw4CIyImNTQ2PwI0IyIPAQYHJwYmPwE2NTQmIyIHEyImNTQ2MzIWFRQHBhUUMzI+BzcjIiY1\
NDY7AT4BMzIWFRQGIyImNTQ3NjQjIg4HBzMyFhUUDgErAQ4BUAcIBAQ1DQ1CBAYIDRYkBRUEFBAi\
HxI3CyQkLQkLKRMKEg8LBwUvBAgCAwULBwwDDQEGFQYSFy0fFRkCAzQBFRsIQQgPJg0IBEMBDAkb\
CPUgMBcTEhcSChkLEA8LDQoODRQKNQkKCQhBFGk0IDAXExIXEgoZBwwKBwgFBgMGATYJCwUJBj8h\
dhURAwEapw0PGjkIDAklGjASKCgoEBgGCw8TCg0NfQsJDgIDCQYPBRIBCQ0LHx8aFRQGDQeIBg4U\
qxYBAQEPCKsDAwYIFP6fJiAaIhQPDgsHDQ4GERMlJDw3VScMCQgLS18mIBoiFA8OCwYcBQsKFA0a\
DR4GDAgFCQbFwQAAAAAB/37/YAJpAbgAewAAJSMOASMiJjU0NjMyFhUUBwYVFDMyPgc3IyImNTQ+\
AzsBPgEzMhYVFAYjIiY1NDc2NCMiBwYHFz4BMzIWFRQGIyImNTQ3NjQjIg4HBzMyFhQGKwEOASMi\
MzIWFRQHMjc2MhcBJxMGIyImNTQ2MzIWFRQHMjf2KB8rNycbHCkXPws6ASAcEys3JxscKRdILgEW\
A/70LVUoISs3JxscKRdBCzwMKCggIB8ZHRsiywkEKSgfIB4ZHRtNAgL8bgwBJAwoKCAgHxkdGyIA\
AAAAAQAA/QwB2gHAAEUAABMGIyImNTQ2MzIWFRQHMj8BBiMiJjU0NjMyFhUUBzI/AQYjIiY1NDYz\
JjU0NjMyFhUUBwYVFDMyPgcBX5shdl8gMBcTEhcSChkLEA8LDQoODRQKNQkKAQMEBgNBFGk0IDAX\
ExIXEgoZJhcDAZsUaTQgMBcTEhcSChkHDAoHCAUGAwYBNgkLCwk/IXZfIDAXExIXEgoZCxAPCw0K\
Dw0U5sXBJiAaIhQPDgsHDQ4GERMlJDw3VScMCQMFBQQCS18mIBoiFA8OCwYccwwGAUtfJiAaIhQP\
DgsGHAULChQNGg0eBgwQDMXBJiAaIhQPDgsHDQ4GERMlJDw3VQAAAAAB/37/YAN0AbgAswAAEzM+\
ATMyFhUUBiMiJjU0NzY0IyIHBgcXPgEzMhYVFAYjIiY1NDc2NCMiDgcHMzIWFRQOASsBDgEjIiY1\
NDYzMhYVFAcGFRQzMj4HNyMOASMiJjU0NjMyFhUUBwYVFDMyPgc3Iw4BIyImNTQ2MzIWFRQHBhUU\
MhYVFAcyPwEiDgEjIiY1NDYyFhUUBzI3NjIXASerKCErNycbHCkXQQs6KCErNycbHCkXQQs6KB8r\
NycbHCkXPws6ASAcEys3JjgpF0guAhUD/qkt/jwMKCggIB8ZHRsiygwoKCAgHxkdGyLKDCgoICAf\
GR0bIssJBCkoHyAeGR0bTQIC+24MAAAAAQAA/QwCGQKuAFYAACUGIyImNTQ2MzIWFRQHMj8BBiMi\
JjU0NjMyFhUUBzI/ASIOASMiJjU0NjMyFhUUBzI3NjIXAScTBiMiJjU0NjMyFhUUBzI/AQYjIiY1\
NDYzMhYVFAcyNwE/KCErNycbHCkXQQs2KB8rNycbHCkXPws0ASAcEys3JxscKRdILgEWA/5qLVUo\
MzI+BzcjIiY1ND4DOwE+ATMyFhUUBiMiJjU0NzY0IyIOAgcGzJwUaTQgMBcTEhcSChkmFwMBmxRp\
NCAwFxMSFxIKGQcMCgcIBQYDBgE2CQoECQY/IXZfIDAXExIXEgoZCxAPCw0KDw0UCpshdl8gMBcT\
EhcSChkLEA8LDQoODRUKmyF2XyAwFxMSFxIKGQsQDwsNCg4NFAo1CQoBAwQGA0EUaTQgMBcTEhcS\
ChkOFQ4IBgIBDktfJiAaIhQPDgsGHHMMBgFLXyYgGiIUDw4LBhwFCwoUDRoNHgYMCAUJBsXBJiAa\
IhQPDgsHDQ4GERMlJDw3VSfFwSYgGiIUDw4LBw0OBhETJSQ7OFUnxcEmIBoiFA8OCwcNDgYREyUk\
PDdVJwwJAwUFBAJLXyYgGiIUDw4LBhwTJyIbCgAB/37/YASAAbgA5wAAARc+ATMyFhUUBiMiJjU0\
NzY0IyIHBgcXPgEzMhYVFAYjIiY1NDc2NCMiDgcHMzIWFAYrAQ4BIyImNTQ2MzIWFRQHBhUUMzI+\
BzcjDgEjIiY1NDYzMhYVFAcGFRQzMj4HNyMOASMiJjU0NjMyFhUUBwYVFDMyPgc3Iw4BIyImNTQ2\
MzIWFRQHBhUUMzI+BzcjIiY1ND4DOwE+ATMyFhUUBiMiJjU0NzY0IyIHBgcXPgEzMhYVFAYjIiY1\
NDc2NCMiDgcB2JwUaTQgMBcTEhcSChkmFwMBmxRpNCAwFxMSFxIKGQcMCgcIBQYDBgE2CQoKCT8h\
dl8gMBcTEhcSChkLEA8LDQoPDRQKmyF2XyAwFxMSFxIKGQsQDwsNCg4NFAqbIXZfIDAXExIXEgoZ\
CxAPCw0KDw0UCpshdl8gMBcTEhcSChkLEA8LDQoODRQKNQkKAQMEBgNBFGk0IDAXExIXEgoZJhcD\
AZsUaTQgMBcTEhcSChkHDAoHCAUGAwYBDwFLXyYgGiIUDw4LBhxzDAYBS18mIBoiFA8OCwYcBQsK\
FA0aDR4GDBAMxcEmIBoiFA8OCwcNDgYREyUkPDdVJ8XBJiAaIhQPDgsHDQ4GERMlIzw3VifFwSYg\
GiIUDw4LBw0OBhETJSQ8N1UnxcEmIBoiFA8OCwcNDgYREyUkPDdVJwwJAwUFBAJLXyYgGiIUDw4L\
BhxzDAYBS18mIBoiFA8OCwYcBQoLEw4ZDh0AAwAA/2AC3wG4ADcAewDFAAAzIiY1NDYzMhYVFAcW\
ISs3JxscKRdBCzooISs3JxscKRdBCzQMKCggIB8ZHRsixAwoKCAgHxkdGyLHCQQpKB8gHhkdG00C\
AvqADAEkDCgoICAfGR0bIsgMKCggIB8ZHRsiAAEAAP8aA1IA5gALAAA1MxUhNTMRIzUhFSMZAyAZ\
GfzgGeZ9ff40fX0AAAAAA//w/wYCJgD6AAcADwATAAA2IiY0NjIWFAAiJjQ2MhYUBQEzAVAyIyMy\
IwGIMiMjMiP90gG4fv5HSyMyIyMy/s8jMiMjMloB9P4MAAT/4f8GAwcA+gAHAA8AEwAXAAA2IiY0\
NjIWFAAiJjQ2MhYUBQEzATMBMwFBMiMjMiMCdzIjIzIj/OMBuHv+R3kBuHv+R0sjMiMjMv7PIzIj\
IzJaAfT+DAH0/gwAAQAA//0BtQDUAC8AACUyNjU0JwYjIjU+ATMyFhUUBwYjIi8BJiMiBhUUFzYz\
MhUUByInJjU0NzYzFh8BFgF2FRwWFBIcAQ8JIC0pFxwkHqggDxYcFRQTHBkZGBwoFiAoF6giJSkc\
JxAMGw8VQiYzJBUVghYoHicPDB0gAxoiLTMkEwIQghcAAAEAAP/NAbUBAwA2AAAXIiY1NDc2MxYf\
ATUzFRcWMzI2NTQnBiMiNT4BMzIWFRQHBiMiLwEVIzUnJiMiBhUUFzYzMhUUTSAtKBYgKBcuHlwi\
DxUcFhQSHAEPCSAtKRccJB4uHlwgDxYcFRQTHANDJjMkEwIQJGmARxcpHCcQDBsPFUImMyQVFSRs\
g0cWKB4nDwwdIAABAA0AAAJFAOAACwAANyc3FzcXNxcHJwcnIhWOZXhqTRaSaXRpLhmZfHx8VBeh\
fHx8AAAAAQAN/8sCRQERABMAACUHJwcnNxc3NTMXNxc3FwcnBxUjARZAaUsVjmUWGwFGak8UkmkZ\
MzI2NTQuAycuAjU0NjMyFhUUBiMiLgE1NDcmIyIGFRQeAhceARUUJQYuAT8BLgIjIgYjIg4BBwYn\
Jjc+ATceATMyNjMyFhcWFA8BDgEVFB4BFxY+AScuATU0NjMyFRQHBiMiIy4CIyIGBSImNTQ2MzIW\
FRQHDgEeARUUFjI+BzcjIi4BNTQ2OwE+ATMyFhUUBiMiJjU0NzY0IyIOBwczMhYUBisBDgFQHjIS\
DA4XDAYYFiEDDAUXAxQYFDctIjYWEAgQCwUQDg8ZERIeBRsXASYGCwEFrgQJCgcGHAYFEBIFEAUD\
BwsMARglDiAoBwQLBwsHmgICGioNBQkFAgMkFAwmJhITAwMSIxgIChL+vSAwFxMSFxIEAQECBhYQ\
DwsNCg4NFAo1BgkECQhBFGk0IDAXExIXEgoZBwwKBwgFBgMGATYJCgoJPyF2KxsQFg0LGAwSFhIJ\
DA0EDgINEh4PIy0kGBAYCQ8KCAgUEQ0JEwwRAxIfFVoDBAgNBr8CAgEBGB8EDQsIEx4uBAIBCAEB\
AREHowMFAgcDBwsDBA0GCAgUCxM3KxQJAQgGB6smIBoiFA8OCwIFBAYDCAYGERMlJDw3VScGCQYI\
C0tfJiAaIhQPDgsGHAULChQNGg0eBgwQDMXBAAAAAgAF//sB/AGaAAkALAAAAQ8BBhUUMzI2NwcO\
ASMiJjU0PwEjNTM/AQc3MhU2MzIWFRQGIiY1NDcGDwEjATZ/OQIUGEQSDCkyHyIiAzdpcxZZJpgZ\
IDUYHRggFgk3EEJIAQkHuAgDFRcPKBkUJBoLC7MgSi54Ci0pHBUSGxEOEhMPJ9gAAQAA//0BtQDU\
AC8AACUyNTQnBiImNT4BMzIWFRQHBiMiLwEmIyIVFBc2MzIWFRQGByInJjU0NzYzFh8BFgFwLRoQ\
HBQBFwkkLSkXHiYeohoRLhkQDw0VFA0dGBwoFiIqF6IcMTkgExAWDQ4WMzUzJBUVehI6IBIQFw4P\
EgIaIi0zJBMCEHoTAAEAAP/NAbUBAwA2AAAXIiY1NDc2MxYfATUzFRcWMzI2NTQnBiMiNT4BMzIW\
FRQHBiMiLwEVIzUnJiMiBhUUFzYzMhUUTSAtKBYgKBcuHlwiDxUcFhQSHAEPCSAtKRccJB4uHlwg\
DxYcFRQTHANDJjMkEwIQJGmARxcpHCcQDBsPFUImMyQVFSRsg0cWKB4nDwwdIAABAA0AAAJFAOAA\
CwAANyc3FzcXNxcHJwcnIhWOZXhqTRaSaXRpLhmZfHx8VBehfHx8AAAAAQAN/8sCRQERABMAACUH\
JwcnNxc3NTMXNxc3FwcnBxUjARZAaUsVjmUWGwFGak8UkmkZG0ZGfE4ZmXwXlntKfFUYoXwblgAA\
G0ZGfE4ZmXwXlntKfFUYoXwblgAABAAA//wD9AJ/AAkAlACgAKoAAAUiJjQ2MzIWFAYlJjU0NzYz\
MhYVFAcOBwcWMzI2NTQ2Ny4CPQEeARUUBiMiJwYjIiYnDgEiJicmIyIGBwYjIjU0Njc+CTc2NTQm\
AQAAAAABGAEYAAsAADM1IzUzNTMVMxUjFXt7eyJ7e3sie3siewAAAAEAAAAAATYBcgAKAAAxNT4E\
NzMUBiQxTDQ0Dx7APAcPKz1vSY7aAAAB//8AAAEtAKAAHQAANz4CMzIeARcWMzI3NhYHDgIjIi4B\
JyYjIgcGJgEJECkcGCYmDwkKHhgEDgIIESkcGCQlEgcIHR0FDUYZISAhMQoGJAYHBxkiHyExCgQj\
BggAAAABAAAAAAEsASwABwAAMREhESM1IxUBLCPmASz+1LS0AAEAAAAAAPoBwgAGAAAzAzMbATMD\
aWkoVVUoaQHC/pgBaP4+AAIAAAAAAMgAyAAHAA8AADYyNjQmIgYUFiImNDYyFhRFPiwsPix0Ujs7\
UjsZLD4sLD5FO1I7O1IAAf84AAAAyADIAAsAACM0NjIWFSM0JiIGFch2pHYeYJRgUnZ2UkpgYEoA\
AAACAAAAAAC0ASwABwAVAAA2MjY0JiIGFBc1LgE1NDYyFhUUBgcVSx4bGx4bGB0rN0Y3Kx14NTY1\
NTatZAg1Jyg8PCgnNQhkAAACAAAAAADIASwADwAfAAA3LgE1NDYyFhUUBgcdASM1Nz4BNTQmIgYV\
FBYXPQEzFVQkMDtSOzAkICAZIiw+LCIZIGYFOCUpOzspJTgFAWVlGQYqGh8sLB8aKgYBSUkAAAAE\
AAD//AP0An8AhwCRAJ0ApwAANz4BNTQuAScuATU0PgI/Ag4BFRQzMjcXDgEjIiY1ND4CMzIWFRQG\
IyImJzceATMyNTQuAicHBhUUHgIVFAYPAR4CMzoBMzI3JjU0NzYzMhYVFAcGBx4BMzI2NTQ2Ny4C\
PQEeARUUBiMiJwYjIi4BJw4BIiYnJiMiDgEHBiMiNTQ2BSImNDYzMhYUBiU+ATU0JyYjIgYVFAU2\
NTQ/AQ4BFDMyNxcOASMiJjU0PgIzMhYVFAYjIiYnNxYzMjY1NCYnBwYVFBYVFA8BHgEzMj4GNz4B\
NTQnJiMiBhUUBTY1NCYnDgEVFAPWCxMTCwwSEf3pIxwgThsjCgQMCxAKEgcSASosFTJDXSCBXrq0\
UUJBIyQ8IkETMCYgGxwaEg0tA1csCjohDhsPEQYKAwcDCQMCQgI0WnIgNRwQKTYwFBcfPXFIfntC\
JR05EQ0aNCEsXF8mAkYBJhE7DwQHBwkHDAgSLDUiBAQWHC8BPFoXEj8zAhIYEhIYEl84JTUlKykf\
IRMJEQ4QCg8GDgEzMBpSXxksWTQGATyxa0ZfOTooGCkbFiAtIwE6BwszFAgRBgwCEAMZDCkOCAIW\
QR4HDNcHWFAwCEUsIRofSEcvXDwlPispDC0dGyNJBaAIBhlEGggEowxYAgIHBAsHDyAwLyAHDhI5\
KyJwBYEiSRUdWUM+AAIADAAKAdMBzwAKAI8AACU0JiMiBhQWMzI2Jw4BIyImNDYzMhYXNjU0JyYj\
IiY0NjMyFx4BFxYzMjU0Jy4BNTQ2MzIWFRQGBxQzMjc+ATc2MzIWFRQGIyIGBwYVFDMyNjMyFhQG\
IyImIyIGFRQXHgEXFhUUBiMiJy4BJyYjIhUUFhUUBiMiJjQ2NTQjIgcOAQcGIyImNTQ3NjMyNzY1\
NAEWGA8QFRYPEBeJGSYOGRsaGQ0qGCUMFBgdHBkXEhALAxQLEhQBAiceFBIbIwEWEA0RAQ0MGhMe\
GxIbFQ0QIRsrDhwbHRkPJxQXEgsUOA0OGRcTFAwBExEKEiogExIdJhcNDhIDERIMFBoNDBYjEg3u\
EBQTIhYVCgElGSobJQIDFg4KExwoHQwLPhYNGA0IFycPFxobFhEjGSoQEzgPDhsUESMGCw4PFicd\
KBomCAoWChIDCw0ZExsOCzkVDx8eMBMUGBokMRckDhI9DAcWFBgODRINDBoAAAACAAD95AIdANwA\
NTQmJw4BFRSYNkUBAgIDUgMEBQECPWJqIB4dGhUpJR4tHz5wSH1yMi4cNhIYERQUMwwcQC0bCR0i\
HR8QEA4pHwwDCAIQIyEcIkwbIwodPBMgGxYxQ10ggV66tFFCQSMkPCEzFg4sKCAbHBoSChQZBloh\
CjADXAsTEwsMEhH+DzMkBAUVHC4BPFoXEj8wWhg/IAQHBwQIdCIFDg4MBASlBGMsIzwNQi8mGiFH\
RCxRNzA1MCsOHhEyChoiGgJCJBseNiEsFSZPFBQKKRoeNSg1JS4rICETOTAXEioZUl8ZLFk0BgE8\
sWtGXzk6FRQSJhkWIC0LFQQ6Bw04TxIYEhIYEoAvLxsHDhI5Kx50BYEiSRUdWEQ/AAAAAAIADAAK\
AdMBzwAKAI8AACU0JiMiBhQWMzI2Jw4BIyImNDYzMhYXNjU0JyYjIiY0NjMyFx4BFxYzMjU0Jy4B\
NTQ2MzIWFRQGBxQzMjc+ATc2MzIWFRQGIyIGBwYVFDMyNjMyFhQGIyImIyIGFRQXHgEXFhUUBiMi\
Jy4BJyYjIhUUFhUUBiMiJjQ2NTQjIgcOAQcGIyImNTQ3NjMyNzY1NAEWGA8QFRYPEBeJGSYOGRsa\
GQ0qGCUMFBgdHBkXEhALAxQLEhQBAiceFBIbIwEWEA0RAQ0MGhMeGxIbFQ0QIRsrDhwbHRkPJxQX\
EgsUOA0OGRcTFAwBExEKEiogExIdJhcNDhIDERIMFBoNDBYjEg3uEBQTIhYVCgElGSobJQIDFg4K\
ExwoHQwLPhYNGA0IFycPFxobFhEjGSoQEzgPDhsUESMGCw4PFicdKBomCAoWChIDCw0ZExsOCzkV\
Dx8eMBMUGBokMRckDhI9DAcWFBgODRINDBoAAAADAAD/BgH0APoABwAPABcAADYUFjI2NCYiAjQ2\
AwAPAAA3FSE1JTMVITUzEyMDIRUjGQHq/f0ZAeoZARkB/hYZRoyMljIy/QgBcjIAAAAAAAwAlgAB\
AAAAAAABAAcAEAABAAAAAAACAAcAKAABAAAAAAADACIAdgABAAAAAAAEAAcAqQABAAAAAAAFAAsA\
yQABAAAAAAAGAAcA5QADAAEECQABAA4AAAADAAEECQACAA4AGAADAAEECQADAEQAMAADAAEECQAE\
AA4AmQADAAEECQAFABYAsQADAAEECQAGAA4A1QBhAGIAYwAyAHMAdgBnAABhYmMyc3ZnAABSAGUA\
ZwB1AGwAYQByAABSZWd1bGFyAABGAG8AbgB0AEYAbwByAGcAZQAgADIALgAwACAAOgAgAGEAYgBj\
ADIAcwB2AGcAIAA6ACAAOQAtADMALQAyADAAMQA4AABGb250Rm9yZ2UgMi4wIDogYWJjMnN2ZyA6\
MhYUBiI2IiY0NjIWFC14qnh4qqWS0JKS0IEyIyMyI1WqeHiqeP7L0JKS0JK+IzIjIzIAAAIAAP8G\
AfQA+gAHAA8AADYUFjI2NCYiAjQ2MhYUBiIteKp4eKqlktCSktBVqnh4qnj+y9CSktCSAAAAAAMA\
AP6iAfQBXgARABcAHQAAEzMVHgEVFAYHFSM1LgE1NDY3GQEOARQWFz4BNCYn5C1gg4NgLWCEg2FN\
amp6TWlpTQFeZAqOYmGPCmRlCI9iY44I/jsBmAh1nnUICXSedAkAAAACAAD/BgHSAPoAIQApAAAl\
FhUUBwYjIicmIyIGFBYzMjc2MzIXFhUUBwYjIiY0NjMyAiImNDYyFhQBzwILBQYNCjN3VXh4VXgy\
BhIHAwwDQJVokpJolHsyIyMyI4IGBA8GAw5feKp4Xw0CBwwGBniS0JL+yiMyIyMyAAAAAQAA/wYB\
0gD6ACEAACUWFRQHBiMiJyYjIgYUFjMyNzYzMhcWFRQHBiMiJjQ2MzIBzwILBQYNCjN3VXh4VXgy\
BhIHAwwDQJVokpJolIIGBA8GAw5feKp4Xw0CBwwGBniS0JIAAAIAAP6iAdIBXgAkACoAACUWFxYV\
FAcGIyInJicRNjc2MzIXFhUUBwYHFSM1LgE1NDY3NTMDEQ4BFBYBEYQ6AgsFBg0KLWZlLgYSBwMM\
AzyCLWCEg2EtLU5pafkKbQYEDwYDDlQK/mgHVw0CBwwGBnAHZWUIj2Jjjghl/dYBmAh1nnUAAAEA\
AP/EAHgAPAAHAAAWIiY0NjIWFFUyIyMyIzwjMiMjMgAAAAEAAP6iAC0BXgADAAATESMRLS0BXv1E\
ArwAAAACAAD9EgFKAL4AAwAPAAA3FSE1JTMVITUzESMRIRUjHgEO/tQeAQ4eHv7yHkaMjHgyMvxU\
AmIyAAEAAAAAAlYBcgALAAA1Nxc3FzcXAScHJweJVFZSryL+/FRWUzVBuXNzcekW/qR0dHBHAAAB\
/+oAvQEQATcAGQAAET4BMzIWMjc2MzIVFAcOASMiJiIHBiMiNTQYIRwUVSgUAwcMFhghHBRVKBQE\
BwsBDhgRPRQDCQwWGBE9FAQKDAAAAAAADgCuAAEAAAAAAAAAfgD+AAEAAAAAAAEABwGNAAEAAAAA\
AAIABwGlAAEAAAAAAAMAJAH3AAEAAAAAAAQABwIsAAEAAAAAAAUACQJIAAEAAAAAAAYABwJiAAMA\
AQQJAAAA/AAAAAMAAQQJAAEADgF9AAMAAQQJAAIADgGVAAMAAQQJAAMASAGtAAMAAQQJAAQADgIc\
AAMAAQQJAAUAEgI0AAMAAQQJAAYADgJSAEMAbwBwAHkAcgBpAGcAaAB0ACAAXAAyADUAMQAgADIA\
MAAxADgAIABKAGUAYQBuAC0ARgByAGEAbgBjAG8AaQBzACAATQBvAGkAbgBlAC4AIABUAGgAaQBz\
ACAAZgBvAG4AdAAgAGkAcwAgAGwAaQBjAGUAbgBzAGUAZAAgAHUAbgBkAGUAcgAgAHQAaABlACAA\
UwBJAEwAIABPAHAAZQBuACAARgBvAG4AdAAgAEwAaQBjAGUAbgBzAGUAIABcACgAaAB0AHQAcAA6\
AC8ALwBzAGMAcgBpAHAAdABzAC4AcwBpAGwALgBvAHIAZwAvAE8ARgBMAFwAKQAuAABDb3B5cmln\
aHQgXDI1MSAyMDE4IEplYW4tRnJhbmNvaXMgTW9pbmUuIFRoaXMgZm9udCBpcyBsaWNlbnNlZCB1\
bmRlciB0aGUgU0lMIE9wZW4gRm9udCBMaWNlbnNlIFwoaHR0cDovL3NjcmlwdHMuc2lsLm9yZy9P\
RkxcKS4AAGEAYgBjADIAcwB2AGcAAGFiYzJzdmcAAFIAZQBnAHUAbABhAHIAAFJlZ3VsYXIAAEYA\
bwBuAHQARgBvAHIAZwBlACAAMgAuADAAIAA6ACAAYQBiAGMAMgBzAHYAZwAgADoAIAAyADcALQAx\
ADEALQAyADAAMQA4AABGb250Rm9yZ2UgMi4wIDogYWJjMnN2ZyA6IDI3LTExLTIwMTgAAGEAYgBj\
IDktMy0yMDE4AABhAGIAYwAyAHMAdgBnAABhYmMyc3ZnAABWAGUAcgBzAGkAbwBuACAAMQAuADAA\
AFZlcnNpb24gMS4wAABhAGIAYwAyAHMAdgBnAABhYmMyc3ZnAAAAAgAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAABEAAAAAQACAQIBAwEEAQUBBgEHAQgBCQEKAQsBDAENAQ4BDwEQAREBEgET\
ARQBFQEWARcBGAEZARoBGwEcAR0BHgEfASABIQEiASMBJAElASYBJwEoASkBKgErASwBLQEuAS8B\
MAExATIBMwE0ATUBNgE3ATgBOQE6ATsBPAE9AT4BPwFAAUEBQgYubm9kZWYHdW5pRTAwMAd1bmlF\
MDQ3B3VuaUUwNDgHdW5pRTA1MAd1bmlFMDVDB3VuaUUwNjIHdW5pRTA2OQd1bmlFMDdBB3VuaUUw\
N0IHdW5pRTA3Qwd1bmlFMDgwB3VuaUUwODEHdW5pRTA4Mgd1bmlFMDgzB3VuaUUwODQHdW5pRTA4\
NQd1bmlFMDg2B3VuaUUwODcHdW5pRTA4OAd1bmlFMDg5B3VuaUUwOEEHdW5pRTA4Qgd1bmlFMDhD\
B3VuaUUwOTQHdW5pRTA5NQd1bmlFMEEwB3VuaUUwQTEHdW5pRTBBMgd1bmlFMEEzB3VuaUUwQTQH\
dW5pRTBBOQd1bmlFMEIzB3VuaUUxMDEHdW5pRTFFNwd1bmlFMjYwB3VuaUUyNjEHdW5pRTI2Mgd1\
bmlFMjYzB3VuaUUyNjQHdW5pRTI4MAd1bmlFNEEwB3VuaUU0QUMHdW5pRTRDMAd1bmlFNENFB3Vu\
aUU0RTEHdW5pRTRFMgd1bmlFNEUzB3VuaUU0RTQHdW5pRTRFNQd1bmlFNEU2B3VuaUU0RTcHdW5p\
RTRFOAd1bmlFNEU5B3VuaUU0RUEHdW5pRTRFRQd1bmlFNTAwB3VuaUU1MDEHdW5pRTU2Nwd1bmlF\
NTY5B3VuaUU1NkMHdW5pRTU2RAd1bmlFNjUwB3VuaUU2NTUHdW5pRTk1QwAAAAAAAAH//wACAAAA\
AQAAAADVs2WlAAAAANGXIhcAAAAA1qodLQ==\
ADIAcwB2AGcAAGFiYzJzdmcAAFYAZQByAHMAaQBvAG4AIAAgAABWZXJzaW9uICAAAGEAYgBjADIA\
cwB2AGcAAGFiYzJzdmcAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgwAAAAEAAgEC\
AAMBAwEEAQUBBgEHAQgBCQEKAQsBDAENAQ4BDwEQAREBEgETARQBFQEWARcBGAEZARoBGwEcAR0B\
HgEfASABIQEiASMBJAElASYBJwEoASkBKgErASwBLQEuAS8BMAExATIBMwE0ATUBNgE3ATgBOQE6\
ATsBPAE9AT4BPwFAAUEBQgFDAUQBRQFGAUcBSAFJAUoBSwFMAU0BTgFPAVABUQFSAVMBVAFVAVYB\
VwFYAVkBWgFbAVwBXQFeAV8BYAFhAWIBYwFkAWUBZgFnAWgBaQFqAWsBbAFtAW4BbwFwAXEBcgFz\
AXQBdQF2AXcBeAF5AXoBewF8AX0BfgF/AYAGLm5vZGVmB3VuaUUwMDAHdW5pRTAyMgd1bmlFMDIz\
B3VuaUUwMjQHdW5pRTAzMAd1bmlFMDM4B3VuaUUwMzkHdW5pRTA0Mwd1bmlFMDQ1B3VuaUUwNDYH\
dW5pRTA0Nwd1bmlFMDQ4B3VuaUUwNTAHdW5pRTA1Qwd1bmlFMDYyB3VuaUUwNjkHdW5pRTA3QQd1\
bmlFMDdCB3VuaUUwN0MHdW5pRTA3RAd1bmlFMDgwB3VuaUUwODEHdW5pRTA4Mgd1bmlFMDgzB3Vu\
aUUwODQHdW5pRTA4NQd1bmlFMDg2B3VuaUUwODcHdW5pRTA4OAd1bmlFMDg5B3VuaUUwOEEHdW5p\
RTA4Qgd1bmlFMDhDB3VuaUUwOTQHdW5pRTA5NQd1bmlFMEEwB3VuaUUwQTEHdW5pRTBBMgd1bmlF\
MEEzB3VuaUUwQTQHdW5pRTBBOQd1bmlFMEIzB3VuaUUxMDEHdW5pRTFCOQd1bmlFMUJCB3VuaUUx\
RTcHdW5pRTI0MAd1bmlFMjQxB3VuaUUyNDIHdW5pRTI0Mwd1bmlFMjQ0B3VuaUUyNDUHdW5pRTI0\
Ngd1bmlFMjQ3B3VuaUUyNDgHdW5pRTI0OQd1bmlFMjYwB3VuaUUyNjEHdW5pRTI2Mgd1bmlFMjYz\
B3VuaUUyNjQHdW5pRTI4MAd1bmlFMjgxB3VuaUUyODIHdW5pRTI4Mwd1bmlFNEEwB3VuaUU0QTIH\
dW5pRTRBNAd1bmlFNEE4B3VuaUU0QUMHdW5pRTRDMAd1bmlFNENFB3VuaUU0RTEHdW5pRTRFMgd1\
bmlFNEUzB3VuaUU0RTQHdW5pRTRFNQd1bmlFNEU2B3VuaUU0RTcHdW5pRTRFOAd1bmlFNEU5B3Vu\
aUU0RUEHdW5pRTRFRQd1bmlFNTAwB3VuaUU1MDEHdW5pRTUyMAd1bmlFNTIxB3VuaUU1MjIHdW5p\
RTUyNAd1bmlFNTI1B3VuaUU1MjkHdW5pRTUyQQd1bmlFNTJCB3VuaUU1MkMHdW5pRTUyRAd1bmlF\
NTJGB3VuaUU1MzAHdW5pRTUzMQd1bmlFNTM5B3VuaUU1NjYHdW5pRTU2Nwd1bmlFNTY5B3VuaUU1\
NkMHdW5pRTU2RAd1bmlFNTgyB3VuaUU1RDAHdW5pRTVFMgd1bmlFNjEwB3VuaUU2MTIHdW5pRTYx\
NAd1bmlFNjE4B3VuaUU2MjQHdW5pRTYzMAd1bmlFNjUwB3VuaUU2NTUHdW5pRTkxMAd1bmlFOTEx\
B3VuaUU5MTIHdW5pRTkxNAd1bmlFOTE1B3VuaUU5MTgHdW5pRTkyMAd1bmlFOTI1B3VuaUU5NUQH\
dW5pRUEwMgd1bmlFQUE0AAAAAAH//wACAAEAAAAAAAAADAAUAAQAAAACAAAAAQAAAAEAAAAAAAEA\
AAAA1+feHQAAAADRlyIXAAAAANgjLVI=\
")'
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
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
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





+
+














-
+




















+

+

+


-
+


-
-
+
+
+
+
+




-
+
-












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







SplineFontDB: 3.0
FontName: abc2svg
FullName: abc2svg
FamilyName: abc2svg
Weight: Regular
Copyright: Copyright \\251 2018 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: 819
Descent: 205
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: 1518628013
ModificationTime: 1543339218
PfmFamily: 17
TTFWeight: 400
TTFWidth: 5
LineGap: 92
VLineGap: 92
Panose: 2 0 5 3 0 0 0 0 0 0
OS2TypoAscent: 0
OS2TypoAOffset: 1
OS2TypoDescent: 0
OS2TypoDOffset: 1
OS2TypoLinegap: 92
OS2WinAscent: 0
OS2WinAOffset: 1
OS2WinDescent: 0
OS2WinDOffset: 1
HheadAscent: 0
HheadAOffset: 1
HheadDescent: 0
HheadDOffset: 1
OS2Vendor: 'PfEd'
MarkAttachClasses: 1
DEI: 91125
LangName: 1033
Encoding: Custom
Compacted: 1
UnicodeInterp: none
NameList: Adobe Glyph List
DisplaySize: -24
DisplaySize: -96
AntiAlias: 1
FitToEm: 1
WinInfo: 0 16 10
BeginChars: 65 65
WinInfo: 48 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: 128 128

StartChar: .nodef
Encoding: 0 0 0
Width: 400
HStem: 0 400<0 401>
Flags: M
VStem: 0 401<0 400>
LayerCount: 2
Fore
SplineSet
0 0 m 1
 0 400 l 1
 401 400 l 1
 401 0 l 1
 0 0 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE000
Encoding: 1 57344 1
Width: 87
Flags: W
HStem: 0 21G<58 65>
VStem: 0 24<91.7005 190.325 838.222 935.924> 53 29<333.889 460.558 569.339 692.856>
StartChar: space
Encoding: 1 32 1
Width: 600
Flags: HM
LayerCount: 2
Fore
SplineSet
0 0 m 1053
EndSplineSet
Validated: 1
EndChar

StartChar: uniE000
Encoding: 2 57344 2
Width: 87
Flags: MW
LayerCount: 2
Fore
SplineSet
0 515 m 9
 0 517 l 1
 35 533 53 565 53 608 c 0
 53 642 42 692 18 758 c 0
︙
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
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
401
402








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

-
+

-
+
-
-



-
+



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


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


-
-
-
-
-
+
+
+
+
+





-
+







 29 39 0 91 0 160 c 0
 0 193 5 228 18 269 c 0
 42 335 53 385 53 419 c 0
 53 463 35 499 0 515 c 9
EndSplineSet
Validated: 1
EndChar

StartChar: uniE022
Encoding: 3 57378 3
Width: 330
Flags: MW
LayerCount: 2
Fore
SplineSet
-80 20 m 5
 410 20 l 5
 410 -20 l 5
 -80 -20 l 5
 -80 20 l 5
EndSplineSet
Validated: 1
EndChar

StartChar: uniE023
Encoding: 4 57379 4
Width: 531
Flags: MW
LayerCount: 2
Fore
SplineSet
-80 20 m 1
 610 20 l 5
 610 -20 l 1
 -80 -20 l 1
 -80 20 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE024
Encoding: 5 57380 5
Width: 210
Flags: HMW
LayerCount: 2
Fore
SplineSet
-80 20 m 1
 290 20 l 1
 290 -20 l 1
 -80 -20 l 1
 -80 20 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE030
Encoding: 6 57392 6
Width: 35
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 1000 m 5
 35 1000 l 5
 35 0 l 5
 0 0 l 5
 0 1000 l 5
EndSplineSet
Validated: 1
EndChar

StartChar: uniE038
Encoding: 7 57400 7
Width: 35
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 1000 m 1
 35 1000 l 1
 35 500 l 1
 0 500 l 1
 0 1000 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE039
Encoding: 8 57401 8
Width: 35
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 1100 m 1
 35 1110 l 5
 35 760 l 1
 0 760 l 1
 0 1100 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE043
Encoding: 9 57411 9
Width: 100
Flags: W
HStem: 320 100<8.4375 91.5625> 570 100<8.4375 91.5625>
VStem: 0 100<328.438 411.562 578.438 661.562>
LayerCount: 2
Fore
SplineSet
50 570 m 3
 22 570 0 592 0 620 c 3
 0 648 22 670 50 670 c 3
 78 670 100 648 100 620 c 3
 100 592 78 570 50 570 c 3
50 320 m 7
 22 320 0 342 0 370 c 7
 0 398 22 420 50 420 c 7
 78 420 100 398 100 370 c 7
 100 342 78 320 50 320 c 7
EndSplineSet
Validated: 1
EndChar

StartChar: uniE045
Encoding: 10 57413 10
Width: 1059
Flags: HMW
LayerCount: 2
Fore
SplineSet
590 0 m 24
 590 160 l 24
 620 160 l 0
 647 83 701 25 770 25 c 0
 818 25 870 42 870 90 c 0
 870 135 766 163 722 175 c 0
 661 192 590 212 590 286 c 0
 590 380 665 430 740 430 c 0
 791 430 809 423 840 405 c 0
 870 430 l 24
 900 430 l 24
 907 275 l 24
 877 275 l 0
 857 351 806 405 740 405 c 0
 702 405 652 376 652 338 c 0
 652 285 733 277 785 263 c 0
 878 238 940 209 940 136 c 0
 940 62 879 0 770 0 c 0
 718 0 688 9 655 32 c 0
 620 0 l 24
 590 0 l 24
1010 0 m 3
 982 0 960 22 960 50 c 3
 960 78 982 100 1010 100 c 3
 1038 100 1060 78 1060 50 c 3
 1060 22 1038 0 1010 0 c 3
505 0 m 3
 477 0 455 22 455 50 c 3
 455 78 477 100 505 100 c 3
 533 100 555 78 555 50 c 3
 555 22 533 0 505 0 c 3
180 390 m 24
 180 30 l 24
 220 30 l 0
 300 30 350 100 350 210 c 0
 350 320 300 390 220 390 c 0
 180 390 l 24
0 0 m 0
 0 30 l 24
 70 30 l 24
 70 390 l 24
 0 390 l 24
 0 420 l 24
 220 420 l 0
 360 420 470 361 470 210 c 0
 470 60 370 0 220 0 c 0
 147 0 73 0 0 0 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE046
Encoding: 11 57414 11
Width: 1061
Flags: HMW
LayerCount: 2
Fore
SplineSet
770 0 m 0
 636 0 550 70 550 210 c 0
 550 350 656 430 770 430 c 0
 818 430 838 425 875 400 c 0
 905 430 l 24
 935 430 l 24
 943 264 l 24
 910 260 l 0
 886 354 841 400 780 400 c 0
 700 400 670 305 670 215 c 0
 670 125 700 30 780 30 c 0
 855 30 906 86 928 165 c 0
 963 155 l 0
 939 65 890 0 770 0 c 0
1010 0 m 3
 982 0 960 22 960 50 c 3
 960 78 982 100 1010 100 c 3
 1038 100 1060 78 1060 50 c 3
 1060 22 1038 0 1010 0 c 3
505 0 m 3
 477 0 455 22 455 50 c 3
 455 78 477 100 505 100 c 3
 533 100 555 78 555 50 c 3
 555 22 533 0 505 0 c 3
180 390 m 24
 180 30 l 24
 220 30 l 0
 300 30 350 100 350 210 c 0
 350 320 300 390 220 390 c 0
 180 390 l 24
0 0 m 0
 0 30 l 24
 70 30 l 24
 70 390 l 24
 0 390 l 24
 0 420 l 24
 220 420 l 0
 360 420 470 361 470 210 c 0
 470 60 370 0 220 0 c 0
 147 0 73 0 0 0 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE047
Encoding: 2 57415 2
Encoding: 12 57415 12
Width: 480
Flags: W
Flags: HMW
HStem: 2 20<238.886 330.311> 278 80<0.392967 71.607> 338 80<362.393 433.607> 670 20<107.689 199.114>
VStem: -4 80<282.393 353.607> 23 28<542.438 620.954> 167 96<56 124.156> 175 96<567.844 636> 358 80<342.393 413.607> 387 28<71.0456 149.564>
LayerCount: 2
Fore
SplineSet
398 338 m 3xb080
398 338 m 3
 376 338 358 356 358 378 c 3
 358 400 376 418 398 418 c 3
 420 418 438 400 438 378 c 3
 438 356 420 338 398 338 c 3xb080
36 278 m 7xd8
 14 278 -4 296 -4 318 c 7
 -4 340 14 358 36 358 c 7
 58 358 76 340 76 318 c 7
 76 296 58 278 36 278 c 7xd8
167 86 m 0x92
 167 109 186 132 214 132 c 0
 240 132 263 111 263 89 c 0x92
 263 73 251 56 219 46 c 1
 235 30 259 22 283 22 c 0
 331 22 387 54 387 106 c 0
 387 130 371 162 339 194 c 1
 291 230 250 264 214 295 c 1
 438 356 420 338 398 338 c 3
36 278 m 3
 14 278 -4 296 -4 318 c 3
 -4 340 14 358 36 358 c 3
 58 358 76 340 76 318 c 3
 76 296 58 278 36 278 c 3
167 91 m 0
 167 114 186 137 214 137 c 0
 240 137 263 116 263 94 c 0
 263 78 251 61 219 51 c 1
 235 35 259 28 283 28 c 0
 331 28 375 59 375 111 c 0
 375 135 369 162 337 194 c 1
 214 295 l 1
 7 5 l 1
 -36 37 l 1
 175 331 l 1x9140
 59 440 23 515 23 570 c 0
 23 618 55 650 79 670 c 1
 111 686 139 690 167 690 c 0x96
 235 690 271 646 271 606 c 0
 271 583 252 560 224 560 c 0
 198 560 175 581 175 603 c 0x91
 175 619 187 636 219 646 c 1
 203 662 179 670 155 670 c 0
 107 670 51 638 51 586 c 0
 51 562 67 530 99 498 c 1
 147 462 188 428 223 397 c 1
 173 330 l 1
 47 429 11 500 11 570 c 0
 11 618 54 651 78 671 c 1
 110 687 139 690 167 690 c 0
 235 690 271 641 271 601 c 0
 271 578 252 555 224 555 c 0
 198 555 175 576 175 598 c 0
 175 614 187 631 219 641 c 1
 203 657 179 664 155 664 c 0
 107 664 63 633 63 581 c 0
 63 557 69 530 101 498 c 1
 223 397 l 1
 435 691 l 1
 478 660 l 1
 263 362 l 1x96
 379 252 415 177 415 122 c 0
 415 74 383 42 359 22 c 1
 327 6 299 2 271 2 c 0x9140
 203 2 167 46 167 86 c 0x92
 265 363 l 1
 391 263 427 192 427 122 c 0
 427 74 384 41 360 21 c 1
 328 5 299 2 271 2 c 0
 203 2 167 51 167 91 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE048
Encoding: 3 57416 3
Encoding: 13 57416 13
Width: 862
Flags: W
HStem: -67 43<422.573 472 512 561.427> 176 40<122 261.794 360 472 512 624 722.206 862> 417 42<420.937 472 512 558.146>
VStem: 260 100<86.3906 176 216 307.453> 472 40<-204 -64.8472 -24 176 216 416 456.872 596> 624 100<86.3906 176 216 306.031>
CounterMasks: 1 1c
LayerCount: 2
Fore
︙
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
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







-
+

-
+
-
-



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


-
-
+
+
-
-
-
-
-
-
+





-
+







 412 409 364 361 360 216 c 1
 472 216 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE050
Encoding: 4 57424 4
Encoding: 14 57424 14
Width: 779
Flags: W
Flags: HMW
HStem: -639 39<257.008 385.474> -255 39<268.842 402.5 446 488.682> 142 126<319.544 361 411 512.424>
VStem: 0 92<-43.3386 199.147> 139 226<-548.75 -424.855> 192 54<-23.0009 79.1161> 311 48<630.535 899.429> 425 39<-557.026 -267.641> 551 41<807.632 989.141> 613 66<-112.05 46.8229>
LayerCount: 2
Fore
SplineSet
399 266 m 1xf3c0
 408 267 418 268 428 268 c 0
 497 268 572 240 616 188 c 1
 667 133 679 68 679 -3 c 0
 679 -96 642 -169 555 -211 c 1
364 851 m 0
 358.834831965 811.556898639 356.976973124 782.035724861 356.976973124 751.255004513 c 0
 356.976973124 716.483564406 359.347803652 680.10480549 362 626 c 1
 443 681 551 791 551 896 c 4
 551 942 546 1011 497 1023 c 5
 417 1013 376 939 364 851 c 0
449 -250 m 9
 518 -230 488 -245 446 -249 c 1
 462 -436 l 1
 472 -486 l 0
 463 -452 464 -467 464 -482 c 0
 464 -585 424 -639 316 -639 c 0
 204 -639 139 -570 139 -486 c 0
 139 -429 184 -378 253 -378 c 0
 315 -378 365 -432 365 -491 c 0xf9c0
 365 -550 317 -584 255 -585 c 1
 275 -596 298 -600 324 -600 c 0
 472.010742188 -487.030273438 472.015625 -488.056640625 472.015625 -489.081054688 c 0
 472.015625 -586.490234375 422.876582453 -657 316 -657 c 0
 204 -657 139 -593 139 -509 c 0
 139 -452 184 -392 253 -392 c 0
 315 -392 365 -436 365 -495 c 0
 365 -554 317 -594 255 -595 c 1
 275 -606 298 -620 324 -620 c 0
 375 -600 425 -573 425 -472 c 0
 425 -463 425 -454 424 -444 c 9
 407 -254 l 1
 376.540978621 -620 435.012695312 -591.5 435.012695312 -489.685546875 c 0
 435.012695312 -488.795898438 435.008789062 -487.900390625 435 -487 c 0
 412 -254 l 17
 396 -255 379 -255 368 -255 c 0
 136 -255 0 -131 0 100 c 0
 0 188 25 277 57 334 c 1
 83 385 164 465 207 499 c 0
 398.364449186 -255.357092735 384.770660292 -256.025113783 371.270180398 -256.025113783 c 0
 175.860782244 -256.025113783 5.68434188608e-14 -116.071979914 0 100 c 0
 0 188 25 277 58 335 c 8
 131 463 275 562 326 600 c 1
 231 519 278 563 329 601 c 1
 321 705 311 787 311 852 c 0
 311 1052 410 1144 503 1172 c 1
 588 1080 592 1005 592 873 c 0
 592 688 539 598 380 473 c 1
 399 266 l 1xf3c0
411 142 m 1
 442 -212 l 1
 317 704 313 787 313 852 c 0
 313 1052 406 1152 494 1160 c 1
 570 1115 592 1005 592 873 c 0
 592 688 538 598 379 473 c 1
 399 266 l 0
 409.453125 267.208007812 419.672851562 267.79296875 429.6484375 267.79296875 c 0
 584.774414062 267.79296875 679 144.540865361 679 -3 c 0
 679 -124 618 -220 449 -250 c 9
601 -23 m 0
 579 -181 613 -104 613 -28 c 0
 613 54 533 142 425 142 c 0
 420 142 416 142 411 142 c 1
404 -212 m 2
 372 138 l 1
 303 125 246 83 246 16 c 0
 246 -16 267 -55 293 -87 c 1
 601 51.748046875 536.096679688 141.236328125 423.16015625 141.236328125 c 0
 419.477539062 141.236328125 415.756835938 140.158203125 412 140 c 1
 445 -215 l 1
 575 -189 601 -121 601 -23 c 0
375 138 m 1
 306 124 251 75 251 8 c 0
 251 -35 281 -84 319 -108 c 1
 246 -91 195 -56 195 46 c 0
 223 -70 192 1 192 73 c 0xf5c0
 192 172 270 236 361 261 c 1
 195 176 270 236 361 261 c 1
 344 450 l 1
 164 306 93 226 92 82 c 1
 95 -86 166 -216 400 -216 c 0
 404 -216 404 -214 404 -212 c 2
 94.8109172159 -111.016315493 218.774420218 -221.508405886 375.873991765 -221.508405886 c 0
 386.441654234 -221.508405886 397.159253713 -221.008441515 408 -220 c 0
363 822 m 0
 360 797 359 769 359 743 c 0xf3c0
 359 690 363 641 366 626 c 1
 447 681 551 785 551 890 c 0
 551 936 539 1003 501 1025 c 1
 415 1015 374 910 363 822 c 0
 375 138 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE05C
Encoding: 5 57436 5
Encoding: 15 57436 15
Width: 722
Flags: W
HStem: -516 36<404.33 535.95> -88 35<438.435 550.878> 50 35<444.881 548.647> 475 37<397.951 540.179>
VStem: 0 123<-514 510> 186 28<-514 -6 15 510> 290 157<-427.748 -329.281 326.281 424.154> 614 108<-378.538 -189.443 184.402 376.99>
LayerCount: 2
Fore
SplineSet
︙
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
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







-
+


-
-
+
+



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





-
+







 0 -514 l 1
 0 510 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE062
Encoding: 6 57442 6
Encoding: 16 57442 16
Width: 703
Flags: W
HStem: -170 101<618.082 698.676> -127 234<86.7071 208.416> 72 102<613.871 693.281> 212 43<161.915 326.675>
VStem: 19 243<-51.1252 51.2871> 425 118<-191.301 97.8937> 610 97<-162.037 -77.8382 83.7117 162.856>
HStem: -170 101<618.042 698.676> -113 224<91.5691 210.802> 72 102<613.779 693.281> 215 40<163.491 326.905>
VStem: 19 241<-54.3228 59.215> 422 121<-211.326 98.8623> 610 97<-162.037 -77.8382 83.7117 162.856>
LayerCount: 2
Fore
SplineSet
19 41 m 0x5e
 19 173 130 255 261 255 c 0
 374 255 448 220 499 146 c 0
 529 102 543 31 543 -30 c 0
 543 -193 492 -322 392 -412 c 1
 291 -501 118 -593 -70 -603 c 1
 72 -565 199 -508 287 -414 c 1
 347 -352 392 -252 414 -146 c 0
 421 -107 425 -69 425 -36 c 0
 425 48 406 112 369 155 c 1
 328 200 294 212 242 212 c 0
 166 212 85 156 67 62 c 1
 97 100 108 107 145 107 c 0
 206 107 262 48 262 -15 c 0
 262 -47 250 -75 223 -97 c 1
 200 -118 172 -127 145 -127 c 0
 67 -127 19 -40 19 41 c 0x5e
661 -170 m 4x9e
 632 -170 610 -150 610 -119 c 4
 610 -90 627 -69 656 -69 c 4
 683 -69 707 -90 707 -119 c 4
 707 -148 687 -170 661 -170 c 4x9e
655 72 m 4x3e
 625 72 605 94 605 127 c 4
 605 156 624 174 654 174 c 4
 681 174 702 153 702 127 c 4
 702 94 682 72 655 72 c 4x3e
19 29 m 0x5e
 19 161 125 255 261 255 c 0
 378 255 440 220 496 146 c 0
 528.135801023 103.534834363 543 31 543 -30 c 0
 543 -193 509 -303 392 -412 c 24
 250 -545 118 -593 -70 -603 c 1
 72 -565 193 -517 296 -414 c 0
 362.272166103 -347.727833897 383 -307 408 -201 c 0
 417.095703125 -162.434570312 422 -69 422 -36 c 0
 422 48 418 100 376 150 c 0
 339.06264499 193.973041679 314 215 245 215 c 0
 168 215 91 170 67 62 c 1
 97 100 116 111 153 111 c 4
 214 111 260 62 260 -1 c 0
 260 -33 248 -61 221 -83 c 1
 198 -104 166 -113 139 -113 c 0
 71 -113 19 -52 19 29 c 0x5e
661 -170 m 0x9e
 632 -170 610 -150 610 -119 c 0
 610 -90 629 -69 656 -69 c 4
 683 -69 707 -90 707 -119 c 0
 707 -148 687 -170 661 -170 c 0x9e
655 72 m 0x3e
 625 72 605 94 605 127 c 0
 605 156 626 174 654 174 c 4
 681 174 702 153 702 127 c 0
 702 94 682 72 655 72 c 0x3e
EndSplineSet
Validated: 1
EndChar

StartChar: uniE069
Encoding: 7 57449 7
Encoding: 17 57449 17
Width: 470
Flags: W
VStem: 0 150<-250 250> 220 150<-250 250>
LayerCount: 2
Fore
SplineSet
220 250 m 1
︙
383
384
385
386
387
388
389
390

391
392
393
394
395
396
397
621
622
623
624
625
626
627

628
629
630
631
632
633
634
635







-
+







 0 -250 l 1
 0 250 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE07A
Encoding: 8 57466 8
Encoding: 18 57466 18
Width: 779
Flags: W
HStem: -502 30<205.501 304.477> -204 31<214.246 323 357 391.941> 113 95<243.207 289> 118 99<329.167 431.634>
VStem: 0 76<-48.8921 170.465> 111 181<-436.162 -326.772> 154 43<-16.0423 68.9973> 249 38<502.74 719.447> 338 32<-437.341 -205.711> 442 32<651.371 785.751> 502 41<-92.0505 45.5518>
LayerCount: 2
Fore
SplineSet
︙
445
446
447
448
449
450
451
452

453
454
455
456
457
458
459
683
684
685
686
687
688
689

690
691
692
693
694
695
696
697







-
+







 442 749 433 790 401 820 c 1
 331 792 299 728 290 658 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE07B
Encoding: 9 57467 9
Encoding: 19 57467 19
Width: 782
Flags: W
HStem: -413 29<322.95 428.387> -70 28<351.623 440.673> 40 28<355.737 438.873> 380 30<318.164 432.756>
VStem: 0 98<-411 408> 149 22<-411 -5 12 408> 232 126<-344.637 -259.418 257.61 342.509> 491 87<-311.532 -144.136 138.096 308.532>
LayerCount: 2
Fore
SplineSet
︙
513
514
515
516
517
518
519
520

521
522
523
524
525
526
527
751
752
753
754
755
756
757

758
759
760
761
762
763
764
765







-
+







 0 -411 l 1
 0 408 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE07C
Encoding: 10 57468 10
Encoding: 20 57468 20
Width: 807
Flags: W
HStem: -136 81<491.982 561.648> -102 188<67.2812 172.801> 58 81<488.633 557.386> 170 34<129.66 260.591>
VStem: 15 195<-48.9031 47.6335> 340 94<-168.512 89.0947> 488 78<-131.953 -59.6448 63.9747 133.311>
LayerCount: 2
Fore
SplineSet
︙
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
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








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

-
+




















-
+







 500 58 484 76 484 102 c 0
 484 125 499 139 523 139 c 0
 545 139 562 123 562 102 c 0
 562 76 546 58 524 58 c 0x3e
EndSplineSet
Validated: 1
EndChar

StartChar: uniE07D
Encoding: 21 57469 21
Width: 200
Flags: HMW
LayerCount: 2
Fore
SplineSet
80 119 m 1
 55 105 45 90 45 70 c 0
 45 42 68 20 88 20 c 0
 113 20 125 44 125 64 c 0
 125 84 103 102 80 119 c 1
123 220 m 28
 105 220 90 209 90 189 c 0
 90 169 99 159 122 141 c 1
 145 148 157 161 157 185 c 0
 157 205 144 220 123 220 c 28
90 0 m 0
 41 0 0 30 0 70 c 0
 0 104 32 118 69 130 c 1
 49 148 40 157 40 180 c 0
 40 215 70 240 110 240 c 0
 154 240 200 220 200 180 c 0
 200 156 178 139 140 129 c 1
 164 110 180 90 180 70 c 0
 180 27 140 0 90 0 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE080
Encoding: 11 57472 11
Encoding: 22 57472 22
Width: 430
Flags: HMW
LayerCount: 2
Fore
SplineSet
138 0 m 1
 138 -130 168 -218 215 -218 c 1
 260 -218 292 -130 292 0 c 1
 292 130 268 218 215 218 c 1
 165 218 138 130 138 0 c 1
0 3 m 1
 0 140 95 250 215 250 c 1
 335 250 430 140 430 0 c 1
 430 -140 335 -250 215 -250 c 1
 95 -250 0 -140 0 3 c 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE081
Encoding: 12 57473 12
Encoding: 23 57473 23
Width: 290
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 0 m 25
 100 250 l 25
︙
596
597
598
599
600
601
602
603

604
605
606
607
608
609
610
864
865
866
867
868
869
870

871
872
873
874
875
876
877
878







-
+







 115 100 l 29
 0 0 l 25
EndSplineSet
Validated: 1
EndChar

StartChar: uniE082
Encoding: 13 57474 13
Encoding: 24 57474 24
Width: 400
Flags: HMW
HStem: -250 500
VStem: 0 400
LayerCount: 2
Fore
SplineSet
︙
631
632
633
634
635
636
637
638

639
640
641
642
643
644
645
899
900
901
902
903
904
905

906
907
908
909
910
911
912
913







-
+







 28 25 0 60 0 128 c 0
 0 213 102 250 199 250 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE083
Encoding: 14 57475 14
Encoding: 25 57475 25
Width: 380
Flags: HMW
HStem: -250 500
LayerCount: 2
Fore
SplineSet
102 170 m 1
︙
668
669
670
671
672
673
674
675

676
677
678
679
680
681
682
936
937
938
939
940
941
942

943
944
945
946
947
948
949
950







-
+







 252 177 223 213 175 213 c 0
 131 213 109 193 102 170 c 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE084
Encoding: 15 57476 15
Encoding: 26 57476 26
Width: 400
Flags: HMW
HStem: -250 500
VStem: 0 400
LayerCount: 2
Fore
SplineSet
︙
699
700
701
702
703
704
705
706

707
708
709
710
711
712
713
967
968
969
970
971
972
973

974
975
976
977
978
979
980
981







-
+







 325 -160 l 5
 325 -209 l 5
EndSplineSet
Validated: 1
EndChar

StartChar: uniE085
Encoding: 16 57477 16
Encoding: 27 57477 27
Width: 400
Flags: HMW
HStem: -250 500
LayerCount: 2
Fore
SplineSet
18 -95 m 0
︙
734
735
736
737
738
739
740
741

742
743
744
745
746
747
748
1002
1003
1004
1005
1006
1007
1008

1009
1010
1011
1012
1013
1014
1015
1016







-
+







 25 -217 0 -176 0 -152 c 0
 0 -135 3 -113 18 -95 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE086
Encoding: 17 57478 17
Encoding: 28 57478 28
Width: 385
Flags: HMW
HStem: -250 500
LayerCount: 2
Fore
SplineSet
200 -210 m 0
︙
764
765
766
767
768
769
770
771

772
773
774
775
776
777
778
1032
1033
1034
1035
1036
1037
1038

1039
1040
1041
1042
1043
1044
1045
1046







-
+







 1 133 74 250 200 250 c 0
 257 250 298 244 340 205 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE087
Encoding: 18 57479 18
Encoding: 29 57479 29
Width: 400
Flags: HMW
HStem: -250 500
LayerCount: 2
Fore
SplineSet
97 161 m 0
︙
787
788
789
790
791
792
793
794

795
796
797
798
799
800
801
1055
1056
1057
1058
1059
1060
1061

1062
1063
1064
1065
1066
1067
1068
1069







-
+







 305 125 280 121 268 121 c 0
 194 121 173 161 97 161 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE088
Encoding: 19 57480 19
Encoding: 30 57480 30
Width: 400
Flags: HMW
HStem: -250 500
LayerCount: 2
Fore
SplineSet
154 -42 m 1
︙
814
815
816
817
818
819
820

821
822
823
824

825
826
827
828
829
830
831
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092

1093
1094
1095
1096
1097
1098
1099
1100







+



-
+







 294 250 370 197 370 130 c 0
 370 77 342 46 280 16 c 1
 351 -16 388 -46 388 -121 c 4
 388 -197 293 -250 194 -250 c 1
 93 -250 0 -194 0 -130 c 0
 0 -77 50 -44 108 -16 c 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE089
Encoding: 20 57481 20
Encoding: 31 57481 31
Width: 385
Flags: HMW
HStem: -250 500
LayerCount: 2
Fore
SplineSet
185 210 m 0
︙
847
848
849
850
851
852
853
854

855
856
857
858
859
860
861
1116
1117
1118
1119
1120
1121
1122

1123
1124
1125
1126
1127
1128
1129
1130







-
+







 384 -133 311 -250 185 -250 c 0
 128 -250 87 -244 45 -205 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE08A
Encoding: 21 57482 21
Encoding: 32 57482 32
Width: 409
Flags: W
HStem: -246 29<187.663 292.861> 30 134<264.058 320.72> 228 21<196.786 281.147>
VStem: 9 110<-126.934 138.101> 325 54<100.5 183.933> 392 17<-84.7973 -75.9219>
LayerCount: 2
Fore
SplineSet
︙
881
882
883
884
885
886
887
888

889
890
891
892
893
894
895
1150
1151
1152
1153
1154
1155
1156

1157
1158
1159
1160
1161
1162
1163
1164







-
+







 244 130 265 164 302 164 c 2
 303 164 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE08B
Encoding: 22 57483 22
Encoding: 33 57483 33
Width: 408
Flags: W
HStem: -246 29<215.419 292.933> 30 134<264.058 320.72> 228 21<215.371 280.515>
VStem: 9 110<-126.934 136.6> 180 35<-350 -246 -197 209 248 350> 325 54<100.5 183.933> 392 17<-84.661 -75.9219>
LayerCount: 2
Fore
SplineSet
︙
928
929
930
931
932
933
934
935

936
937
938
939
940
941
942
1197
1198
1199
1200
1201
1202
1203

1204
1205
1206
1207
1208
1209
1210
1211







-
+







 119 -58 126 -133 158 -175 c 0
 165 -184 172 -191 180 -197 c 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE08C
Encoding: 23 57484 23
Encoding: 34 57484 34
Width: 500
Flags: HMW
HStem: -250 500
LayerCount: 2
Fore
SplineSet
0 35 m 25
︙
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
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
1046
1047
1048





1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
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
1095
1096

1097
1098
1099
1100
1101
1102
1103
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
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











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








1337
1338
1339
1340
1341
1342
1343
1344
1345
1346

1347
1348
1349
1350
1351
1352
1353
1354







-
+


















-
+

















-
-
-
+
+
+
-
-



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





-
-
-
+
+
+
-
-



-
-
-
-
-
+
+
+
+
+

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






-
-
-
+
+
+
-
-



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





-
+







 0 -35 l 25
 0 35 l 25
EndSplineSet
Validated: 1
EndChar

StartChar: uniE094
Encoding: 24 57492 24
Encoding: 35 57492 35
Width: 260
Flags: MW
HStem: -250 500
LayerCount: 2
Fore
SplineSet
220 -490 m 0
 228 -500 208 -509 200 -500 c 4
 105 -388 20 -171 20 0 c 0
 20 170 105 388 200 500 c 0
 211 513 231 503 220 490 c 0
 136 388 90 170 90 0 c 0
 90 -169 138 -388 220 -490 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE095
Encoding: 25 57493 25
Encoding: 36 57493 36
Width: 260
Flags: HMW
LayerCount: 2
Fore
SplineSet
20 -490 m 0
 102 -388 150 -169 150 0 c 0
 150 170 104 388 20 490 c 0
 9 503 29 513 40 500 c 0
 135 388 220 170 220 0 c 0
 220 -171 135 -388 40 -500 c 0
 32 -509 12 -500 20 -490 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE0A0
Encoding: 26 57504 26
Width: 529
Flags: W
Encoding: 37 57504 37
Width: 619
Flags: HMW
HStem: -129 35<239.072 356.375> 98 31<166.535 282.804>
VStem: 0 39<-180 170> 40 106<-19.7907 60.9119> 378 110<-62.7554 24.9716> 489 40<-180 170>
LayerCount: 2
Fore
SplineSet
424 -32 m 0
 424 38 361 99 280 99 c 0
 241 99 196 73 196 29 c 0
 196 -42 263 -99 344 -99 c 0
 385 -99 424 -77 424 -32 c 0
489 170 m 1
 529 170 l 1
 529 -180 l 1
 489 -180 l 1
 489 170 l 1
0 170 m 1
 39 170 l 1
 39 -180 l 1
 0 -180 l 1
 0 170 l 1
538 170 m 1
 588 170 l 1
 588 -170 l 1
 538 -170 l 1
 538 170 l 1
36 170 m 1
 86 170 l 1
 86 -170 l 1
 36 -170 l 1
 36 170 l 1
151 63 m 0
 148 56 146 47 146 37 c 0
 146 29 147 22 149 15 c 0
 161 -26 224 -89 290 -94 c 0
 294 -94 299 -94 303 -94 c 0
 331 -94 357 -88 373 -59 c 0
 377 -52 378 -44 378 -36 c 0
 378 -27 377 -18 375 -11 c 0
 364 30 300 93 234 98 c 0
 230 98 225 98 221 98 c 0
 192 98 164 92 151 63 c 0
488 0 m 0
537 0 m 0
 488 -80 400 -129 264 -129 c 0
 128 -129 40 -80 40 -5 c 0
 40 80 128 129 264 129 c 0
 400 129 488 80 488 0 c 0
 537 -80 448 -130 312 -130 c 0
 176 -130 87 -75 87 0 c 0
 87 85 176 130 312 130 c 0
 448 130 537 80 537 0 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE0A1
Encoding: 27 57505 27
Width: 540
Flags: W
Encoding: 38 57505 38
Width: 530
Flags: HMW
HStem: -170 100<25 515> 70 100<25 515>
VStem: 0 25<-220 -170 -70 70 170 220> 515 25<-220 -170 -70 70 170 220>
LayerCount: 2
Fore
SplineSet
25 70 m 29
 25 -70 l 29
 515 -70 l 29
 515 70 l 29
 25 70 l 29
30 65 m 25
 30 -65 l 25
 500 -65 l 25
 500 65 l 25
 30 65 l 25
0 220 m 29
 25 220 l 29
 25 170 l 29
 515 170 l 29
 515 220 l 29
 540 220 l 29
 540 -220 l 29
 515 -220 l 29
 515 -170 l 29
 25 -170 l 29
 25 -220 l 29
 0 -220 l 29
 30 220 l 25
 30 165 l 25
 500 165 l 25
 500 220 l 25
 530 220 l 25
 530 -220 l 25
 500 -220 l 25
 500 -165 l 25
 30 -165 l 25
 30 -220 l 25
 0 -220 l 25
 0 220 l 29
EndSplineSet
Validated: 1
EndChar

StartChar: uniE0A2
Encoding: 28 57506 28
Width: 448
Flags: W
Encoding: 39 57506 39
Width: 450
Flags: HMW
HStem: -129 35<199.072 316.375> 98 31<126.535 242.804>
VStem: 0 106<-19.7907 60.9119> 338 110<-62.7554 24.9716>
LayerCount: 2
Fore
SplineSet
111 63 m 0
337 -30 m 4
 108 56 106 47 106 37 c 0
 106 29 107 22 109 15 c 0
 337 40 264 101 193 101 c 4
 154 101 109 75 109 31 c 4
 121 -26 184 -89 250 -94 c 0
 254 -94 259 -94 263 -94 c 0
 109 -40 186 -97 257 -97 c 4
 291 -94 317 -88 333 -59 c 0
 337 -52 338 -44 338 -36 c 0
 338 -27 337 -18 335 -11 c 0
 298 -97 337 -75 337 -30 c 4
 324 30 260 93 194 98 c 0
 190 98 185 98 181 98 c 0
 152 98 124 92 111 63 c 0
448 0 m 0
 448 -80 360 -129 224 -129 c 0
 88 -129 0 -80 0 -5 c 0
 0 80 88 129 224 129 c 0
 360 129 448 80 448 0 c 0
450 0 m 0
 450 -70 361 -129 225 -129 c 0
 89 -129 0 -70 0 0 c 0
 0 70 89 129 225 129 c 0
 361 129 450 70 450 0 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE0A3
Encoding: 29 57507 29
Encoding: 40 57507 40
Width: 329
Flags: W
HStem: -148 57<54.5533 171.763> 91 57<156.237 273.528>
VStem: 0 31<-79.2669 -12.3025> 297 31<12.3025 73.4219>
LayerCount: 2
Fore
SplineSet
︙
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
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
1392
1393
1394
1395
1396
1397







-
-
-
+
+
+
-
-



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





-
+







 0 70 105 148 198 148 c 0
 245 148 288 128 313 81 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE0A4
Encoding: 30 57508 30
Width: 330
Flags: W
Encoding: 41 57508 41
Width: 320
Flags: HMW
HStem: -140 279<120.935 205.86>
VStem: 0 330<-42.5424 39.6306>
LayerCount: 2
Fore
SplineSet
0 -33 m 0
 0 55 77 109 165 132 c 0
 182 136 197 139 212 139 c 0
 276 139 330 103 330 33 c 0
320 40 m 0
 320 -51 231 -135 110 -135 c 0
 40 -135 0 -90 0 -40 c 0
 0 50 90 135 210 135 c 0
 330 -56 255 -106 165 -132 c 0
 147 -138 131 -140 114 -140 c 0
 280 135 320 90 320 40 c 0
 52 -140 0 -103 0 -33 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE0A9
Encoding: 31 57513 31
Encoding: 42 57513 42
Width: 330
Flags: HMW
LayerCount: 2
Fore
SplineSet
-2 113 m 1
 25 145 l 1
︙
1160
1161
1162
1163
1164
1165
1166
1167

1168
1169
1170
1171
1172
1173
1174
1407
1408
1409
1410
1411
1412
1413

1414
1415
1416
1417
1418
1419
1420
1421







-
+







 132 -0 l 1
 -2 113 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE0B3
Encoding: 32 57523 32
Encoding: 43 57523 43
Width: 300
Flags: HMW
LayerCount: 2
Fore
SplineSet
150 -18 m 1
 79 -90 l 1
︙
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
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
1270
1271
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
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
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
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
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
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

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







-
+














-
-
-
+
+
+

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












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

-
+

-
+
-
-



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





-
+







 300 -83 233 -150 150 -150 c 24
 67 -150 0 -83 0 0 c 24
EndSplineSet
Validated: 1
EndChar

StartChar: uniE101
Encoding: 33 57601 33
Encoding: 44 57601 44
Width: 560
Flags: W
LayerCount: 2
Fore
SplineSet
0 -250 m 5
 440 250 l 5
 560 250 l 5
 119 -250 l 5
 0 -250 l 5
EndSplineSet
Validated: 1
EndChar

StartChar: uniE1E7
Encoding: 34 57831 34
Width: 480
StartChar: uniE1B9
Encoding: 45 57785 45
Width: 330
Flags: W
HStem: -50 100<8.4375 91.5625>
VStem: 0 100<-41.5625 41.5625>
HStem: -140 280
VStem: 0 330
LayerCount: 2
Fore
SplineSet
0 0 m 1
 165 140 l 1
 330 0 l 1
 165 -140 l 1
 0 0 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE1BB
Encoding: 46 57787 46
Width: 330
Flags: W
HStem: -140 280
VStem: 0 330
LayerCount: 2
Fore
SplineSet
0 -140 m 29
 165 140 l 25
 330 -140 l 29
 0 -140 l 29
EndSplineSet
Validated: 1
EndChar

StartChar: uniE1E7
Encoding: 47 57831 47
Width: 100
Flags: MW
LayerCount: 2
Fore
SplineSet
50 -50 m 3
 22 -50 0 -28 0 0 c 3
 0 28 22 50 50 50 c 3
 78 50 100 28 100 0 c 3
 100 -28 78 -50 50 -50 c 3
EndSplineSet
Validated: 1
EndChar

StartChar: uniE240
Encoding: 48 57920 48
Width: 315
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 -239 m 9
 0 0 l 1
 30 0 l 1
 51 -195 315 -321 315 -584 c 0
 315 -643 302 -710 269 -785 c 1
 282 -738 287 -691 287 -647 c 0
 287 -452 175 -294 30 -239 c 1
 0 -239 l 9
EndSplineSet
Validated: 1
EndChar

StartChar: uniE241
Encoding: 49 57921 49
Width: 315
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 0 m 1
 0 239 l 1
 30 239 l 1
 178 280 288 445 288 642 c 0
 288 688 282 736 269 785 c 1
 302 711 315 647 315 588 c 0
 315 328 51 195 30 0 c 0
 0 0 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE242
Encoding: 50 57922 50
Width: 315
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 -343 m 9
 0 0 l 1
 30 0 l 1
 62.1962890625 -133.135742188 315.4921875 -235.983398438 315.4921875 -417.918945312 c 0
 315.4921875 -445.063476562 309.853515625 -473.969726562 297 -505 c 1
 308.7109375 -531.232421875 315.594726562 -559.000976562 315.594726562 -588.922851562 c 0
 315.594726562 -622.875976562 306.73046875 -659.6015625 286 -700 c 1
 289.740234375 -679.993164062 291.475585938 -660.758789062 291.475585938 -642.3125 c 0
 291.475585938 -448.700195312 100.301757812 -342 30 -342 c 1
 0 -343 l 9
30 -171 m 1
 56 -278 226 -366 291 -492 c 1
 291.465820312 -485.108398438 291.692382812 -478.3203125 291.692382812 -471.635742188 c 0
 291.692382812 -277.536132812 100.569335938 -171 30 -171 c 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE243
Encoding: 51 57923 51
Width: 315
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 -1 m 9
 0 342 l 1
 30 342 l 1
 100.301757812 342 291.475585938 448.700195312 291.475585938 642.3125 c 0
 291.475585938 660.758789062 289.740234375 679.993164062 286 700 c 1
 306.73046875 659.6015625 315.594726562 622.875976562 315.594726562 588.922851562 c 0
 315.594726562 559.000976562 308.7109375 531.232421875 297 505 c 1
 309.853515625 473.969726562 315.4921875 445.063476562 315.4921875 417.918945312 c 0
 315.4921875 235.983398438 62.1962890625 133.135742188 30 0 c 1
 0 -1 l 9
30 171 m 1
 100.569335938 171 291.692382812 277.536132812 291.692382812 471.635742188 c 0
 291.692382812 478.3203125 291.465820312 484.108398438 291 491 c 1
 226 365 56 278 30 171 c 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE244
Encoding: 52 57924 52
Width: 315
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 -368 m 9
 0 145 l 1
 30 145 l 1
 62 12 315 -91 315 -273 c 0
 315 -300 310 -329 297 -360 c 1
 309 -386 315 -414 315 -444 c 0
 315 -471 310 -500 297 -531 c 1
 309 -557 316 -585 316 -615 c 0
 316 -649 307 -686 286 -726 c 1
 290 -706 291 -687 291 -668 c 0
 291 -475 100 -368 30 -368 c 1
 0 -368 l 9
30 -199 m 1
 56 -307 226 -392 291 -518 c 1
 291 -511 292 -504 292 -498 c 0
 292 -305.781467412 104.491731968 -198.972460053 31.9860569235 -198.972460053 c 0
 31.3140795885 -198.972460053 30.6519803414 -198.981634357 30 -199 c 1
30 -28 m 1
 56 -135 226 -221 291 -347 c 1
 291 -340 292 -333 292 -327 c 0
 292 -134.781467412 104.491731968 -27.9724600525 31.9860569235 -27.9724600525 c 0
 31.3140795885 -27.9724600525 30.6519803414 -27.9816343566 30 -28 c 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE245
Encoding: 53 57925 53
Width: 315
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 343 m 17
 30 343 l 1
 100.301757812 343 291.475585938 449.700195312 291.475585938 643.3125 c 0
 291.475585938 661.758789062 289.740234375 680.993164062 286 701 c 1
 306.73046875 660.6015625 315.594726562 623.875976562 315.594726562 589.922851562 c 0
 315.594726562 560.000976562 308.7109375 532.232421875 297 506 c 1
 309.81640625 475.145507812 315.422851562 446.318359375 315.422851562 419.19921875 c 0
 315.422851562 389.1875 308.556640625 361.265625 297 335 c 1
 309.853515625 303.969726562 315.4921875 275.063476562 315.4921875 247.918945312 c 0
 315.4921875 65.9833984375 62.1962890625 -36.8642578125 30 -170 c 1
 0 -170 l 1
 0 343 l 17
30 0 m 1
 100.569335938 0 291.692382812 107.536132812 291.692382812 301.635742188 c 0
 291.692382812 308.3203125 291.465820312 315.108398438 291 322 c 1
 226 196 56 109 30 0 c 1
30 171 m 1
 100.569335938 171 291.692382812 278.536132812 291.692382812 472.635742188 c 0
 291.692382812 479.3203125 291.465820312 486.108398438 291 493 c 1
 226 367 56 280 30 171 c 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE246
Encoding: 54 57926 54
Width: 315
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 -344 m 9
 0 340 l 1
 30 340 l 1
 62.1962890625 206.864257812 315.4921875 104.016601562 315.4921875 -77.9189453125 c 0
 315.4921875 -105.063476562 309.853515625 -133.969726562 297 -165 c 1
 308.556640625 -191.265625 315.422851562 -219.1875 315.422851562 -249.19921875 c 0
 315.422851562 -276.318359375 309.81640625 -305.145507812 297 -336 c 1
 308.556640625 -362.265625 315.422851562 -390.1875 315.422851562 -420.19921875 c 0
 315.422851562 -447.318359375 309.81640625 -476.145507812 297 -507 c 1
 308.7109375 -533.232421875 315.594726562 -561.000976562 315.594726562 -590.922851562 c 0
 315.594726562 -624.875976562 306.73046875 -661.6015625 286 -702 c 1
 289.740234375 -681.993164062 291.475585938 -662.758789062 291.475585938 -644.3125 c 0
 291.475585938 -450.700195312 100.301757812 -344 30 -344 c 1
 0 -344 l 9
30 -173 m 1
 56 -281 226 -368 291 -494 c 1
 291.465820312 -487.108398438 291.692382812 -480.3203125 291.692382812 -473.635742188 c 0
 291.692382812 -279.536132812 100.569335938 -173 30 -173 c 1
30 -2 m 1
 56 -110 226 -197 291 -323 c 1
 291.465820312 -316.108398438 291.692382812 -309.3203125 291.692382812 -302.635742188 c 0
 291.692382812 -108.536132812 100.569335938 -2 30 -2 c 1
30 169 m 1
 56 62 226 -26 291 -152 c 1
 291.465820312 -145.108398438 291.692382812 -138.3203125 291.692382812 -131.635742188 c 0
 291.692382812 62.4638671875 100.569335938 169 30 169 c 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE247
Encoding: 55 57927 55
Width: 315
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 -370 m 9
 0 314 l 1
 30 314 l 1
 100.301757812 314 291.475585938 420.700195312 291.475585938 614.3125 c 0
 291.475585938 632.758789062 289.740234375 651.993164062 286 672 c 1
 306.73046875 631.6015625 315.594726562 594.875976562 315.594726562 560.922851562 c 0
 315.594726562 531.000976562 308.7109375 503.232421875 297 477 c 1
 309.81640625 446.145507812 315.422851562 417.318359375 315.422851562 390.19921875 c 0
 315.422851562 360.1875 308.556640625 332.265625 297 306 c 1
 309.81640625 275.145507812 315.422851562 246.318359375 315.422851562 219.19921875 c 0
 315.422851562 189.1875 308.556640625 161.265625 297 135 c 1
 309.853515625 103.969726562 315.4921875 75.0634765625 315.4921875 47.9189453125 c 0
 315.4921875 -134.016601562 62.1962890625 -236.864257812 30 -370 c 1
 0 -370 l 9
30 -200 m 5
 100.569335938 -200 291.692382812 -92.4638671875 291.692382812 101.635742188 c 0
 291.692382812 108.3203125 291.465820312 115.108398438 291 122 c 5
 226 -4 56 -91 30 -200 c 5
30 -29 m 1
 100.569335938 -29 291.692382812 78.5361328125 291.692382812 272.635742188 c 0
 291.692382812 279.3203125 291.465820312 286.108398438 291 293 c 1
 226 167 56 81 30 -29 c 1
30 142 m 1
 100.569335938 142 291.692382812 249.536132812 291.692382812 443.635742188 c 0
 291.692382812 450.3203125 291.465820312 457.108398438 291 464 c 1
 226 338 56 251 30 142 c 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE248
Encoding: 56 57928 56
Width: 315
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 -325 m 9
 0 530 l 1
 30 530 l 1
 62.1962890625 396.864257812 315.4921875 294.016601562 315.4921875 112.081054688 c 0
 315.4921875 84.9365234375 309.853515625 56.0302734375 297 25 c 1
 308.556640625 -1.265625 315.422851562 -29.1875 315.422851562 -59.19921875 c 0
 315.422851562 -86.318359375 309.81640625 -115.145507812 297 -146 c 1
 308.556640625 -172.265625 315.422851562 -200.1875 315.422851562 -230.19921875 c 0
 315.422851562 -257.318359375 309.81640625 -286.145507812 297 -317 c 1
 308.556640625 -343.265625 315.422851562 -371.1875 315.422851562 -401.19921875 c 0
 315.422851562 -428.318359375 309.81640625 -457.145507812 297 -488 c 1
 308.7109375 -514.232421875 315.594726562 -542.000976562 315.594726562 -571.922851562 c 0
 315.594726562 -605.875976562 306.73046875 -642.6015625 286 -683 c 1
 289.740234375 -662.993164062 291.475585938 -643.758789062 291.475585938 -625.3125 c 0
 291.475585938 -431.700195312 100.301757812 -325 30 -325 c 1
 0 -325 l 9
30 -154 m 1
 56 -262 226 -349 291 -475 c 1
 291.465820312 -468.108398438 291.692382812 -461.3203125 291.692382812 -454.635742188 c 0
 291.692382812 -260.536132812 100.569335938 -154 30 -154 c 1
30 17 m 1
 56 -91 226 -178 291 -304 c 1
 291.465820312 -297.108398438 291.692382812 -290.3203125 291.692382812 -283.635742188 c 0
 291.692382812 -89.5361328125 100.569335938 17 30 17 c 1
30 188 m 1
 56 80 226 -7 291 -133 c 1
 291.465820312 -126.108398438 291.692382812 -119.3203125 291.692382812 -112.635742188 c 0
 291.692382812 81.4638671875 100.569335938 188 30 188 c 1
30 359 m 1
 56 252 226 164 291 38 c 1
 291.465820312 44.8916015625 291.692382812 51.6796875 291.692382812 58.3642578125 c 0
 291.692382812 252.463867188 100.569335938 359 30 359 c 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE249
Encoding: 57 57929 57
Width: 315
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 -580 m 9
 0 275 l 1
 30 275 l 1
 100.301757812 275 291.475585938 381.700195312 291.475585938 575.3125 c 0
 291.475585938 593.758789062 289.740234375 612.993164062 286 633 c 1
 306.73046875 592.6015625 315.594726562 555.875976562 315.594726562 521.922851562 c 0
 315.594726562 492.000976562 308.7109375 464.232421875 297 438 c 1
 309.81640625 407.145507812 315.422851562 378.318359375 315.422851562 351.19921875 c 0
 315.422851562 321.1875 308.556640625 293.265625 297 267 c 1
 309.81640625 236.145507812 315.422851562 207.318359375 315.422851562 180.19921875 c 0
 315.422851562 150.1875 308.556640625 122.265625 297 96 c 1
 309.81640625 65.1455078125 315.422851562 36.318359375 315.422851562 9.19921875 c 0
 315.422851562 -20.8125 308.556640625 -48.734375 297 -75 c 1
 309.853515625 -106.030273438 315.4921875 -134.936523438 315.4921875 -162.081054688 c 0
 315.4921875 -344.016601562 62.1962890625 -446.864257812 30 -580 c 1
 0 -580 l 9
30 -410 m 5
 100.569335938 -410 291.692382812 -302.463867188 291.692382812 -108.364257812 c 0
 291.692382812 -101.6796875 291.465820312 -94.8916015625 291 -88 c 5
 226 -214 56 -301 30 -410 c 5
30 -239 m 1
 100.569335938 -239 291.692382812 -131.463867188 291.692382812 62.6357421875 c 0
 291.692382812 69.3203125 291.465820312 76.1083984375 291 83 c 1
 226 -43 56 -129 30 -239 c 1
30 -68 m 1
 100.569335938 -68 291.692382812 39.5361328125 291.692382812 233.635742188 c 0
 291.692382812 240.3203125 291.465820312 247.108398438 291 254 c 1
 226 128 56 41 30 -68 c 1
30 103 m 1
 100.569335938 103 291.692382812 210.536132812 291.692382812 404.635742188 c 0
 291.692382812 411.3203125 291.465820312 418.108398438 291 425 c 1
 226 299 56 213 30 103 c 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE260
Encoding: 35 57952 35
Encoding: 58 57952 58
Width: 269
Flags: W
Flags: HMW
HStem: 122 38<116.669 186.23>
VStem: 50 35<-129 103.906 108 432> 203 66<-1.30317 108.888>
LayerCount: 2
Fore
SplineSet
148 122 m 0
 122 122 85 99 85 74 c 2
 85 -129 l 1
 103 -127 128 -103 157 -60 c 1
 187 -19 203 22 203 57 c 0
 203 92 179 122 148 122 c 0
178 160 m 0
 222 160 269 124 269 75 c 0
 269 28 243 -20 190 -74 c 0
 136 -128 84 -156 50 -156 c 1
 50 40 50 236 50 432 c 1
 85 432 l 1
 85 108 l 1
 108 142 138 160 178 160 c 0
103 122 m 0
 77 122 40 90 40 65 c 2
 40 -120 l 1
 58 -112 83 -92 112 -49 c 1
 142 -8 155 22 155 57 c 0
 155 92 134 122 103 122 c 0
133 160 m 0
 177 160 225 124 225 75 c 0
 225 28 203 -20 150 -74 c 0
 96 -128 40 -156 0 -156 c 1
 0 432 l 1
 40 432 l 1
 40 108 l 1
 63 142 93 160 133 160 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE261
Encoding: 36 57953 36
Encoding: 59 57953 59
Width: 200
Flags: W
VStem: 0 28<-101 49 146 376> 172 25<-378 -152 -56 94>
LayerCount: 2
Fore
SplineSet
28 -101 m 1
︙
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











1332
1333
1334
1335
1336
1337

1338
1339
1340
1341
1342
1343
1344
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







-
-
-
+
+
+
-



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





-
+







 1 377 l 1
 28 378 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE262
Encoding: 37 57954 37
Width: 269
Flags: W
Encoding: 60 57954 60
Width: 255
Flags: HMW
VStem: 57 25<-369 -194 -103 71 164 334> 184 24<-328 -158 -68 106 198 373>
LayerCount: 2
Fore
SplineSet
82 77 m 17
 82 -103 l 1
 184 -75 l 1
 184 106 l 1
 82 77 l 17
82 -369 m 1
 57 -369 l 1
 57 -194 l 1
 0 -211 l 1
 0 -126 l 1
 57 -112 l 1
 57 71 l 1
 0 55 l 1
 0 142 l 1
 57 156 l 1
 57 334 l 1
 82 334 l 1
 82 164 l 1
 184 190 l 1
 184 373 l 1
 208 373 l 1
83 70 m 21
 83 -97 l 5
 173 -70 l 5
 173 97 l 5
 83 70 l 21
83 -360 m 5
 53 -360 l 5
 53 -197 l 5
 0 -212 l 5
 0 -120 l 5
 53 -105 l 5
 53 62 l 5
 0 47 l 5
 0 137 l 5
 53 152 l 5
 53 320 l 5
 83 320 l 5
 83 161 l 5
 173 189 l 5
 173 360 l 5
 202 360 l 5
 202 197 l 5
 255 212 l 5
 208 198 l 1
 268 213 l 1
 268 130 l 1
 208 112 l 1
 208 -68 l 1
 268 -53 l 1
 268 -136 l 1
 208 -151 l 1
 208 -328 l 1
 184 -328 l 1
 184 -158 l 1
 82 -187 l 1
 82 -369 l 1
 255 120 l 5
 202 105 l 5
 202 -62 l 5
 255 -47 l 5
 255 -137 l 5
 202 -152 l 5
 202 -320 l 5
 173 -320 l 5
 173 -161 l 5
 83 -189 l 5
 83 -360 l 5
EndSplineSet
Validated: 1
EndChar

StartChar: uniE263
Encoding: 38 57955 38
Encoding: 61 57955 61
Width: 267
Flags: W
HStem: -124 74<20 77 210 267> 50 72<20 77 210 267>
VStem: 20 72<-124 -65 65 122> 195 72<-124 -65 65 122>
LayerCount: 2
Fore
SplineSet
︙
1368
1369
1370
1371
1372
1373
1374
1375

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







-
+

-
+
-
-





-
-
+
+
















-
-
+
+



















-
+







 267 -124 l 1
 195 -124 l 9
EndSplineSet
Validated: 1
EndChar

StartChar: uniE264
Encoding: 39 57956 39
Encoding: 62 57956 62
Width: 366
Flags: W
Flags: HMW
HStem: 125 38<53.6461 109.57 242.595 296.832>
VStem: 0 31<-125 432> 122 54<-4.60115 110.015> 189 30<-125 432> 311 53<-2.92645 109.746>
LayerCount: 2
Fore
SplineSet
78 125 m 1
 55 124 31 100 31 78 c 2
 31 -125 l 1
 43 -125 54 -108 75 -79 c 0
 31 -120 l 1
 43 -120 54 -108 75 -79 c 0
 96 -50 110 -19 118 16 c 0
 122 29 122 42 122 54 c 0
 122 72 119 90 112 104 c 1
 102 117 90 125 79 125 c 2
 78 125 l 1
104 163 m 0
 144 163 176 116 176 73 c 0
 176 57 172 41 167 23 c 1
 150 -17 128 -52 100 -86 c 0
 71 -121 33 -150 0 -150 c 1
 0 432 l 1
 31 432 l 1
 31 113 l 1
 47 145 68 163 104 163 c 0
265 125 m 1
 242 124 219 100 219 78 c 2
 219 -125 l 1
 230 -125 244 -108 265 -79 c 0
 219 -120 l 5
 230 -120 244 -108 265 -79 c 0
 283 -50 297 -19 305 16 c 0
 309 29 311 42 311 54 c 0
 311 72 307 90 300 104 c 1
 290 117 280 125 269 125 c 2
 265 125 l 1
291 163 m 0
 333 163 364 119 364 73 c 0
 364 57 360 41 353 23 c 0
 337 -17 317 -52 288 -86 c 1
 260 -121 219 -150 189 -150 c 1
 189 432 l 1
 219 432 l 1
 219 113 l 1
 235 143 256 163 291 163 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE280
Encoding: 40 57984 40
Encoding: 63 57984 63
Width: 269
Flags: HMW
LayerCount: 2
Fore
SplineSet
171 122 m 0
 140 122 116 92 116 57 c 0
︙
1440
1441
1442
1443
1444
1445
1446
1447









































































































































1448
1449

1450
1451
1452
1453
1454
1455
1456
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
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
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172

2173
2174
2175
2176
2177
2178
2179
2180








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

-
+







 269 236 269 40 269 -156 c 1
 235 -156 183 -128 129 -74 c 0
 76 -20 50 28 50 75 c 0
 50 124 97 160 141 160 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE281
Encoding: 64 57985 64
Width: 366
Flags: HMW
LayerCount: 2
Fore
SplineSet
87 125 m 1
 86 125 l 2
 75 125 63 117 53 104 c 1
 46 90 43 72 43 54 c 0
 43 42 43 29 47 16 c 0
 55 -19 69 -50 90 -79 c 0
 111 -108 122 -120 134 -120 c 1
 134 78 l 2
 134 100 110 124 87 125 c 1
61 163 m 0
 97 163 118 145 134 113 c 1
 134 432 l 1
 165 432 l 1
 165 -150 l 1
 135 -150 94 -121 65 -86 c 0
 37 -52 15 -17 -2 23 c 1
 -7 41 -11 57 -11 73 c 0
 -11 116 21 163 61 163 c 0
265 125 m 1
 242 124 219 100 219 78 c 2
 219 -120 l 1
 230 -120 244 -108 265 -79 c 0
 283 -50 297 -19 305 16 c 0
 309 29 311 42 311 54 c 0
 311 72 307 90 300 104 c 1
 290 117 280 125 269 125 c 2
 265 125 l 1
291 163 m 0
 333 163 364 119 364 73 c 0
 364 57 360 41 353 23 c 0
 337 -17 317 -52 288 -86 c 1
 260 -121 219 -150 189 -150 c 1
 189 432 l 1
 219 432 l 1
 219 113 l 1
 235 143 256 163 291 163 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE282
Encoding: 65 57986 65
Width: 169
Flags: HMW
LayerCount: 2
Fore
SplineSet
68 320 m 8
 98 320 l 1
 98 158 l 1
 169 172 l 1
 169 80 l 1
 98 66 l 1
 98 -61 l 1
 169 -47 l 1
 169 -137 l 1
 98 -152 l 1
 98 -320 l 8
 68 -320 l 1
 68 -158 l 1
 0 -172 l 1
 0 -80 l 1
 68 -66 l 1
 68 61 l 1
 0 47 l 1
 0 137 l 1
 68 152 l 1
 68 320 l 8
EndSplineSet
Validated: 1
EndChar

StartChar: uniE283
Encoding: 66 57987 66
Width: 314
Flags: HMW
LayerCount: 2
Fore
SplineSet
233 192 m 17
 233 360 l 1
 263 360 l 1
 263 202 l 1
 314 217 l 1
 314 125 l 1
 263 110 l 1
 263 -49 l 1
 314 -34 l 1
 314 -124 l 1
 263 -139 l 1
 263 -320 l 1
 233 -320 l 1
 233 -150 l 1
 172 -168 l 1
 172 -340 l 25
 142 -340 l 25
 142 -176 l 25
 82 -192 l 17
 81 -360 l 1
 51 -360 l 1
 51 -202 l 1
 0 -217 l 1
 0 -125 l 1
 51 -110 l 1
 51 49 l 1
 0 34 l 1
 0 124 l 1
 51 139 l 1
 51 320 l 1
 81 320 l 1
 81 150 l 1
 142 168 l 1
 142 340 l 25
 172 340 l 25
 172 176 l 25
 233 192 l 17
142 -83 m 9
 142 75 l 1
 81 58 l 1
 81 -101 l 1
 142 -83 l 9
172 83 m 9
 172 -75 l 1
 233 -58 l 1
 233 101 l 1
 172 83 l 9
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4A0
Encoding: 41 58528 41
Encoding: 67 58528 67
Width: 320
Flags: W
HStem: 0 244<5 15>
VStem: -3 322
LayerCount: 2
Fore
SplineSet
︙
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

1545
1546
1547
1548
1549
1550
1551


1552
1553
1554
1555
1556
1557
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
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595

1596
1597

1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613

1614
1615

1616
1617
1618
1619
1620
1621
1622
1623
1624
2191
2192
2193
2194
2195
2196
2197
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
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
2310
2311
2312

2313
2314

2315

2316
2317
2318
2319


2320
2321
2322
2323
2324
2325
2326
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
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








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

-
+



















-
+

-
+
-
-






-
-
-
+
+
+

-
-
-
-
-
+
+
+
+
+





-
+

















+



-
+

-
+
-




-
-
+
+







-
+

-
+
-
-













-
+

-
+
-
-













-
+

-
+
-
-













-
+

-
+
-
-







 305 136 l 1
 314 132 319 124 319 116 c 0
 319 109 314 101 305 98 c 1
 18 1 l 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4A2
Encoding: 68 58530 68
Width: 80
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 40 m 24
 0 63 17 80 40 80 c 24
 62 80 80 63 80 40 c 24
 80 18 63 0 40 0 c 24
 18 0 0 18 0 40 c 24
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4A4
Encoding: 69 58532 69
Width: 320
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 0 m 25
 0 40 l 25
 320 40 l 25
 320 0 l 25
 0 0 l 25
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4A8
Encoding: 70 58536 70
Width: 320
Flags: HMW
LayerCount: 2
Fore
SplineSet
40 0 m 29
 0 280 l 25
 100 280 l 25
 60 0 l 25
 40 0 l 29
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4AC
Encoding: 42 58540 42
Encoding: 71 58540 71
Width: 280
Flags: W
HStem: 0 309
VStem: 0 280
LayerCount: 2
Fore
SplineSet
0 0 m 1
 140 309 l 25
 280 0 l 1
 215 0 l 1
 127 198 l 25
 37 0 l 1
 0 0 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4C0
Encoding: 43 58560 43
Encoding: 72 58560 72
Width: 600
Flags: W
Flags: HMW
HStem: 0 120<253.391 344.66> 244 86<189.458 410.542>
VStem: 0 10<0 27.4595> 239 120<15.0142 104.986> 590 10<0 27.4595>
LayerCount: 2
Fore
SplineSet
0 0 m 1
 0 214 150 330 300 330 c 3
 450 330 600 213 600 0 c 1
 590 0 l 1
 575 150 446 244 300 244 c 3
 154 244 25 150 10 0 c 1
 585 0 l 5
 570 150 446 244 300 244 c 3
 154 244 30 150 15 0 c 1
 0 0 l 1
299 0 m 7
 268 0 239 28 239 60 c 7
 239 92 268 120 299 120 c 7
 332 120 359 92 359 60 c 7
 359 27 333 0 299 0 c 7
299 0 m 3
 268 0 239 28 239 60 c 3
 239 92 268 120 299 120 c 3
 332 120 359 92 359 60 c 3
 359 27 333 0 299 0 c 3
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4CE
Encoding: 44 58574 44
Encoding: 73 58574 73
Width: 182
Flags: HMW
LayerCount: 2
Fore
SplineSet
86 301 m 0
 123 301 136 294 156 272 c 0
 175 251 182 226 182 195 c 0
 182 152 162 110 132 74 c 0
 97 34 43 0 23 0 c 0
 21 0 19 2 17 3 c 0
 16 4 16 5 16 6 c 0
 16 26 87 105 87 140 c 0
 87 149 81 155 67 155 c 0
 32 156 -0 184 -0 222 c 0
 -0 258 27 301 86 301 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4E1
Encoding: 45 58593 45
Encoding: 74 58593 74
Width: 130
Flags: W
Flags: HMW
VStem: 0 130<-250 250>
LayerCount: 2
Fore
SplineSet
0 250 m 1
 128 250 l 1
 130 -250 l 1
 130 250 l 1
 130 -250 l 5
 0 -250 l 1
 0 250 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4E2
Encoding: 46 58594 46
Encoding: 75 58594 75
Width: 130
Flags: W
Flags: MW
HStem: 0 250<0 130>
VStem: 0 130<0 250>
LayerCount: 2
Fore
SplineSet
0 250 m 1
 130 250 l 1
 130 0 l 1
 0 0 l 1
 0 250 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4E3
Encoding: 47 58595 47
Encoding: 76 58595 76
Width: 300
Flags: W
Flags: MW
HStem: -125 125<0 300>
VStem: 0 300<-125 0>
LayerCount: 2
Fore
SplineSet
0 0 m 1
 300 0 l 1
 300 -125 l 1
 0 -125 l 1
 0 0 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4E4
Encoding: 48 58596 48
Encoding: 77 58596 77
Width: 300
Flags: W
Flags: MW
HStem: 0 125<0 300>
VStem: 0 300<0 125>
LayerCount: 2
Fore
SplineSet
0 125 m 1
 300 125 l 1
 300 0 l 1
 0 0 l 1
 0 125 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4E5
Encoding: 49 58597 49
Encoding: 78 58597 78
Width: 238
Flags: W
Flags: MW
HStem: -216 62<79.4562 172.905>
VStem: 0 64<-298.233 -231.781>
LayerCount: 2
Fore
SplineSet
41 391 m 1
 230 162 l 1
 127 -55 l 1
 235 -262 l 1
︙
1632
1633
1634
1635
1636
1637
1638
1639

1640
1641
1642
1643
1644
1645
1646
2394
2395
2396
2397
2398
2399
2400

2401
2402
2403
2404
2405
2406
2407
2408







-
+







 122 193 l 1
 41 391 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4E6
Encoding: 50 58598 50
Encoding: 79 58598 79
Width: 255
Flags: W
HStem: 48 33<112 170.038>
VStem: 0 135<81.9955 177.625>
LayerCount: 2
Fore
SplineSet
︙
1656
1657
1658
1659
1660
1661
1662
1663

1664
1665
1666
1667
1668
1669
1670
2418
2419
2420
2421
2422
2423
2424

2425
2426
2427
2428
2429
2430
2431
2432







-
+







 58 -227 l 1
 171 60 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4E7
Encoding: 51 58599 51
Encoding: 80 58599 80
Width: 329
Flags: W
HStem: -208 32<112 170.069> 48 33<184 242.918>
VStem: 0 135<-174.731 -78.875> 72 135<81.9955 177.625>
LayerCount: 2
Fore
SplineSet
︙
1687
1688
1689
1690
1691
1692
1693
1694

1695
1696
1697
1698
1699
1700
1701
2449
2450
2451
2452
2453
2454
2455

2456
2457
2458
2459
2460
2461
2462
2463







-
+







 86 -488 l 1
 171 -196 l 1xd0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4E8
Encoding: 52 58600 52
Encoding: 81 58600 81
Width: 399
Flags: W
HStem: -208 32<112 170.069> 48 32<189 245.07> 304 33<255 314.117>
VStem: 0 135<-174.731 -78.875> 77 135<81.2688 177.125> 143 135<337.996 433.625>
LayerCount: 2
Fore
SplineSet
︙
1725
1726
1727
1728
1729
1730
1731
1732

1733
1734
1735
1736
1737
1738
1739
2487
2488
2489
2490
2491
2492
2493

2494
2495
2496
2497
2498
2499
2500
2501







-
+







 158 -176 182 -160 188 -142 c 1
 246 60 l 1xf4
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4E9
Encoding: 53 58601 53
Encoding: 82 58601 82
Width: 472
Flags: W
HStem: -464 32<112 170.069> -208 32<187 245.069> 48 32<264 320.07> 304 33<330 389.117>
VStem: 0 135<-430.731 -334.875> 75 135<-174.731 -78.875> 152 135<81.2688 177.125> 218 135<337.996 433.625>
LayerCount: 2
Fore
SplineSet
︙
1770
1771
1772
1773
1774
1775
1776
1777

1778
1779
1780
1781
1782
1783
1784
2532
2533
2534
2535
2536
2537
2538

2539
2540
2541
2542
2543
2544
2545
2546







-
+







 86 -744 l 1
 171 -452 l 1xf1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4EA
Encoding: 54 58602 54
Encoding: 83 58602 83
Width: 472
Flags: W
HStem: -464 32<112 170.069> -210 32<187 245.069> 40 32<260 318.069> 290 32<333 389.07> 542 33<393 452.117>
VStem: 0 135<-430.731 -334.875> 75 135<-176.731 -80.875> 148 135<73.2688 169.125> 221 135<323.269 419.125> 281 135<575.996 671.625>
LayerCount: 2
Fore
SplineSet
︙
1822
1823
1824
1825
1826
1827
1828
1829

1830
1831
1832
1833
1834
1835
1836
2584
2585
2586
2587
2588
2589
2590

2591
2592
2593
2594
2595
2596
2597
2598







-
+







 233 -178 257 -162 263 -144 c 1
 319 52 l 1xfa
EndSplineSet
Validated: 1
EndChar

StartChar: uniE4EE
Encoding: 55 58606 55
Encoding: 84 58606 84
Width: 851
Flags: W
HStem: -105 210<25 825>
VStem: 0 25<-230 -105 105 230> 825 25<-230 -105 105 230>
LayerCount: 2
Fore
SplineSet
︙
1848
1849
1850
1851
1852
1853
1854
1855

1856
1857
1858
1859
1860
1861
1862
2610
2611
2612
2613
2614
2615
2616

2617
2618
2619
2620
2621
2622
2623
2624







-
+







 0 -230 l 25
 0 230 l 25
EndSplineSet
Validated: 1
EndChar

StartChar: uniE500
Encoding: 56 58624 56
Encoding: 85 58624 85
Width: 563
Flags: W
HStem: -195 120<435.745 528.255> 75 120<8.74536 101.255>
VStem: -5 120<88.7454 181.255> 422 120<-181.255 -88.7454>
LayerCount: 2
Fore
SplineSet
︙
1876
1877
1878
1879
1880
1881
1882
1883

1884
1885
1886
1887
1888
1889
1890
2638
2639
2640
2641
2642
2643
2644

2645
2646
2647
2648
2649
2650
2651
2652







-
+







 109 -250 l 1
 -16 -250 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE501
Encoding: 57 58625 57
Encoding: 86 58625 86
Width: 800
Flags: W
HStem: -195 120<659.745 752.255> 75 120<-6.25464 86.2546>
VStem: -20 120<88.7454 181.255> 646 120<-181.255 -88.7454>
LayerCount: 2
Fore
SplineSet
︙
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




1948
1949
1950
1951
1952
1953

1954
1955
1956
1957
1958
1959
1960
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
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
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
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
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
2893
2894
2895
2896
2897
2898
2899
2900
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
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
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
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
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
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
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
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
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618

3619
3620
3621


3622
3623
3624
3625
3626







3627
3628
3629
3630
3631
3632
3633
3634










3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646




3647
3648
3649
3650
3651
3652
3653
3654
3655

3656
3657
3658
3659
3660
3661
3662
3663







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


-
+


-
-
+
+



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

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


-
-
-
-
+
+
+
+





-
+







 652 250 l 5
 775 250 l 5
 334 -250 l 5
 212 -250 l 5
EndSplineSet
Validated: 1
EndChar

StartChar: uniE520
Encoding: 87 58656 87
Width: 563
Flags: HMW
LayerCount: 2
Fore
SplineSet
197 40 m 0
 199.179123831 39.0525548563 201.555731167 38.5988184777 204.0907001 38.5988184777 c 0
 228.311569742 38.5988184777 266.989634802 80.0214592618 286 128 c 0
 293.801273837 147.763227053 298.897664408 174.829638922 298.897664408 197.52305288 c 0
 298.897664408 218.46369363 294.558131706 235.680764302 284 240 c 0
 282.059714009 240.759242344 279.934395026 241.11995209 277.659464452 241.11995209 c 0
 252.96754404 241.11995209 210.650235832 198.625589581 196 162 c 0
 185.665333312 135.693575703 181.068143327 108.945807045 181.068143327 87.1471403297 c 0
 181.068143327 62.5417301443 186.925393958 44.2419393862 197 40 c 0
200 0 m 0
 183 0 173 6 153 32 c 1
 108 -90 l 1
 160 -90 l 2
 175 -90 175 -120 160 -120 c 0
 -65 -120 l 0
 -79 -120 -80 -90 -65 -90 c 2
 10 -90 l 1
 114 195 l 0
 115.167116963 197.917792406 120.420719938 212.754502351 120.420719938 224.605732511 c 0
 120.420719938 233.06305846 117.745271893 240 109 240 c 0
 83 240 72 207 28 135 c 0
 21 124 -6 139 1 151 c 0
 56 249 69 280 125 280 c 0
 170 280 193 271 203 235 c 1
 244 278 263 280 305 280 c 0
 341 280 380 248 380 180 c 0
 380 87 299 0 200 0 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE521
Encoding: 88 58657 88
Width: 440
Flags: W
HStem: -10 44.404<309.482 391.648> 0 21G<-1 65.5 153 199> 212.877 67.1232<170.507 229.008 295.16 358.649> 221 59<37.7036 99.8884>
VStem: 276.686 77.1955<12.819 101.414> 335.007 74.6509<146.188 236.074>
LayerCount: 2
Fore
SplineSet
80 21 m 0x64
 76 11 74 1 57 0 c 0
 4 0 l 0
 -6 0 0 18 4 26 c 1
 70 193 l 0
 77 211 69 221 60 221 c 0
 42 221 35 210 -11 138 c 0
 -18 127 -39 139 -33 151 c 0
 3 216 36 280 86 280 c 0x54
 128 280 145 266 152 240 c 1
 170 260 194 280 224 280 c 0
 254 280 273 263 278 240 c 1
 292 259 322 280 349 280 c 0
 382.297060451 280 409.658220776 253.618221661 409.658220776 218.530504648 c 0x24
 409.658220776 210.41331474 408.193901764 201.830198995 405 193 c 0
 358 68 l 0
 355.211869734 60.3326417674 353.881302664 53.2726015335 353.881302664 47.6241881024 c 0
 353.881302664 39.5840041338 356.577277218 34.4040367054 361.602949871 34.4040367054 c 0
 363.177144158 34.4040367054 364.979913018 34.9122608557 367 36 c 0
 389 48 404 72 419 93 c 0
 427 104 449 93 440 78 c 0
 411 27 388 -10 323 -10 c 0
 295.96461562 -10 276.685848474 4.31990873934 276.685848474 30.6552962356 c 0xa8
 276.685848474 38.4136929968 278.359032859 47.2149008096 282 57 c 0
 334 193 l 0
 334.687448544 195.062345631 335.007330587 196.961328373 335.007330587 198.698285174 c 0
 335.007330587 208.224115412 325.386390673 212.876768553 314.009865299 212.876768553 c 0
 300.302784706 212.876768553 284.047157224 206.122608782 279 193 c 0
 214 22 l 0
 211 14 207 0 191 -1 c 1
 153 0 l 16
 134 -2 132 12 136 22 c 0
 203 193 l 0
 203.698722351 195.018531237 204.023750859 196.886379473 204.023750859 198.6021409 c 0
 204.023750859 208.040661137 194.187819777 212.876768553 182.617370253 212.876768553 c 0
 169.199127766 212.876768553 153.448127054 206.372675496 148 193 c 0
 80 21 l 0x64
EndSplineSet
Validated: 1
EndChar

StartChar: uniE522
Encoding: 89 58658 89
Width: 351
Flags: HMW
LayerCount: 2
Fore
SplineSet
-50 -160 m 0
 -90 -160 -130 -135 -130 -90 c 0
 -130 -55 -113 -30 -88 -30 c 0
 -63 -30 -47 -45 -47 -65 c 0
 -47 -75 -54 -83 -65 -90 c 0
 -75 -97 -75 -100 -75 -110 c 0
 -75 -120 -65 -124 -50 -124 c 0
 13 -124 16 -35 83 230 c 1
 64 230 65 230 30 230 c 0
 17.239470207 230 10.992185238 240.421191718 10.992185238 250.625180963 c 0
 10.992185238 260.412503619 16.7396874095 270 28 270 c 0
 59 270 61 270 93 270 c 1
 121 374 204 440 270 440 c 0
 310 440 350 415 350 370 c 0
 350 335 333 310 308 310 c 0
 283 310 267 325 267 345 c 0
 267 355 274 363 285 370 c 0
 296 377 295 380 295 390 c 0
 295 400 285 404 270 404 c 0
 228 404 218 332 205 270 c 1
 232 270 229 270 259 270 c 0
 272 270 278.5 260 278.5 250 c 0
 278.5 240 272 230 259 230 c 0
 233 230 229 230 196 230 c 1
 153 -26 80 -160 -50 -160 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE524
Encoding: 90 58660 90
Width: 563
Flags: W
HStem: 0 30<56.2969 128.192> 250 30<86.1231 145.206>
VStem: 0 67<48.3332 106.102> 30 50<188.851 246.418> 140 60<38.2418 104.228> 145.315 72.6848<183.703 229.735>
LayerCount: 2
Fore
SplineSet
80 0 m 0xd8
 41 0 0 33 0 70 c 0xe0
 0 92 14 108 30 108 c 0xd0
 47 108 67 100 67 84 c 0
 67 69 62 55 55 48 c 1
 60 34 69 30 85 30 c 0
 113 30 140 45 140 70 c 0xe8
 140 100 116 103 90 120 c 0
 57 141 30 167 30 200 c 0
 30 247 70 280 130 280 c 0
 175 280 218 253 218 220 c 0
 218 199 202 180 180 180 c 0
 163.575188443 180 145.315176651 194.681601887 145.315176651 213.518742217 c 0xd4
 145.315176651 218.765893239 146.732008255 224.335480975 150 230 c 1
 142 240 133 250 120 250 c 0
 101 250 80 239 80 220 c 0
 80 193 127 175 150 160 c 0
 184 137 200 120 200 90 c 0
 200 26 156 0 80 0 c 0xd8
EndSplineSet
Validated: 1
EndChar

StartChar: uniE525
Encoding: 91 58661 91
Width: 563
Flags: HMW
LayerCount: 2
Fore
SplineSet
-10 3 m 0
 -22 -6 -34 16 -23 26 c 0
 153 219 l 0
 141.918058124 224.910369 126.469558534 226.454180286 105.444752759 226.454180286 c 0
 98.0113613903 226.454180286 89.8809317488 226.261203875 81 226 c 0
 70 226 47 173 34 162 c 0
 20 150 6 154 20 187 c 0
 41 238 38 251 44 267 c 1
 79.2709584661 264.544426942 105.57190844 263.63368868 125.594979066 263.63368868 c 0
 183.112330324 263.63368868 188.827343421 271.148705903 206.551743542 271.148705903 c 0
 210.297411805 271.148705903 214.579415356 270.813087697 220 270 c 0
 235 268 233 254 224 245 c 0
 66 78 l 0
 64.6486486486 74.6216216216 63.972972973 72.1015339664 63.972972973 70.1929599431 c 0
 63.972972973 57.9780861943 91.6486486486 70.8108108108 147 44 c 0
 158 39 168 52 164 64 c 0
 157 84 125 65 125 100 c 0
 125 115 141 130 157 130 c 0
 177 130 195 117 195 75 c 0
 195 36.9571906054 164.866783384 2.35817739562 123.772791397 2.35817739562 c 0
 120.578422501 2.35817739562 117.317823606 2.5672403992 114 3 c 0
 69.8119048549 8.52351189314 48.9765181701 18.5669028431 29.7645164434 18.5669028431 c 0
 17.6725183082 18.5669028431 6.22361116537 14.5882936895 -10 3 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE529
Encoding: 92 58665 92
Width: 703
Flags: HMW
LayerCount: 2
Fore
SplineSet
522 40 m 0
 524.179123831 39.0525548563 526.555731167 38.5988184777 529.0907001 38.5988184777 c 0
 553.311569742 38.5988184777 591.989634802 80.0214592618 611 128 c 0
 618.801273837 147.763227053 623.897664408 174.829638922 623.897664408 197.52305288 c 0
 623.897664408 218.46369363 619.558131706 235.680764302 609 240 c 0
 607.059714009 240.759242344 604.934395026 241.11995209 602.659464452 241.11995209 c 0
 577.96754404 241.11995209 535.650235832 198.625589581 521 162 c 0
 510.665333312 135.693575703 506.068143327 108.945807045 506.068143327 87.1471403297 c 0
 506.068143327 62.5417301443 511.925393958 44.2419393862 522 40 c 0
197 40 m 0
 199.179123831 39.0525548563 201.555731167 38.5988184777 204.0907001 38.5988184777 c 0
 228.311569742 38.5988184777 266.989634802 80.0214592618 286 128 c 0
 293.801273837 147.763227053 298.897664408 174.829638922 298.897664408 197.52305288 c 0
 298.897664408 218.46369363 294.558131706 235.680764302 284 240 c 0
 282.059714009 240.759242344 279.934395026 241.11995209 277.659464452 241.11995209 c 0
 252.96754404 241.11995209 210.650235832 198.625589581 196 162 c 0
 185.665333312 135.693575703 181.068143327 108.945807045 181.068143327 87.1471403297 c 0
 181.068143327 62.5417301443 186.925393958 44.2419393862 197 40 c 0
200 0 m 0
 183 0 173 6 153 32 c 1
 108 -90 l 1
 160 -90 l 2
 175 -90 175 -120 160 -120 c 2
 -65 -120 l 2
 -79 -120 -80 -90 -65 -90 c 2
 10 -90 l 1
 114 195 l 2
 115.167116963 197.917792406 120.420719938 212.754502351 120.420719938 224.605732511 c 0
 120.420719938 233.06305846 117.745271893 240 109 240 c 0
 83 240 72 207 28 135 c 0
 21 124 -6 139 1 151 c 0
 56 249 69 280 125 280 c 0
 170 280 193 271 203 235 c 1
 244 278 263 280 305 280 c 0
 331 280 358 264 371 230 c 1
 395 267 413 280 450 280 c 0
 495 280 518 271 528 235 c 1
 569 278 588 280 630 280 c 0
 656 280 683 264 696 230 c 1
 720 267 738 280 775 280 c 0
 820 280 843 271 853 235 c 1
 894 278 913 280 955 280 c 0
 981 280 1008 264 1021 230 c 1
 1045 267 1063 280 1100 280 c 0
 1145 280 1168 271 1178 235 c 1
 1219 278 1238 280 1280 280 c 0
 1316 280 1355 248 1355 180 c 0
 1355 87 1274 0 1175 0 c 0
 1158 0 1148 6 1128 32 c 1
 1083 -90 l 1
 1135 -90 l 2
 1150 -90 1150 -120 1135 -120 c 2
 910 -120 l 2
 896 -120 895 -90 910 -90 c 2
 985 -90 l 1
 1089 195 l 2
 1090.16711696 197.917792406 1095.42071994 212.754502351 1095.42071994 224.605732511 c 0
 1095.42071994 233.06305846 1092.74527189 240 1084 240 c 0
 1064 240 1053 221 1030 181 c 0
 1030 181 1030 180 1030 180 c 0
 1030 87 949 0 850 0 c 0
 833 0 823 6 803 32 c 1
 758 -90 l 1
 810 -90 l 2
 825 -90 825 -120 810 -120 c 2
 585 -120 l 2
 571 -120 570 -90 585 -90 c 2
 660 -90 l 1
 764 195 l 2
 765.167116963 197.917792406 770.420719938 212.754502351 770.420719938 224.605732511 c 0
 770.420719938 233.06305846 767.745271893 240 759 240 c 0
 739 240 728 221 705 181 c 0
 705 181 705 180 705 180 c 0
 705 87 624 0 525 0 c 0
 508 0 498 6 478 32 c 1
 433 -90 l 1
 485 -90 l 2
 500 -90 500 -120 485 -120 c 2
 260 -120 l 2
 246 -120 245 -90 260 -90 c 2
 335 -90 l 1
 439 195 l 2
 440.167116963 197.917792406 445.420719938 212.754502351 445.420719938 224.605732511 c 0
 445.420719938 233.06305846 442.745271893 240 434 240 c 0
 414 240 403 221 380 181 c 0
 380 181 380 180 380 180 c 0
 380 87 299 0 200 0 c 0
1172 40 m 0
 1174.17912383 39.0525548563 1176.55573117 38.5988184777 1179.0907001 38.5988184777 c 0
 1203.31156974 38.5988184777 1241.9896348 80.0214592618 1261 128 c 0
 1268.80127384 147.763227053 1273.89766441 174.829638922 1273.89766441 197.52305288 c 0
 1273.89766441 218.46369363 1269.55813171 235.680764302 1259 240 c 0
 1257.05971401 240.759242344 1254.93439503 241.11995209 1252.65946445 241.11995209 c 0
 1227.96754404 241.11995209 1185.65023583 198.625589581 1171 162 c 0
 1160.66533331 135.693575703 1156.06814333 108.945807045 1156.06814333 87.1471403297 c 0
 1156.06814333 62.5417301443 1161.92539396 44.2419393862 1172 40 c 0
847 40 m 0
 849.179123831 39.0525548563 851.555731167 38.5988184777 854.0907001 38.5988184777 c 0
 878.311569742 38.5988184777 916.989634802 80.0214592618 936 128 c 0
 943.801273837 147.763227053 948.897664408 174.829638922 948.897664408 197.52305288 c 0
 948.897664408 218.46369363 944.558131706 235.680764302 934 240 c 0
 932.059714009 240.759242344 929.934395026 241.11995209 927.659464452 241.11995209 c 0
 902.96754404 241.11995209 860.650235832 198.625589581 846 162 c 0
 835.665333312 135.693575703 831.068143327 108.945807045 831.068143327 87.1471403297 c 0
 831.068143327 62.5417301443 836.925393958 44.2419393862 847 40 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE52A
Encoding: 93 58666 93
Width: 563
Flags: W
HStem: -120 30<-74.2249 10 108 169.668 250.775 335 433 494.668 575.775 660 758 819.668> 0 38.5988<191.014 237.319 516.014 562.319 841.014 887.319> 240 40<80.1149 147.5 239.117 318 404.386 472.5 564.117 643 729.386 797.5 889.117 973>
VStem: 120.421 60.6474<87.1471 224.606> 298.898 81.1023<108.679 217.246> 445.421 60.6474<87.1471 224.606> 623.898 81.1023<108.679 217.246> 770.421 60.6474<87.1471 224.606> 948.898 81.1023<108.462 239.669>
LayerCount: 2
Fore
SplineSet
850 0 m 0
 833 0 823 6 803 32 c 1
 758 -90 l 1
 810 -90 l 2
 825 -90 825 -120 810 -120 c 2
 585 -120 l 2
 571 -120 570 -90 585 -90 c 2
 660 -90 l 1
 764 195 l 2
 765.167116963 197.917792406 770.420719938 212.754502351 770.420719938 224.605732511 c 0
 770.420719938 233.06305846 767.745271893 240 759 240 c 0
 739 240 728 221 705 181 c 0
 705 181 705 180 705 180 c 0
 705 87 624 0 525 0 c 0
 508 0 498 6 478 32 c 1
 433 -90 l 1
 485 -90 l 2
 500 -90 500 -120 485 -120 c 2
 260 -120 l 2
 246 -120 245 -90 260 -90 c 2
 335 -90 l 1
 439 195 l 2
 440.167116963 197.917792406 445.420719938 212.754502351 445.420719938 224.605732511 c 0
 445.420719938 233.06305846 442.745271893 240 434 240 c 0
 414 240 403 221 380 181 c 0
 380 181 380 180 380 180 c 0
 380 87 299 0 200 0 c 0
 183 0 173 6 153 32 c 1
 108 -90 l 1
 160 -90 l 2
 175 -90 175 -120 160 -120 c 2
 -65 -120 l 2
 -79 -120 -80 -90 -65 -90 c 2
 10 -90 l 1
 114 195 l 2
 115.167116963 197.917792406 120.420719938 212.754502351 120.420719938 224.605732511 c 0
 120.420719938 233.06305846 117.745271893 240 109 240 c 0
 83 240 72 207 28 135 c 0
 21 124 -6 139 1 151 c 0
 56 249 69 280 125 280 c 0
 170 280 193 271 203 235 c 1
 244 278 263 280 305 280 c 0
 331 280 358 264 371 230 c 1
 395 267 413 280 450 280 c 0
 495 280 518 271 528 235 c 1
 569 278 588 280 630 280 c 0
 656 280 683 264 696 230 c 1
 720 267 738 280 775 280 c 0
 820 280 843 271 853 235 c 1
 894 278 913 280 955 280 c 0
 991 280 1030 248 1030 180 c 0
 1030 87 949 0 850 0 c 0
847 40 m 0
 849.179123831 39.0525548563 851.555731167 38.5988184777 854.0907001 38.5988184777 c 0
 878.311569742 38.5988184777 916.989634802 80.0214592618 936 128 c 0
 943.801273837 147.763227053 948.897664408 174.829638922 948.897664408 197.52305288 c 0
 948.897664408 218.46369363 944.558131706 235.680764302 934 240 c 0
 932.059714009 240.759242344 929.934395026 241.11995209 927.659464452 241.11995209 c 0
 902.96754404 241.11995209 860.650235832 198.625589581 846 162 c 0
 835.665333312 135.693575703 831.068143327 108.945807045 831.068143327 87.1471403297 c 0
 831.068143327 62.5417301443 836.925393958 44.2419393862 847 40 c 0
522 40 m 0
 524.179123831 39.0525548563 526.555731167 38.5988184777 529.0907001 38.5988184777 c 0
 553.311569742 38.5988184777 591.989634802 80.0214592618 611 128 c 0
 618.801273837 147.763227053 623.897664408 174.829638922 623.897664408 197.52305288 c 0
 623.897664408 218.46369363 619.558131706 235.680764302 609 240 c 0
 607.059714009 240.759242344 604.934395026 241.11995209 602.659464452 241.11995209 c 0
 577.96754404 241.11995209 535.650235832 198.625589581 521 162 c 0
 510.665333312 135.693575703 506.068143327 108.945807045 506.068143327 87.1471403297 c 0
 506.068143327 62.5417301443 511.925393958 44.2419393862 522 40 c 0
197 40 m 0
 199.179123831 39.0525548563 201.555731167 38.5988184777 204.0907001 38.5988184777 c 0
 228.311569742 38.5988184777 266.989634802 80.0214592618 286 128 c 0
 293.801273837 147.763227053 298.897664408 174.829638922 298.897664408 197.52305288 c 0
 298.897664408 218.46369363 294.558131706 235.680764302 284 240 c 0
 282.059714009 240.759242344 279.934395026 241.11995209 277.659464452 241.11995209 c 0
 252.96754404 241.11995209 210.650235832 198.625589581 196 162 c 0
 185.665333312 135.693575703 181.068143327 108.945807045 181.068143327 87.1471403297 c 0
 181.068143327 62.5417301443 186.925393958 44.2419393862 197 40 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE52B
Encoding: 94 58667 94
Width: 703
Flags: HMW
LayerCount: 2
Fore
SplineSet
200 0 m 0
 183 0 173 6 153 32 c 1
 108 -90 l 1
 160 -90 l 2
 175 -90 175 -120 160 -120 c 2
 -65 -120 l 2
 -79 -120 -80 -90 -65 -90 c 2
 10 -90 l 1
 114 195 l 2
 115.167116963 197.917792406 120.420719938 212.754502351 120.420719938 224.605732511 c 0
 120.420719938 233.06305846 117.745271893 240 109 240 c 0
 83 240 72 207 28 135 c 0
 21 124 -6 139 1 151 c 0
 56 249 69 280 125 280 c 0
 170 280 193 271 203 235 c 1
 244 278 263 280 305 280 c 0
 331 280 358 264 371 230 c 1
 395 267 413 280 450 280 c 0
 495 280 518 271 528 235 c 1
 569 278 588 280 630 280 c 0
 666 280 705 248 705 180 c 0
 705 87 624 0 525 0 c 0
 508 0 498 6 478 32 c 1
 433 -90 l 1
 485 -90 l 2
 500 -90 500 -120 485 -120 c 2
 260 -120 l 2
 246 -120 245 -90 260 -90 c 2
 335 -90 l 1
 439 195 l 2
 440.167116963 197.917792406 445.420719938 212.754502351 445.420719938 224.605732511 c 0
 445.420719938 233.06305846 442.745271893 240 434 240 c 0
 414 240 403 221 380 181 c 0
 380 181 380 180 380 180 c 0
 380 87 299 0 200 0 c 0
197 40 m 0
 199.179123831 39.0525548563 201.555731167 38.5988184777 204.0907001 38.5988184777 c 0
 228.311569742 38.5988184777 266.989634802 80.0214592618 286 128 c 0
 293.801273837 147.763227053 298.897664408 174.829638922 298.897664408 197.52305288 c 0
 298.897664408 218.46369363 294.558131706 235.680764302 284 240 c 0
 282.059714009 240.759242344 279.934395026 241.11995209 277.659464452 241.11995209 c 0
 252.96754404 241.11995209 210.650235832 198.625589581 196 162 c 0
 185.665333312 135.693575703 181.068143327 108.945807045 181.068143327 87.1471403297 c 0
 181.068143327 62.5417301443 186.925393958 44.2419393862 197 40 c 0
522 40 m 0
 524.179123831 39.0525548563 526.555731167 38.5988184777 529.0907001 38.5988184777 c 0
 553.311569742 38.5988184777 591.989634802 80.0214592618 611 128 c 0
 618.801273837 147.763227053 623.897664408 174.829638922 623.897664408 197.52305288 c 0
 623.897664408 218.46369363 619.558131706 235.680764302 609 240 c 0
 607.059714009 240.759242344 604.934395026 241.11995209 602.659464452 241.11995209 c 0
 577.96754404 241.11995209 535.650235832 198.625589581 521 162 c 0
 510.665333312 135.693575703 506.068143327 108.945807045 506.068143327 87.1471403297 c 0
 506.068143327 62.5417301443 511.925393958 44.2419393862 522 40 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE52C
Encoding: 95 58668 95
Width: 811
Flags: HMW
LayerCount: 2
Fore
SplineSet
429 119 m 0
 480 232 500 280 556 280 c 0
 601 280 624 271 634 235 c 1
 675 278 694 280 736 280 c 0
 772 280 811 248 811 180 c 0
 811 87 730 0 631 0 c 0
 614 0 604 6 584 32 c 1
 539 -90 l 1
 591 -90 l 2
 606 -90 606 -120 591 -120 c 2
 366 -120 l 2
 352 -120 351 -90 366 -90 c 2
 441 -90 l 1
 545 195 l 2
 546.167116963 197.917792406 551.420719938 212.754502351 551.420719938 224.605732511 c 0
 551.420719938 233.06305846 548.745271893 240 540 240 c 0
 514 240 491 175 454 100 c 0
 423 37 388 -10 323 -10 c 0
 295.96461562 -10 276.685848474 4.31990873934 276.685848474 30.6552962356 c 0
 276.685848474 38.4136929968 278.359032859 47.2149008096 282 57 c 2
 334 193 l 2
 334.687448544 195.062345631 335.007330587 196.961328373 335.007330587 198.698285174 c 0
 335.007330587 208.224115412 325.386390673 212.876768553 314.009865299 212.876768553 c 0
 300.302784706 212.876768553 284.047157224 206.122608782 279 193 c 2
 214 22 l 2
 211 14 207 0 191 -1 c 2
 153 0 l 2
 134 -2 132 12 136 22 c 2
 203 193 l 2
 203.698722351 195.018531237 204.023750859 196.886379473 204.023750859 198.6021409 c 0
 204.023750859 208.040661137 194.187819777 212.876768553 182.617370253 212.876768553 c 0
 169.199127766 212.876768553 153.448127054 206.372675496 148 193 c 2
 80 21 l 2
 76 11 74 1 57 0 c 2
 4 0 l 2
 -6 0 0 18 4 26 c 2
 70 193 l 2
 77 211 69 221 60 221 c 0
 42 221 35 210 -11 138 c 0
 -18 127 -39 139 -33 151 c 0
 3 216 36 280 86 280 c 0
 128 280 145 266 152 240 c 1
 170 260 194 280 224 280 c 0
 254 280 273 263 278 240 c 1
 292 259 322 280 349 280 c 0
 382.297060451 280 409.658220776 253.618221661 409.658220776 218.530504648 c 0
 409.658220776 210.41331474 408.193901764 201.830198995 405 193 c 2
 358 68 l 2
 355.211869734 60.3326417674 353.881302664 53.2726015335 353.881302664 47.6241881024 c 0
 353.881302664 39.5840041338 356.577277218 34.4040367054 361.602949871 34.4040367054 c 0
 363.177144158 34.4040367054 364.979913018 34.9122608557 367 36 c 0
 389 48 418 94 429 119 c 0
628 40 m 0
 630.179123831 39.0525548563 632.555731167 38.5988184777 635.0907001 38.5988184777 c 0
 659.311569742 38.5988184777 697.989634802 80.0214592618 717 128 c 0
 724.801273837 147.763227053 729.897664408 174.829638922 729.897664408 197.52305288 c 0
 729.897664408 218.46369363 725.558131706 235.680764302 715 240 c 0
 713.059714009 240.759242344 710.934395026 241.11995209 708.659464452 241.11995209 c 0
 683.96754404 241.11995209 641.650235832 198.625589581 627 162 c 0
 616.665333312 135.693575703 612.068143327 108.945807045 612.068143327 87.1471403297 c 0
 612.068143327 62.5417301443 617.925393958 44.2419393862 628 40 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE52D
Encoding: 96 58669 96
Width: 351
Flags: HMW
LayerCount: 2
Fore
SplineSet
80 21 m 0
 76 11 74 1 57 0 c 0
 4 0 l 0
 -6 0 0 18 4 26 c 1
 70 193 l 0
 77 211 69 221 60 221 c 0
 42 221 35 210 -11 138 c 0
 -18 127 -39 139 -33 151 c 0
 3 216 36 280 86 280 c 0
 128 280 145 266 152 240 c 1
 170 260 194 280 224 280 c 0
 254 280 273 263 278 240 c 1
 292 259 322 280 349 280 c 0
 382.297060451 280 409.658220776 253.618221661 409.658220776 218.530504648 c 0
 409.658220776 210.41331474 408.193901764 201.830198995 405 193 c 0
 358 68 l 0
 355.211869734 60.3326417674 353.881302664 53.2726015335 353.881302664 47.6241881024 c 0
 353.881302664 39.5840041338 356.577277218 34.4040367054 361.602949871 34.4040367054 c 0
 363.177144158 34.4040367054 364.979913018 34.9122608557 367 36 c 0
 389 48 404 72 419 93 c 0
 427 104 449 93 440 78 c 0
 411 27 388 -10 323 -10 c 0
 295.96461562 -10 276.685848474 4.31990873934 276.685848474 30.6552962356 c 0
 276.685848474 38.4136929968 278.359032859 47.2149008096 282 57 c 0
 334 193 l 0
 334.687448544 195.062345631 335.007330587 196.961328373 335.007330587 198.698285174 c 0
 335.007330587 208.224115412 325.386390673 212.876768553 314.009865299 212.876768553 c 0
 300.302784706 212.876768553 284.047157224 206.122608782 279 193 c 0
 214 22 l 0
 211 14 207 0 191 -1 c 1
 153 0 l 16
 134 -2 132 12 136 22 c 0
 203 193 l 0
 203.698722351 195.018531237 204.023750859 196.886379473 204.023750859 198.6021409 c 0
 204.023750859 208.040661137 194.187819777 212.876768553 182.617370253 212.876768553 c 0
 169.199127766 212.876768553 153.448127054 206.372675496 148 193 c 0
 80 21 l 0
393 -160 m 0
 353 -160 313 -135 313 -90 c 0
 313 -55 330 -30 355 -30 c 0
 380 -30 396 -45 396 -65 c 0
 396 -75 389 -83 378 -90 c 0
 368 -97 368 -100 368 -110 c 0
 368 -120 378 -124 393 -124 c 0
 456 -124 459 -35 526 230 c 1
 507 230 508 230 473 230 c 0
 460.239470207 230 453.992185238 240.421191718 453.992185238 250.625180963 c 0
 453.992185238 260.412503619 459.73968741 270 471 270 c 0
 502 270 504 270 536 270 c 1
 564 374 647 440 713 440 c 0
 753 440 793 415 793 370 c 0
 793 335 776 310 751 310 c 0
 726 310 710 325 710 345 c 0
 710 355 717 363 728 370 c 0
 739 377 738 380 738 390 c 0
 738 400 728 404 713 404 c 0
 671 404 661 332 648 270 c 1
 675 270 672 270 702 270 c 0
 715 270 721.5 260 721.5 250 c 0
 721.5 240 715 230 702 230 c 0
 676 230 672 230 639 230 c 1
 596 -26 523 -160 393 -160 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE52F
Encoding: 97 58671 97
Width: 617
Flags: HMW
LayerCount: 2
Fore
SplineSet
351 230 m 9
 196 230 l 1
 153 -26 80 -160 -50 -160 c 0
 -90 -160 -130 -135 -130 -90 c 0
 -130 -55 -113 -30 -88 -30 c 0
 -63 -30 -47 -45 -47 -65 c 0
 -47 -75 -54 -83 -65 -90 c 0
 -75 -97 -75 -100 -75 -110 c 0
 -75 -120 -65 -124 -50 -124 c 0
 13 -124 16 -35 83 230 c 1
 64 230 65 230 30 230 c 0
 17.239470207 230 10.992185238 240.421191718 10.992185238 250.625180963 c 0
 10.992185238 260.412503619 16.7396874095 270 28 270 c 0
 59 270 61 270 93 270 c 1
 121 374 204 440 270 440 c 0
 310 440 350 415 350 370 c 0
 350 335 333 310 308 310 c 0
 283 310 267 325 267 345 c 0
 267 355 274 363 285 370 c 0
 296 377 295 380 295 390 c 0
 295 400 285 404 270 404 c 0
 228 404 218 333 205 271 c 1
 360 270 l 1
 388 374 471 440 537 440 c 0
 577 440 617 415 617 370 c 0
 617 335 600 310 575 310 c 0
 550 310 534 325 534 345 c 0
 534 355 541 363 552 370 c 0
 563 377 562 380 562 390 c 0
 562 400 552 404 537 404 c 0
 495 404 485 332 472 270 c 1
 499 270 496 270 526 270 c 0
 539 270 545.5 260 545.5 250 c 0
 545.5 240 539 230 526 230 c 0
 500 230 496 230 463 230 c 1
 420 -26 347 -160 217 -160 c 0
 177 -160 137 -135 137 -90 c 0
 137 -55 154 -30 179 -30 c 0
 204 -30 220 -45 220 -65 c 0
 220 -75 213 -83 202 -90 c 0
 192 -97 192 -100 192 -110 c 0
 192 -120 202 -124 217 -124 c 0
 280 -124 284 -35 351 230 c 9
EndSplineSet
Validated: 1
EndChar

StartChar: uniE530
Encoding: 98 58672 98
Width: 351
Flags: HMW
LayerCount: 2
Fore
SplineSet
204 270 m 9
 360 270 l 1
 388 374 471 440 537 440 c 0
 577 440 617 415 617 370 c 0
 617 335 600 310 575 310 c 0
 550 310 534 325 534 345 c 0
 534 355 541 363 552 370 c 0
 563 377 562 380 562 390 c 0
 562 400 552 404 537 404 c 0
 495 404 485 333 472 271 c 1
 627 270 l 1
 655 374 738 440 804 440 c 0
 844 440 884 415 884 370 c 0
 884 335 867 310 842 310 c 0
 817 310 801 325 801 345 c 0
 801 355 808 363 819 370 c 0
 830 377 829 380 829 390 c 0
 829 400 819 404 804 404 c 0
 762 404 752 332 739 270 c 1
 766 270 763 270 793 270 c 0
 806 270 812.5 260 812.5 250 c 0
 812.5 240 806 230 793 230 c 0
 767 230 763 230 730 230 c 1
 687 -26 614 -160 484 -160 c 0
 444 -160 404 -135 404 -90 c 0
 404 -55 421 -30 446 -30 c 0
 471 -30 487 -45 487 -65 c 0
 487 -75 480 -83 469 -90 c 0
 459 -97 459 -100 459 -110 c 0
 459 -120 469 -124 484 -124 c 0
 547 -124 551 -35 618 230 c 9
 463 230 l 1
 420 -26 347 -160 217 -160 c 0
 177 -160 137 -135 137 -90 c 0
 137 -55 154 -30 179 -30 c 0
 204 -30 220 -45 220 -65 c 0
 220 -75 213 -83 202 -90 c 0
 192 -97 192 -100 192 -110 c 0
 192 -120 202 -124 217 -124 c 0
 280 -124 283 -35 351 230 c 9
 196 230 l 1
 153 -26 80 -160 -50 -160 c 0
 -90 -160 -130 -135 -130 -90 c 0
 -130 -55 -113 -30 -88 -30 c 0
 -63 -30 -47 -45 -47 -65 c 0
 -47 -75 -54 -83 -65 -90 c 0
 -75 -97 -75 -100 -75 -110 c 0
 -75 -120 -65 -124 -50 -124 c 0
 13 -124 16 -35 83 230 c 1
 64 230 65 230 30 230 c 0
 17.239470207 230 10.992185238 240.421191718 10.992185238 250.625180963 c 0
 10.992185238 260.412503619 16.7396874095 270 28 270 c 0
 59 270 61 270 93 270 c 1
 121 374 204 440 270 440 c 0
 310 440 350 415 350 370 c 0
 350 335 333 310 308 310 c 0
 283 310 267 325 267 345 c 0
 267 355 274 363 285 370 c 0
 296 377 295 380 295 390 c 0
 295 400 285 404 270 404 c 0
 228 404 217 332 204 270 c 9
EndSplineSet
Validated: 1
EndChar

StartChar: uniE531
Encoding: 99 58673 99
Width: 617
Flags: HMW
LayerCount: 2
Fore
SplineSet
472 271 m 9
 628 270 l 1
 656 374 739 440 805 440 c 0
 845 440 885 415 885 370 c 0
 885 335 868 310 843 310 c 0
 818 310 802 325 802 345 c 0
 802 355 809 363 820 370 c 0
 831 377 830 380 830 390 c 0
 830 400 820 404 805 404 c 0
 763 404 753 333 740 271 c 1
 895 270 l 1
 923 374 1006 440 1072 440 c 0
 1112 440 1152 415 1152 370 c 0
 1152 335 1135 310 1110 310 c 0
 1085 310 1069 325 1069 345 c 0
 1069 355 1076 363 1087 370 c 0
 1098 377 1097 380 1097 390 c 0
 1097 400 1087 404 1072 404 c 0
 1030 404 1020 332 1007 270 c 1
 1034 270 1031 270 1061 270 c 0
 1074 270 1080.5 260 1080.5 250 c 0
 1080.5 240 1074 230 1061 230 c 0
 1035 230 1031 230 998 230 c 1
 955 -26 882 -160 752 -160 c 0
 712 -160 672 -135 672 -90 c 0
 672 -55 689 -30 714 -30 c 0
 739 -30 755 -45 755 -65 c 0
 755 -75 748 -83 737 -90 c 0
 727 -97 727 -100 727 -110 c 0
 727 -120 737 -124 752 -124 c 0
 815 -124 819 -35 886 230 c 9
 731 230 l 1
 688 -26 615 -160 485 -160 c 0
 445 -160 405 -135 405 -90 c 0
 405 -55 422 -30 447 -30 c 0
 472 -30 488 -45 488 -65 c 0
 488 -75 481 -83 470 -90 c 0
 460 -97 460 -100 460 -110 c 0
 460 -120 470 -124 485 -124 c 0
 548 -124 551 -36 618 230 c 9
 463 230 l 1
 420 -26 347 -160 217 -160 c 0
 177 -160 137 -135 137 -90 c 0
 137 -55 154 -30 179 -30 c 0
 204 -30 220 -45 220 -65 c 0
 220 -75 213 -83 202 -90 c 0
 192 -97 192 -100 192 -110 c 0
 192 -120 202 -124 217 -124 c 0
 280 -124 284 -35 351 230 c 9
 196 230 l 1
 153 -26 80 -160 -50 -160 c 0
 -90 -160 -130 -135 -130 -90 c 0
 -130 -55 -113 -30 -88 -30 c 0
 -63 -30 -47 -45 -47 -65 c 0
 -47 -75 -54 -83 -65 -90 c 0
 -75 -97 -75 -100 -75 -110 c 0
 -75 -120 -65 -124 -50 -124 c 0
 13 -124 16 -35 83 230 c 1
 64 230 65 230 30 230 c 0
 17.239470207 230 10.992185238 240.421191718 10.992185238 250.625180963 c 0
 10.992185238 260.412503619 16.7396874095 270 28 270 c 0
 59 270 61 270 93 270 c 1
 121 374 204 440 270 440 c 0
 310 440 350 415 350 370 c 0
 350 335 333 310 308 310 c 0
 283 310 267 325 267 345 c 0
 267 355 274 363 285 370 c 0
 296 377 295 380 295 390 c 0
 295 400 285 404 270 404 c 0
 228 404 218 333 205 271 c 1
 360 270 l 1
 388 374 471 440 537 440 c 0
 577 440 617 415 617 370 c 0
 617 335 600 310 575 310 c 0
 550 310 534 325 534 345 c 0
 534 355 541 363 552 370 c 0
 563 377 562 380 562 390 c 0
 562 400 552 404 537 404 c 0
 495 404 485 332 472 271 c 9
EndSplineSet
Validated: 1
EndChar

StartChar: uniE539
Encoding: 100 58681 100
Width: 351
Flags: HMW
LayerCount: 2
Fore
SplineSet
80 0 m 0xd8
 41 0 0 33 0 70 c 0xe8
 0 92 14 108 30 108 c 0xd8
 47 108 67 100 67 84 c 0xe8
 67 69 62 55 55 48 c 1
 60 34 69 30 85 30 c 0
 113 30 140 45 140 70 c 0
 140 100 120 107 94 124 c 0
 61 145 30 167 30 200 c 0
 30 247 70 280 130 280 c 0
 175 280 218 253 218 220 c 0
 218 199 202 180 180 180 c 0
 163.575188443 180 145.315176651 194.681601887 145.315176651 213.518742217 c 0
 145.315176651 218.765893239 146.732008255 224.335480975 150 230 c 1
 142 240 133 250 120 250 c 0
 101 250 80 239 80 220 c 0
 80 193 127 175 150 160 c 0
 184 137 200 120 200 90 c 0
 200 26 156 0 80 0 c 0xd8
494 3 m 0
 482 -6 470 16 481 26 c 0
 655 217 l 0
 647.065121876 221.231935 637.451249329 222.385713558 625.122178884 222.385713558 c 0
 614.144520003 222.385713558 601.014276252 221.471008125 585 221 c 0
 574 221 554 173 541 162 c 0
 527 150 511 153 524 187 c 0
 543 238 542 251 548 267 c 1
 580.854598393 264.712654542 605.061346797 263.852204333 623.335584921 263.852204333 c 0
 678.854023456 263.852204333 679.616120157 271.794054171 701.762784585 271.794054171 c 0
 707.383128795 271.794054171 714.380713088 271.282571588 724 270 c 0
 739 268 737 254 728 245 c 0
 574 82 l 0
 571.290722326 77.5296918374 570.067832218 74.1420610385 570.067832218 71.5487518924 c 0
 570.067832218 54.9981455171 619.876699814 70.8006196048 651 44 c 0
 660 36 672 52 668 64 c 0
 661 84 629 65 629 100 c 0
 629 115 645 130 661 130 c 0
 681 130 699 117 699 75 c 0
 699 35.6904170379 666.82658183 2.81551770962 623.631918047 2.81551770962 c 0
 621.774432159 2.81551770962 619.896565457 2.87631094845 618 3 c 0
 574.626134889 6.18925478761 553.222377354 17.5155864555 532.50873405 17.5155864555 c 0
 520.748265557 17.5155864555 509.210259784 13.8644712743 494 3 c 0
182 -160 m 0
 142 -160 102 -135 102 -90 c 0
 102 -55 119 -30 144 -30 c 0
 169 -30 185 -45 185 -65 c 0
 185 -75 178 -83 167 -90 c 0
 157 -97 165 -100 165 -110 c 0
 165 -120 167 -124 182 -124 c 0
 245 -124 248 -35 315 230 c 1
 296 230 297 230 262 230 c 0
 249.239470207 230 242.992185238 240.421191718 242.992185238 250.625180963 c 0
 242.992185238 260.412503619 248.73968741 270 260 270 c 0
 291 270 293 270 325 270 c 1
 353 374 436 440 502 440 c 0
 542 440 582 415 582 370 c 0
 582 335 565 310 540 310 c 0
 515 310 499 325 499 345 c 0
 499 355 506 363 517 370 c 0
 528 377 527 380 527 390 c 0
 527 400 517 404 502 404 c 0
 460 404 450 332 437 270 c 1
 464 270 461 270 491 270 c 0
 504 270 510.5 260 510.5 250 c 0
 510.5 240 504 230 491 230 c 0
 465 230 461 230 428 230 c 1
 385 -26 312 -160 182 -160 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE566
Encoding: 101 58726 101
Width: 509
Flags: HMW
LayerCount: 2
Fore
SplineSet
310 265 m 1
 183 258 l 1
 126 74 l 0
 125 70 124 67 124 63 c 0
 124 51 132 42 144 42 c 0
 176 42 230 60 254 80 c 9
 310 265 l 1
242 40 m 1
 192 9 164 -5 120 -5 c 0
 72 -5 52 26 52 57 c 0
 52 64 53 72 55 79 c 0
 110 258 l 1
 5 258 l 1
 5 290 l 1
 120 290 l 1
 142 364 l 1
 231 410 l 1
 193 290 l 1
 345 300 l 1
 367 300 370 281 370 255 c 1
 390 281 423 296 455 296 c 0
 488 296 508 275 508 247 c 0
 508 223 490 202 468 202 c 0
 447 202 430 214 430 233 c 0
 430 249 431 253 439 270 c 1
 402 260 378 241 368 216 c 0
 302 0 l 1
 230 0 l 1
 242 40 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE567
Encoding: 58 58727 58
Encoding: 102 58727 102
Width: 437
Flags: W
HStem: -3 64<35.7017 100.585> 0 37<332.058 392.5> 149 63<337.781 400.299> 173 35<42.4847 103.856>
VStem: 0 14<65.2321 138.945> 423 14<71.1359 142.998>
HStem: -3 72<49.5596 110.739> 0 49<319.775 397.094> 141 71<327.059 386.441> 161 47<36.904 118.027>
VStem: 0 24<64.6579 145.71> 413 24<63.9568 143.617>
LayerCount: 2
Fore
SplineSet
374 37 m 0x5c
 402 37 423 69 423 106 c 0
 423 136 416 150 401 161 c 1
 386 152 374 149 363 149 c 0
 344 149 335 159 335 176 c 0
 336 196 349 212 360 212 c 0
 405 212 437 156 437 108 c 0
368 49 m 0x5c
 396 49 413 69 413 106 c 0
 413 136 402 146 387 157 c 1
 375 145 368 141 357 141 c 0
 338 141 323 159 323 176 c 0
 324 196 345 212 356 212 c 0
 401 212 437 183 437 108 c 0
 437 69 419 41 396 21 c 0
 382 8 364 0 345 0 c 0x6c
 325 0 299 7 279 21 c 1
 111 151 l 1
 92 164 79 173 64 173 c 0
 35 173 14 142 14 103 c 0
 14 74 20 60 35 49 c 1
 50 58 63 61 74 61 c 0
 92 61 102 51 102 32 c 0
 102 11 93 -1 77 -3 c 1x9c
 63 -3 44 6 28 23 c 1
 382 8 362 0 343 0 c 0x6c
 323 0 295 7 275 21 c 1
 113 143 l 1
 94 156 85 161 70 161 c 0
 41 161 24 142 24 103 c 0
 24 74 34 64 49 53 c 1
 61 65 69 69 80 69 c 0
 98 69 114 51 114 32 c 0
 114 11 97 -1 81 -3 c 1x9c
 67 -3 44 6 28 23 c 1
 10 45 0 69 0 102 c 0
 0 141 18 169 40 189 c 0
 55 202 75 208 94 208 c 0
 114 207 137 204 157 190 c 1
 325 60 l 1
 344 47 359 37 374 37 c 0x5c
 55 202 77 208 96 208 c 0
 116 207 141 204 161 190 c 1
 323 68 l 1
 342 55 353 49 368 49 c 0x5c
EndSplineSet
Validated: 1
EndChar

StartChar: uniE569
Encoding: 59 58729 59
Encoding: 103 58729 103
Width: 437
Flags: HMW
LayerCount: 2
Fore
SplineSet
77 -3 m 0
 33 -3 0 54 0 102 c 0
︙
1988
1989
1990
1991
1992
1993
1994
1995

1996
1997
1998
1999
2000
2001
2002
3691
3692
3693
3694
3695
3696
3697

3698
3699
3700
3701
3702
3703
3704
3705







-
+







 92 61 102 51 102 32 c 0
 102 11 93 -1 77 -3 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE56C
Encoding: 60 58732 60
Encoding: 104 58732 104
Width: 580
Flags: W
HStem: 0 224
LayerCount: 2
Fore
SplineSet
34 46 m 13
︙
2013
2014
2015
2016
2017
2018
2019
2020

2021
2022
2023
2024
2025
2026
2027
3716
3717
3718
3719
3720
3721
3722

3723
3724
3725
3726
3727
3728
3729
3730







-
+







 109 124 l 5
 34 46 l 13
EndSplineSet
Validated: 1
EndChar

StartChar: uniE56D
Encoding: 61 58733 61
Encoding: 105 58733 105
Width: 580
Flags: W
HStem: -53 326<278 305> 0 21G<197.065 232.286 418.065 453.137>
VStem: 278 27<-53 70 150 273>
LayerCount: 2
Fore
SplineSet
︙
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
2131
2132
2133

2134
2135
2136
2137
2138
2139
2140
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
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
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
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
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








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

-
+


-
-
+
+



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

-
-
+
+

-
-
-
+
+
+

-
+



-
+

-
-
+
+


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



-
-
+
+





-
+







 305 97 l 9
 305 -53 l 25
 278 -53 l 25
 278 70 l 1xa0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE582
Encoding: 106 58754 106
Width: 280
Flags: HMW
LayerCount: 2
Fore
SplineSet
123 0 m 25
 123 123 l 25
 0 123 l 25
 0 157 l 25
 123 157 l 25
 123 280 l 25
 157 280 l 25
 157 157 l 25
 280 157 l 25
 280 123 l 25
 157 123 l 25
 157 0 l 25
 123 0 l 25
EndSplineSet
Validated: 1
EndChar

StartChar: uniE5D0
Encoding: 107 58832 107
Width: 310
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 0 m 1
 0 60 l 1
 93 79 229 114 280 370 c 1
 310 370 l 1
 310 175 152 13 0 0 c 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE5E2
Encoding: 108 58850 108
Width: 300
Flags: W
HStem: 0 62<198.921 262.211> 96 64<38.8054 112.592>
VStem: 283 16<88.1179 101.401>
LayerCount: 2
Fore
SplineSet
1 70 m 0
 14 108 35 160 95 160 c 0
 150 160 169 95 210 68 c 0
 216 64 222 62 229 62 c 0
 250 62 271 80 283 98 c 0
 288 106 302 100 299 90 c 0
 286 50 265 0 205 0 c 0
 150 0 137 65 90 92 c 0
 85 95 80 96 75 96 c 0
 55 96 32 79 17 61 c 0
 10 53 -2 61 1 70 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE610
Encoding: 109 58896 109
Width: 300
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 0 m 25
 0 300 l 25
 300 300 l 25
 300 0 l 25
 265 0 l 25
 265 180 l 25
 35 180 l 29
 35 0 l 29
 0 0 l 25
EndSplineSet
Validated: 1
EndChar

StartChar: uniE612
Encoding: 110 58898 110
Width: 250
Flags: HMW
LayerCount: 2
Fore
SplineSet
105 0 m 25
 0 450 l 29
 40 450 l 29
 125 90 l 25
 210 450 l 29
 250 450 l 29
 145 0 l 25
 105 0 l 25
EndSplineSet
Validated: 1
EndChar

StartChar: uniE614
Encoding: 111 58900 111
Width: 200
Flags: HMW
LayerCount: 2
Fore
SplineSet
100 25 m 28
 141 25 175 59 175 100 c 28
 175 141 141 175 100 175 c 28
 59 175 25 141 25 100 c 28
 25 59 59 25 100 25 c 28
100 0 m 28
 45 0 0 45 0 100 c 28
 0 155 45 200 100 200 c 28
 155 200 200 155 200 100 c 28
 200 45 155 0 100 0 c 28
EndSplineSet
Validated: 1
EndChar

StartChar: uniE618
Encoding: 112 58904 112
Width: 280
Flags: HMW
LayerCount: 2
Fore
SplineSet
-200 0 m 1
 -200 110 -110 200 0 200 c 24
 110 200 200 110 200 0 c 1
 170 0 l 1
 170 99 99 170 0 170 c 24
 -99 170 -170 99 -170 0 c 1
 -200 0 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE624
Encoding: 113 58916 113
Width: 250
Flags: HMW
LayerCount: 2
Fore
SplineSet
90 120 m 0
 110 120 132 165 132 200 c 28
 132 235 110 280 90 280 c 0
 70 280 48 235 48 200 c 24
 48 165 70 120 90 120 c 0
72 0 m 25
 72 100 l 17
 37 110 0 144.818359375 0 200 c 0
 0 255 45 300 90 300 c 0
 135 300 180 255 180 200 c 0
 180 144.818359375 143 110 108 100 c 0
 108 0 l 25
 72 0 l 25
EndSplineSet
Validated: 1
EndChar

StartChar: uniE630
Encoding: 114 58928 114
Width: 200
Flags: HMW
LayerCount: 2
Fore
SplineSet
84 102 m 1
 36.534641833 109.00393025 -7.1054273576e-15 150.442560477 0 200 c 24
 0 255 45 300 100 300 c 24
 155 300 200 255 200 200 c 24
 200 150.442560477 163.465358167 109.00393025 116 102 c 1
 116 101.288034818 l 1
 116 0 l 25
 84 0 l 25
 84 101.288034818 l 1
 84 102 l 1
116 126 m 5
 149.481193966 134.213607404 175 164.479867787 175 200 c 24
 175 241 141 275 100 275 c 24
 59 275 25 241 25 200 c 24
 25 164.479867787 50.5188060342 134.213607404 84 126 c 1
 84 126.757636954 l 1
 84 200 l 25
 116 200 l 25
 116 126.757636954 l 1
 116 126 l 5
EndSplineSet
Validated: 1
EndChar

StartChar: uniE650
Encoding: 62 58960 62
Encoding: 115 58960 115
Width: 1037
Flags: W
HStem: -2 60<953.253 1010.82> 0 42<353.953 425.192 547.67 646.14> 286 33<516.961 581> 359 73<29.5 117.603> 388 51<365.056 474.516> 607 32<183.481 261 301 390.125>
VStem: 0 57<401 499.322> 207 54<373 448> 273 58<234.695 340.5> 425 56<120.828 255.23> 488 38<456.957 539.616> 586 39<188.61 284.44> 675 57<69.552 222.033> 887 59<79.8865 267.532> 952 60<-0.820206 56.8202>
HStem: -2 60<361.035 435.033 953.253 1010.82> 0 49<543.265 652.027> 286 36<514.943 580.797> 359 66<58.4784 125.129> 402 58<367.211 444.917> 607 32<177.106 261>
VStem: 0 57<406 505.924> 148 26<463.933 475.584> 200 67<410.241 442> 274.641 84.3586<205.588 329> 425 56<126.64 255.856> 452 64<466.983 558.522> 585 40<194.878 284.873> 675 60<72.5613 225.441> 887 59<79.8865 267.532> 952 60<-0.820206 56.8202>
LayerCount: 2
Fore
SplineSet
982 -2 m 3xa7fe
 967 -2 952 12 952 28 c 3
 952 44 967 58 982 58 c 3
 998 58 1012 44 1012 28 c 3
 1012 12 1000 -2 982 -2 c 3xa7fe
460 93 m 1
 440 125 425 152 425 186 c 27
152 90 m 0x67ef
 221.394397964 119.985233688 274.64143816 164.649883528 274.64143816 208.902553279 c 0
 274.64143816 216.303422646 273.152138825 223.692769088 270 231 c 0
 252 273 185 332 185 389 c 0
 185 407 200 441 200 442 c 2
 261 607 l 1
 114 601 57 505 57 460 c 0x6fef
 57 436 69 425 89 425 c 0
 110 425 128 443 148 485 c 1
 174 472 l 1
 146 384 124 359 75 359 c 0x37ef
 35 359 0 389 0 423 c 0
 0 505 74 639 277 639 c 3
 460 639 516 565 516 503 c 0
 516 439 482 402 420 402 c 0
 384 402 344 435 320 493 c 1
 344 507 l 1
 366 469 373 460 401 460 c 0
 437 460 452 482 452 510 c 0x2fdf
 452 530 431 601 303 608 c 1
 276 542 l 2
 275 538 267 498 267 479 c 0
 267 390 359 361 359 297 c 0
 359 211 296 140 296 140 c 1
 334 114 366 63 394 63 c 0
 399 63 402.9375 62.625 406.671875 62.625 c 0
 417.875 62.625 427.25 66 458 93 c 1
 438 125 425 152 425 186 c 27
 425 226 431 247 453 276 c 0
 479 311 522 319 563 319 c 0
 599 319 625 289 625 247 c 3
 479 311 522 322 563 322 c 0
 599 322 625 289 625 247 c 3
 625 233 625 214 615 195 c 0
 591 148 543 113 518 93 c 1
 542 64 566 42 604 42 c 0x6ffe
 630 42 675 80 675 116 c 0
 591 148 551 110 526 90 c 1
 550 61 566 49 604 49 c 0x6fef
 630 49 675 80 675 116 c 0
 675 217 703 283 835 318 c 1
 761 420 580 491 580 509 c 0
 761 420 580 491 580 509 c 2
 580 510 l 1
 835 427 946 304 946 166 c 0
 946 75 889 1 799 1 c 0
 767 1 730 7 699 58 c 1xa7fe
 767 1 730 7 699 58 c 1xa7ef
 672 15 633 0 603 0 c 3
 553 0 506 38 485 64 c 1
 427 14 405 -4 383 -4 c 0
 532 0 504 33 483 59 c 1
 425 9 405 -4 383 -4 c 0
 361 -4 347 9 312 50 c 1
 294 81 282 95 268 95 c 0
 246 95 227 70 207 59 c 0
 135 11 94 1 76 1 c 0
 69 1 66 4 66 8 c 0
 66 23 116 65 157 90 c 0
 246 95 227 72 207 59 c 0
 134 12 102 1 84 1 c 0
 77 1 74 4 74 8 c 0
 74 23 108 71 152 90 c 0x67ef
 260 153 241 115 271 246 c 0
 272 250 273 253 273 256 c 0
 273 302 207 316 207 373 c 0
 207 379 208 386 209 392 c 2
 261 607 l 1
 129 597 57 517 57 472 c 0
 57 448 69 432 89 432 c 0
 110 432 147 440 170 480 c 1
 186 472 l 1
982 -2 m 3xa7cf
 133 384 109 359 43 359 c 0x77fe
 16 359 0 384 0 418 c 0
 967 -2 952 12 952 28 c 3
 0 494 74 639 277 639 c 3
 460 639 526 555 526 487 c 0
 526 437 471 388 423 388 c 0
 387 388 344 414 320 472 c 1
 333 484 l 1
 355 446 383 439 411 439 c 0x2ffe
 452 439 488 458 488 495 c 0
 952 44 967 58 982 58 c 3
 488 530 443 601 301 608 c 1
 263 448 l 1
 998 58 1012 44 1012 28 c 3
 262 444 261 438 261 434 c 0
 261 384 331 366 331 315 c 0
 331 311 331 307 330 303 c 2
 292 140 l 1
 1012 12 1000 -2 982 -2 c 3xa7cf
 330 114 355 40 383 40 c 0
 403 40 419 57 460 93 c 1
499 120 m 1
 564 179 586 202 586 247 c 0
 586 253 584 261 582 268 c 0
 578 284 569 286 556 286 c 0
 521 286 481 246 481 186 c 0
 481 159 485 145 499 120 c 1
498 126 m 1
 563 185 585 210 585 247 c 0
 585 253 583 261 581 268 c 0
 577 284 568 286 555 286 c 0
 520 286 481 246 481 186 c 0x27ef
 481 159 484 151 498 126 c 1
797 40 m 1
 864 44 887 102 887 174 c 0
 887 218 870 274 846 302 c 1
 758 262 732 202 732 117 c 0
 732 73 753 50 797 40 c 1
 758 262 735 202 735 117 c 0
 735 73 753 50 797 40 c 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE655
Encoding: 63 58965 63
Encoding: 116 58965 116
Width: 540
Flags: W
HStem: 68 93<79.5149 155.133> 182 17<220 222.173 252.655 264.303> 192 94<18.5323 100.176 375.888 460.387> 230 56<60.9363 133.273> 230 18<300.618 361.695> 274 18<213.64 227.572 256.894 258> 315 97<73.5817 155.121 322.704 406.413>
VStem: 179 23<209.875 223.47 254.181 264.625> 192 98<17.9339 97.9009 381.276 451.65> 230 18<113.95 174.519 300.936 363.797> 278 17<212.458 224.186 254.5 261>
LayerCount: 2
Fore
SplineSet
︙
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
2231

2232
2233
2234
2235
2236
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311


4312
4313
4314



4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371







4372
4373
4374
4375
4376
4377
4378






4379
4380
4381
4382



4383


4384
4385
4386
4387
4388
4389







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

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



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





 135 161 150 163 166 179 c 0
 173 186 179 196 179 204 c 0
 179 219 166 230 141 230 c 0xcb40
EndSplineSet
Validated: 1
EndChar

StartChar: uniE910
Encoding: 117 59664 117
Width: 500
Flags: HMW
LayerCount: 2
Fore
SplineSet
45 0 m 28
 45 -113 137 -205 250 -205 c 28
 363 -205 455 -113 455 0 c 28
 455 113 363 205 250 205 c 28
 137 205 45 113 45 0 c 28
0 0 m 28
 0 139 111 250 250 250 c 28
 388 250 500 139 500 0 c 28
 500 -138 389 -250 250 -250 c 28
 112 -250 0 -138 0 0 c 28
250 -60 m 7
 217 -60 190 -33 190 0 c 7
 190 33 217 60 250 60 c 7
 283 60 310 33 310 0 c 7
 310 -33 283 -60 250 -60 c 7
EndSplineSet
Validated: 1
EndChar

StartChar: uniE911
Encoding: 118 59665 118
Width: 500
Flags: HMW
LayerCount: 2
Fore
SplineSet
45 0 m 24
 45 -113 137 -205 250 -205 c 24
 363 -205 455 -113 455 0 c 24
 455 113 363 205 250 205 c 24
 137 205 45 113 45 0 c 24
0 0 m 24
 0 139 111 250 250 250 c 24
 388 250 500 139 500 0 c 24
 500 -138 389 -250 250 -250 c 24
 112 -250 0 -138 0 0 c 24
EndSplineSet
Validated: 1
EndChar

StartChar: uniE912
Encoding: 119 59666 119
Width: 500
Flags: HMW
LayerCount: 2
Fore
SplineSet
228 350 m 1
 273 350 l 1
 273 250 l 1
 400 237 500 131 500 0 c 0
 500 -130 401 -237 273 -250 c 1
 273 -350 l 5
 228 -350 l 5
 228 -249 l 1
 100 -238 0 -131 0 0 c 0
 0 132 99 238 228 249 c 1
 228 350 l 1
228 -203.826663616 m 1
 228 203.826663616 l 1
 125.298009966 192.809355922 45 105.569124751 45 0 c 0
 45 -105.569124751 125.298009966 -192.809355922 228 -203.826663616 c 1
273 -203.716902537 m 1
 375.222749877 -192.242459755 455 -105.22624212 455 0 c 0
 455 105.22624212 375.222749877 192.242459755 273 203.716902537 c 1
 273 -203.716902537 l 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE914
Encoding: 120 59668 120
Width: 500
Flags: HMW
LayerCount: 2
Fore
SplineSet
463 130 m 0
 464 127 465 123 465 120 c 0
 465 112 461 103 454 99 c 0
 451 97 447 96 443 96 c 0
 435 96 427 100 420 110 c 1
 386 173 323 205 250 205 c 8
 137 205 45 113 45 0 c 24
 45 -113 137 -205 250 -205 c 16
 330 -205 386 -174 420 -110 c 0
 424 -102 434 -97 444 -97 c 0
 448 -97 451 -97 454 -99 c 0
 462 -104 466 -111 466 -118 c 0
 466 -122 465 -126 463 -130 c 0
 420 -211 350 -250 250 -250 c 8
 112 -250 0 -138 0 0 c 24
 0 139 111 250 250 250 c 0
 344 250 420 210 463 130 c 0
250 -60 m 3
 217 -60 190 -33 190 0 c 3
 190 33 217 60 250 60 c 3
 283 60 310 33 310 0 c 3
 310 -33 283 -60 250 -60 c 3
EndSplineSet
Validated: 1
EndChar

StartChar: uniE915
Encoding: 121 59669 121
Width: 500
Flags: HMW
LayerCount: 2
Fore
SplineSet
463 130 m 0
 464 127 465 123 465 120 c 0
 465 112 461 103 454 99 c 0
 451 97 447 96 443 96 c 0
 435 96 427 100 420 110 c 1
 386 173 323 205 250 205 c 8
 137 205 45 113 45 0 c 24
 45 -113 137 -205 250 -205 c 16
 330 -205 386 -174 420 -110 c 0
 424 -102 434 -97 444 -97 c 0
 448 -97 451 -97 454 -99 c 0
 462 -104 466 -111 466 -118 c 0
 466 -122 465 -126 463 -130 c 0
 420 -211 350 -250 250 -250 c 8
 112 -250 0 -138 0 0 c 24
 0 139 111 250 250 250 c 0
 344 250 420 210 463 130 c 0
EndSplineSet
Validated: 1
EndChar

StartChar: uniE918
Encoding: 122 59672 122
Width: 500
Flags: HMW
LayerCount: 2
Fore
SplineSet
273 249 m 1
 356 243 424 203 463 130 c 0
 464 127 465 123 465 120 c 0
 465 112 461 103 454 99 c 0
 451 97 447 96 443 96 c 0
 435 96 427 100 420 110 c 0
 390 166 336 198 273 204 c 1
 273 -204 l 1
 341 -199 389 -168 420 -110 c 0
 424 -102 434 -97 444 -97 c 0
 448 -97 451 -97 454 -99 c 0
 462 -104 466 -111 466 -118 c 0
 466 -122 465 -126 463 -130 c 0
 423 -205 361 -244 273 -249 c 1
 273 -350 l 1
 228 -350 l 1
 228 -249 l 1
 100 -238 0 -131 0 0 c 0
 0 132 99 238 228 249 c 1
 228 350 l 1
 273 350 l 1
 273 249 l 1
228 -204 m 1
 228 204 l 1
 125 193 45 106 45 0 c 0
 45 -106 125 -193 228 -204 c 1
EndSplineSet
Validated: 1
EndChar

StartChar: uniE920
Encoding: 123 59680 123
Width: 120
Flags: HMW
LayerCount: 2
Fore
SplineSet
60 -60 m 3
 27 -60 0 -33 0 0 c 3
 0 33 27 60 60 60 c 3
 93 60 120 33 120 0 c 3
 120 -33 93 -60 60 -60 c 3
EndSplineSet
Validated: 1
EndChar

StartChar: uniE925
Encoding: 124 59685 124
Width: 45
Flags: HMW
LayerCount: 2
Fore
SplineSet
45 350 m 9
 45 -350 l 1
 0 -350 l 9
 0 350 l 1
 45 350 l 9
EndSplineSet
Validated: 1
EndChar

StartChar: uniE95C
Encoding: 64 59740 64
StartChar: uniE95D
Encoding: 125 59741 125
Width: 540
Flags: W
HStem: -170 100<25 515> 70 100<25 515>
VStem: 0 25<-220 -170 -70 70 170 220> 515 25<-540 -170 -70 70 170 220>
Flags: HMW
LayerCount: 2
Fore
SplineSet
30 70 m 25
 30 -70 l 25
 300 -70 l 25
 300 70 l 25
 30 70 l 25
0 190 m 25
 30 190 l 25
 30 140 l 25
 300 140 l 25
 300 190 l 25
 330 190 l 1
 330 -750 l 29
 300 -750 l 5
 300 -140 l 1
 30 -140 l 25
 30 -190 l 25
 0 -190 l 25
 0 190 l 25
EndSplineSet
Validated: 1
EndChar

StartChar: uniEA02
Encoding: 126 59906 126
Width: 250
Flags: HMW
LayerCount: 2
Fore
SplineSet
0 65 m 25
 137 250 l 25
 221 135 l 25
 307 250 l 25
 389 137 l 1
 564 370 l 1
 598 348 l 1
 338 0 l 1
 254 116 l 25
 168 0 l 25
 85 112 l 25
 32 41 l 25
 0 65 l 25
EndSplineSet
Validated: 1
EndChar

StartChar: uniEAA4
Encoding: 127 60068 127
Width: 250
Flags: HMW
LayerCount: 2
Fore
SplineSet
25 70 m 25
 25 -70 l 25
 515 -70 l 25
 515 70 l 25
 25 70 l 25
0 220 m 25
 25 220 l 25
0 270 m 0
 30 300 45 311 85 311 c 0
 125 311 170 250 210 250 c 0
 222 250 230 250 250 270 c 0
 252 272 256 273 260 273 c 0
 266 273 272 271 272 264 c 0
 272 257 266 246 250 230 c 0
 25 170 l 25
 515 170 l 25
 515 220 l 25
 540 220 l 1
 541 -540 l 25
 516 -540 l 1
 220 200 205 189 165 189 c 0
 125 189 80 250 40 250 c 0
 28 250 20 250 0 230 c 0
 -2 228 -7 226 -11 226 c 0
 515 -170 l 1
 25 -170 l 25
 25 -220 l 25
 -17 226 -22 229 -22 236 c 0
 0 -220 l 25
 0 220 l 25
 -22 243 -17 253 0 270 c 0
EndSplineSet
Validated: 1
EndChar
EndChars
EndSplineFont
Changes to modules/MIDI.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// MIDI.js - module to handle the %%MIDI parameters
//
// Copyright (C) 2018 Jean-Francois Moine - GPL3+
// Copyright (C) 2019 Jean-Francois Moine - GPL3+
//
// This module is loaded when "%%MIDI" appears in a ABC source.
//
// Parameters (see abcMIDI for details)
//	%%MIDI channel n
//	%%MIDI program n
//	%%MIDI control k v
︙
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
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







-
+
-








-
+












-
+
















-
+







    var	pit = Number(p)
	if (isNaN(pit))
		return
	p = ((pit / 12) | 0) * 7 - 19;	// octave
	pit = pit % 12;			// in octave
	p += pits[pit]
	note = {
		pit: p,
		pit: p
		apit: p,
	}
	if (accs[pit])
		note.acc = accs[pit]
	return note
    } // tonote()

    // normalize a note for mapping
    function norm(p) {
    var	a = p.match(/^([_^]*)([A-Ga-g])([,']*)$/)	// '
    var	a = p.match(/^([_^=]*)([A-Ga-g])([,']*)$/)	// '
	if (!a)
		return
	if (p.match(/[A-Z]/)) {
		p = p.toLowerCase();
		if (p.indexOf("'") > 0)
			p = p.replace("'", '')
		else
			p += ','
	}
	return p
    } // norm()

	var	n, v,
    var	n, v, s,
	maps = this.get_maps(),
		a = parm.split(/\s+/)

	switch (a[1]) {
	case "channel":
		if (a[2] != "10")
			break
		this.set_v_param("midictl", "0 1") // channel 10 is bank 128 program 0
		break
	case "drummap":
		if (this.cfmt().sound != "play")
			break
//fixme: should have a 'MIDIdrum' per voice?
		n = norm(a[2]);
		v = tonote(a[3]);
		if (!n || !v) {
			this.syntax(1, abc.errs.bad_val, "%%MIDI drummap")
			this.syntax(1, this.errs.bad_val, "%%MIDI drummap")
			break
		}
		if (!maps.MIDIdrum)
			maps.MIDIdrum = {}
		maps.MIDIdrum[n] = [null, v];
		this.set_v_param("mididrum", "MIDIdrum")
		break
︙
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
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







+
+
+
-
+
+
+
+
















-
+







			return
		}
		v = parseInt(a[3])
		if (isNaN(v) || v < 0 || v > 127) {
			this.syntax(1, "Bad controller value in %%MIDI")
			return
		}
		if (this.cfmt().sound != "play")
			break
		if (this.parse.state >= 2) {
		this.set_v_param("midictl", a[2] + ' ' + a[3])
			s = this.new_block("midictl");
			s.ctrl = n;
			s.val = v
		}
		break
	}
    }, // do_midi()

    // set the MIDI parameters in the current voice
    set_midi: function(a) {
    var	i, item,
	curvoice = this.get_curvoice()

	for (i = 0; i < a.length; i++) {
		switch (a[i]) {
		case "instr=":			// %%MIDI program
			curvoice.instr = a[i + 1]
			break
		case "midictl=":		// %%MIDI control
			if (!curvoice.midictl)
				curvoice.midictl = {}
				curvoice.midictl = []
			item = a[i + 1].split(' ');
			curvoice.midictl[item[0]] = Number(item[1])
			break
		case "mididrum=":		// %%MIDI drummap note midipitch
			if (!curvoice.map)
				curvoice.map = {}
			curvoice.map = a[i + 1]
︙
133
134
135
136
137
138
139





140
141
142
143

144
145
146
147
148
149
150
151
152
153
154
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152

153








154
155
156







+
+
+
+
+



-
+
-
-
-
-
-
-
-
-



	else
		of(text)
    },

    set_vp: function(of, a) {
	abc2svg.MIDI.set_midi.call(this, a);
	of(a)
    },

    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.modules.hooks.push(abc2svg.MIDI.set_hooks);
// export
	"errs",
	"set_v_param",
	"syntax",
// hooks
	[ "do_pscom", "abc2svg.MIDI.do_pscom" ],
	[ "set_vp", "abc2svg.MIDI.set_vp" ]
);

// the module is loaded
abc2svg.modules.MIDI.loaded = true
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
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
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


-
+








-
+
-
-
-
-
-
+




+
+





-
+











-
+



-
+



-
+







-
-
-
-
+



-
-
-

+




-
+








-
-
+
+
+

-

















+
+
+
+
+
+
+



-
+
-
-
-
-
-
-
-
-



// ambitus.js - module to insert an ambitus at start of a voice
//
// Copyright (C) 2018 Jean-Francois Moine - GPL3+
// Copyright (C) 2018-2019 Jean-Francois Moine - GPL3+
//
// This module is loaded when "%%ambitus" appears in a ABC source.
//
// Parameters
//	%%ambitus 1

abc2svg.ambitus = {
    do_ambitus: function() {

    var	C = abc2svg.C,
// constants from the abc2svg core
    var	BASE_LEN = 1536,
	NOTE = 8,
	FULL = 0
    var	s, v, p_v, min, max,
	s, v, p_v, min, max,
	voice_tb = this.get_voice_tb()

	for (v = 0; v < voice_tb.length; v++) {
		p_v = voice_tb[v];
		if (p_v.second)
			continue
		min = 100;
		max = -100

		// search the top and bottom pitches
		for (s = p_v.sym; s; s = s.next) {
			if (s.type != NOTE)
			if (s.type != C.NOTE)
				continue
			if (s.notes[s.nhd].pit > max)
				max = s.notes[s.nhd].pit
			if (s.notes[0].pit < min)
				min = s.notes[0].pit
		}
		if (min == 100)
			continue			// no note

		s = p_v.clef;
		s.stem = 1;
		s.head = FULL;
		s.head = C.FULL;
		s.stemless = true;
		s.nhd = 1;
		s.notes = [{
				dur: BASE_LEN / 4,
				dur: C.BLEN / 4,
				pit: min,
				shhd: 0
			},{
				dur: BASE_LEN / 4,
				dur: C.BLEN / 4,
				pit: max,
				shhd: 0
			}]
	}
    }, // do_ambitus()

    draw_symbols: function(of, p_voice) {
// constants from the abc2svg core
    var	d,
	delta_tb = this.get_delta_tb(),
	staff_tb = this.get_staff_tb(),
    var	staff_tb = this.get_staff_tb(),
	s = p_voice.sym

	if (s.clef_type != undefined && s.nhd > 0) {
		d = delta_tb[s.clef_type] + s.clef_line * 2;
		s.notes[0].pit += d;
		s.notes[1].pit += d;
		s.x -= 26;
		this.set_scale(s);
		this.draw_note(s)
		if (s.notes[1].pit - s.notes[0].pit > 4) {
			this.xypath(s.x, 3 * (s.notes[1].pit - 18) + staff_tb[s.st].y);
			this.out_svg('v' +
				((s.notes[1].pit - s.notes[0].pit) * 3).toFixed(2) +
				((s.notes[1].pit - s.notes[0].pit) * 3).toFixed(1) +
				'" stroke-width=".6"/>\n');
		}
		s.x += 26;
		p_voice.clef.nhd = 0
	}
	of(p_voice)
    }, // draw_symbols()

    output_music: function(of) {
	if (this.cfmt().ambitus)
    set_pitch: function(of, last_s) {
	of(last_s)
	if (!last_s && this.cfmt().ambitus)
		abc2svg.ambitus.do_ambitus.call(this)
	of()
    },

    set_fmt: function(of, cmd, param, lock) {
	if (cmd == "ambitus") {
		this.cfmt().ambitus = param
		return
	}
	of(cmd, param, lock)
    },

    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.modules.hooks.push(abc2svg.ambitus.set_hooks);
// export
	"draw_note",
// hooks
	[ "draw_symbols", "abc2svg.ambitus.draw_symbols" ],
	[ "output_music", "abc2svg.ambitus.output_music" ],
	[ "set_format", "abc2svg.ambitus.set_fmt" ],
	[ "set_width", "abc2svg.ambitus.set_width" ]
)

// the module is loaded
abc2svg.modules.ambitus.loaded = true
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
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
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


-
+










-
-
+
+







-
+

-
+











-
+






-
+
















-
+








-
+
-







// break.js - module to handle the %%break command
//
// Copyright (C) 2018 Jean-Francois Moine - GPL3+
// Copyright (C) 2018-2019 Jean-Francois Moine - GPL3+
//
// 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	BASE_LEN = 1536		// constant from the abc2svg core
	    var	b, c, d, sq,
	    var	C = abc2svg.C,
		b, c, d, sq,
		a = parm.split(/[ ,]/),
		cfmt = this.cfmt()

		if (!cfmt.break)
			cfmt.break = []
		for (n = 1; n < a.length; n++) {
			b = a[n];
			c = b.match(/(\d)([a-z]?)(:\d\/\d)?/)
			c = b.match(/(\d+)([a-z]?)(:\d+\/\d+)?/)
			if (!c) {
				this.syntax(1, errs.bad_val, "%%break")
				this.syntax(1, this.errs.bad_val, "%%break")
				continue
			}
			if (c[2])
				sq = c[2].charCodeAt(0) - 0x61
			if (!c[3]) {
				cfmt.break.push({	// on measure bar
						m: c[1],
						t: 0,
						sq: sq})
				continue
			}
			d = c[3].match(/:(\d)\/(\d)/)
			d = c[3].match(/:(\d+)\/(\d+)/)
			if (!d || d[2] < 1) {
				this.syntax(1, "Bad denominator in %%break")
				continue
			}
			cfmt.break.push({
					m: c[1],
					t: d[1] * BASE_LEN / d[2],
					t: d[1] * C.BLEN / d[2],
					sq: sq})
		}
	}, // get_break()

	// insert the EOLs of %%break
	do_break: function() {
	    var	i, m, t, brk, seq,
		voice_tb = this.get_voice_tb()
		v = this.get_cur_sy().top_voice,
		s1 = voice_tb[v].sym,
		cfmt = this.cfmt()

		for (i = 0; i < cfmt.break.length; i++) {
			brk = cfmt.break[i];
			m = brk.m
			for (s = s1; s; s = s.next) {
				if (s.bar_type && s.bar_num == m)
				if (s.bar_num == m)
					break
			}
			if (!s)
				continue

			if (brk.sq) {
				seq = brk.sq
				for (s = s.ts_next; s; s = s.ts_next) {
					if (s.bar_type
					if (s.bar_num == m) {
					 && s.bar_num == m) {
						if (--seq == 0)
							break
					}
				}
				if (!s)
					continue
			}
︙
99
100
101
102
103
104
105





106
107
108
109

110
111
112
113
114
115
116
117
118
119
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

113







114
115
116







+
+
+
+
+



-
+
-
-
-
-
-
-
-



		of(text)
    },

    set_bar_num: function(of) {
	of()
	if (this.cfmt().break)
		abc2svg.break.do_break.call(this)
    },

    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.modules.hooks.push(abc2svg.break.set_hooks);
// export
	"errs",
	"syntax",
// hooks
	[ "do_pscom", "abc2svg.break.do_pscom" ],
	[ "set_bar_num", "abc2svg.break.set_bar_num" ]
);

// the module is loaded
abc2svg.modules.break.loaded = true
Changes to modules/capo.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// capo.js - module to add a capo chord line
//
// Copyright (C) 2018 Jean-Francois Moine - GPL3+
// Copyright (C) 2018-2019 Jean-Francois Moine - GPL3+
//
// This module is loaded when "%%capo" appears in a ABC source.
//
// Parameters
//	%%capo n	'n' is the capo fret number

abc2svg.capo = {
︙
53
54
55
56
57
58
59
60

61

62
63





64
65

66
67
68
69
70
71
72
73
74
75
76
53
54
55
56
57
58
59

60
61
62


63
64
65
66
67
68

69








70
71
72







-
+

+
-
-
+
+
+
+
+

-
+
-
-
-
-
-
-
-
-




    set_fmt: function(of, cmd, param, lock) {
	if (cmd == "capo") {
		this.cfmt().capo = param
		return
	}
	of(cmd, param, lock)
    }
    },

    set_hooks: function(abc) {
} // capo

	abc.gch_build = abc2svg.capo.gch_build.bind(abc, abc.gch_build);
	abc.output_music = abc2svg.capo.output_music.bind(abc, abc.output_music);
	abc.set_format = abc2svg.capo.set_fmt.bind(abc, abc.set_format)
    }
} // capo

abc2svg.modules.hooks.push(
abc2svg.modules.hooks.push(abc2svg.capo.set_hooks);
// export
	"gch_tr1",
	"get_font",
// hooks
	[ "set_format", "abc2svg.capo.set_fmt" ],
	[ "gch_build", "abc2svg.capo.gch_build" ],
	[ "output_music", "abc2svg.capo.output_music" ]
)

// the module is loaded
abc2svg.modules.capo.loaded = true
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
31
32
33
34
35
36
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


-
+









-
+












-
+


-
+







// clip.js - module to handle the %%clip command
//
// Copyright (C) 2018 Jean-Francois Moine - GPL3+
// Copyright (C) 2018-2019 Jean-Francois Moine - GPL3+
//
// 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	BASE_LEN = 1536		// constant from the abc2svg core
    var	C = abc2svg.C

	// get the start/stop points
	function get_symsel(a) {
	    var	j, d, sq,
		b = a.match(/(\d+)([a-z]?)(:\d+\/\d+)?/)

		if (!b)
			return
		if (b[2])
			sq = b[2].charCodeAt(0) - 0x61
		if (!b[3])
			return {m: b[1], t: 0, sq: sq}	// on measure bar
		a = b[3].match(/:(\d)\/(\d)/)
		a = b[3].match(/:(\d+)\/(\d+)/)
		if (!a || a[2] < 1)
			return
		return {m: b[1], t: a[1] * BASE_LEN / a[2], sq: sq}
		return {m: b[1], t: a[1] * C.BLEN / a[2], sq: sq}
	} // get_symsel()

	    var	b, c,
		a = parm.split(/[ -]/)

		if (a.length != 3) {
			this.syntax(1, this.errs.bad_val, "%%clip")
︙
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
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







-
-
-
+
-
-
-
+









-
+









-
+









-
+







			return
		}
		this.cfmt().clip = [b, c]
    }, // get_clip()

    // cut the tune
    do_clip: function() {
    var	BAR = 0,		// constants from the abc2svg core
	CLEF = 1,
	KEY = 5,
    var	C = abc2svg.C
	METER = 6,
	STAVES = 12
    var	voice_tb = this.get_voice_tb(),
	voice_tb = this.get_voice_tb(),
	cfmt = this.cfmt()

	// go to a global (measure + time)
	function go_global_time(s, sel) {
	    var	s2, bar_time, seq

		if (sel.m <= 1) {	// special case: there is no measure 0/1
			if (sel.m == 1) {
				for (s2 = s; s2; s2 = s2.ts_next) {
					if (s2.type == BAR
					if (s2.type == C.BAR
					 && s2.time != 0)
						break
				}
				if (s2.time < voice_tb[this.get_cur_sy().top_voice].
								meter.wmeasure)
					s = s2
			}
		} else {
			for ( ; s; s = s.ts_next) {
				if (s.type == BAR
				if (s.type == C.BAR
				 && s.bar_num >= sel.m)
					break
			}
			if (!s)
				return // null

			if (sel.sq) {
				seq = sel.sq
				for (s = s.ts_next; s; s = s.ts_next) {
					if (s.type == BAR
					if (s.type == C.BAR
					 && s.bar_num == sel.m) {
						if (--seq == 0)
							break
					}
				}
				if (!s)
					return // null
︙
122
123
124
125
126
127
128
129

130
131
132

133
134
135

136
137
138

139
140
141
142
143
144
145
118
119
120
121
122
123
124

125
126
127

128
129
130

131
132
133

134
135
136
137
138
139
140
141







-
+


-
+


-
+


-
+







				return
			}

			// update the start of voices
			sy = this.get_cur_sy()
			for (s2 = this.get_tsfirst(); s2 != s; s2 = s2.ts_next) {
				switch (s2.type) {
				case CLEF:
				case C.CLEF:
					s2.p_v.clef = s2
					break
				case KEY:
				case C.KEY:
					s2.p_v.key = this.clone(s2.as.u.key)
					break
				case METER:
				case C.METER:
					s2.p_v.meter = this.clone(s2.as.u.meter)
					break
				case STAVES:
				case C.STAVES:
					sy = s2.sy;
					this.set_cur_sy(sy)
					break
				}
			}
			for (v = 0; v < voice_tb.length; v++) {
				p_voice = voice_tb[v]
︙
189
190
191
192
193
194
195





196
197
198
199

200
201
202
203
204
205
206
207
208
209
210
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

200








201
202
203







+
+
+
+
+



-
+
-
-
-
-
-
-
-
-



		of(text)
    },

    set_bar_num: function(of) {
	of()
	if (this.cfmt().clip)
		abc2svg.clip.do_clip.call(this)
    },

    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.modules.hooks.push(abc2svg.clip.set_hooks);
// export
	"clone",
	"errs",
	"syntax",
// hooks
	[ "do_pscom", "abc2svg.clip.do_pscom" ],
	[ "set_bar_num", "abc2svg.clip.set_bar_num" ]
);

// the module is loaded
abc2svg.modules.clip.loaded = true
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
31
32
33
34
35
36
37
38
39
40
41

42
43
44
45
46
47
48
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


-
+










-
-
+
-
-
-
-






-
+














-
+







// combine.js - module to add a combine chord line
//
// Copyright (C) 2018 Jean-Francois Moine - GPL3+
// Copyright (C) 2018-2019 Jean-Francois Moine - GPL3+
//
// 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	NOTE = 8,		// constants from the abc2svg core
	REST = 10,
    var	C = abc2svg.C
	SL_ABOVE = 0x01,
	SL_BELOW = 0x02,
	SL_AUTO = 0x03,
	SL_DOTTED = 0x08

    // check if voice combine may occur
    function may_combine(s) {
    var	nhd2,
	s2 = s.ts_next

	if (!s2 || (s2.type != NOTE && s2.type != REST))
	if (!s2 || (s2.type != C.NOTE && s2.type != C.REST))
		return false
	if (s2.v == s.v
	 || s2.st != s.st
	 || s2.time != s.time
	 || s2.dur != s.dur)
		return false
	if (s.combine <= 0
	 && s2.type != s.type)
		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 == REST) {
	if (s.type == C.REST) {
		if (s.type == s2.type && s.invis && !s2.invis)
			return false
		return true
	}
	if (s2.a_ly
	 || s2.sl1 || s2.sl2
	 || s2.slur_start || s2.slur_end)
︙
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
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







-
-
+
+

-
-
+
+











-
+



-
+







	}

	s.ymx = 3 * (s.notes[nhd].pit - 18) + 4;
	s.ymn = 3 * (s.notes[0].pit - 18) - 4;

	// force the tie directions
	type = s.notes[0].ti1
	if ((type & 0x0f) == SL_AUTO)
		s.notes[0].ti1 = SL_BELOW | (type & ~SL_DOTTED);
	if ((type & 0x0f) == C.SL_AUTO)
		s.notes[0].ti1 = C.SL_BELOW | (type & ~C.SL_DOTTED);
	type = s.notes[nhd].ti1
	if ((type & 0x0f) == SL_AUTO)
		s.notes[nhd].ti1 = SL_ABOVE | (type & ~SL_DOTTED)
	if ((type & 0x0f) == C.SL_AUTO)
		s.notes[nhd].ti1 = C.SL_ABOVE | (type & ~C.SL_DOTTED)
} // combine_notes()

// combine 2 voices
function do_combine(s) {
	var s2, nhd, nhd2, type

	while (1) {
		nhd = s.nhd;
		s2 = s.ts_next;
		nhd2 = s2.nhd
		if (s.type != s2.type) {	// if note and rest
			if (s2.type != REST) {
			if (s2.type != C.REST) {
				s2 = s;
				s = s2.ts_next
			}
		} else if (s.type == REST) {
		} else if (s.type == C.REST) {
			if (s.invis
			 && !s2.invis)
				delete s.invis
		} else {
			combine_notes.call(this, s, s2)
		}

︙
123
124
125
126
127
128
129
130

131
132
133
134
135
136
137
138

139
140
141
142
143
144
145
118
119
120
121
122
123
124

125
126
127
128
129
130
131
132

133
134
135
136
137
138
139
140







-
+







-
+







	}
} // do_combine()

	var s, s2, g, i, r

	for (s = this.get_tsfirst(); s; s = s.ts_next) {
		switch (s.type) {
		case REST:
		case C.REST:
			if (s.combine == undefined || s.combine < 0)
				continue
			if (may_combine.call(this, s))
				do_combine.call(this, s)
			continue
		default:
			continue
		case NOTE:
		case C.NOTE:
			if (s.combine == undefined || s.combine <= 0)
				continue
			break
		}

		if (!s.beam_st)
			continue
︙
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
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







-
+











-
+







				break
			}
//fixme: may have rests in beam
			if (s2.beam_end)
				break
			do {
				s2 = s2.next
			} while (s2.type != NOTE && s2.type != REST)
			} while (s2.type != C.NOTE && s2.type != C.REST)
		}
		if (!s2)
			continue
		s2 = s
		while (1) {
			do_combine.call(this, s2)
//fixme: may have rests in beam
			if (s2.beam_end)
				break
			do {
				s2 = s2.next
			} while (s2.type != NOTE && s2.type != REST)
			} while (s2.type != C.NOTE && s2.type != C.REST)
		}
	}
    }, // comb_v()

    do_pscom: function(of, text) {
	if (text.slice(0, 13) == "voicecombine ")
		this.set_v_param("combine", text.split(/[ \t]/)[1])
︙
205
206
207
208
209
210
211







212
213
214
215

216
217
218
219
220
221
222
223
224
225
226
227
228
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216

217










218
219
220







+
+
+
+
+
+
+



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



	for (i = 0; i < a.length; i++) {
		if (a[i] == "combine=") {	// %%voicecombine
			curvoice.combine = a[i + 1]
			break
		}
	}
	of(a)
    },

    set_hooks: function(abc) {
	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.modules.hooks.push(abc2svg.combine.set_hooks);
// export
	"set_v_param",
	"sort_pitch",
	"unlksym",
// hooks
	[ "do_pscom", "abc2svg.combine.do_pscom" ],
	[ "new_note", "abc2svg.combine.new_note" ],
	[ "set_stem_dir", "abc2svg.combine.set_stem_dir" ],
	[ "set_vp", "abc2svg.combine.set_vp" ]
);

// the module is loaded
abc2svg.modules.voicecombine.loaded = true
Changes to modules/diag.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// diag.js - module to insert guitar chord diagrams
//
// Copyright (C) 2018 Jean-Francois Moine - GPL3+
// Copyright (C) 2018-2019 Jean-Francois Moine - GPL3+
//
// This module is loaded when "%%diagram" appears in a ABC source.
//
// Parameters
//	%%diagram 1

abc2svg.diag = {
︙
484
485
486
487
488
489
490





491
492
493
494

495
496
497
498
499
500
501
502
503
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498

499






500
501
502







+
+
+
+
+



-
+
-
-
-
-
-
-




    set_fmt: function(of, cmd, param, lock) {
	if (cmd == "diagram") {
		this.cfmt().diag = param
		return
	}
	of(cmd, param, lock)
    },

    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.modules.hooks.push(abc2svg.diag.set_hooks);
// export
	"deco_cnv",
// hooks
	[ "output_music", "abc2svg.diag.output_music" ],
	[ "set_format", "abc2svg.diag.set_fmt" ]
);

// the module is loaded
abc2svg.modules.diagram.loaded = true
Added 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
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
// equalbars.js - module to set equal spaced measure bars
//
// Copyright (C) 2018-2019 Jean-Francois Moine - GPL3+
//
// 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()
    },

    // get the equalbars parameter
    set_fmt: function(of, cmd, param, lock) {
	if (cmd == "equalbars")
		this.cfmt().equalbars = this.get_bool(param)
	else
		of(cmd, param, lock)
    },

    // adjust the symbol offsets of a music line
    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

	// search the first note/rest/bar
	for (s2 = tsfirst; s2; s2 = s2.ts_next) {
		if (!s2.seqst)
			continue
		switch (s2.type) {
		default:
			continue
		case C.GRACE:
		case C.MREST:
		case C.NOTE:
		case C.REST:
		case C.SPACE:
			break
		}
		break
	}
	if (!s2)
		return

	// build an array of the bars
	t0 = t = s2.time
	for (s = s2; s.ts_next; s = s.ts_next) {
		if (s.type == C.BAR && s.seqst) {
			bars.push([s, s.time - t]);
			t = s.time
		}
	}
	bars.push([s, s.time - t]);
	t = s.time
	if (s.dur)
		t += s.dur;

	n = bars.length
	if (n <= 1)
		return				// one or no bar

	// set the measure parameters
	x = s2.type == C.GRACE ? s2.extra.x : s2.x;
	d = this.equalbars_d
	if (!d)
		d = this.equalbars_d = x;	// offset first note/rest

	w = (width - d) / (t - t0)		// width per time unit

	// loop on the bars
	for (i = 0; i < n; i++) {
		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;
			s2 = s2.ts_next
			if (!s2 || s2.seqst)
				break
		}
		if (!s2)
			break
	}
    }, // set_sym_glue()

    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
Changes to modules/grid.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
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

401
402
403

404
405
406
407
408
409
410
411
412

413










414
415
416


-
+




+
+
-
+
+
+
+






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


-
+



-
+


-
+




-
-
-
+
+
+
+

+
-
+
+
+
+
+

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


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








-



-
+






-
+


-
+







-
-
+
+




-
+





-
+
+

+


+


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




-
+





-
-
+
+

-
+






-
-
+
+

-
+






-
+


-
+





+

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



+
-
+



-
-
+
+





+
+
+







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

+

+
+

-
+

+











-
-
-
-
-
-
-
-

+


-
+





-
+
+
+
+
+
+



-
+












-












-
+

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


-
+
+
+
+
+
+



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



// grid.js - module to insert a chord grid before or after a tune
//
// Copyright (C) 2018 Jean-Francois Moine - GPL3+
// Copyright (C) 2018-2019 Jean-Francois Moine - GPL3+
//
// This module is loaded when "%%grid" appears in a ABC source.
//
// Parameters
//	%%grid <n> [include=<list>] [nomusic] [norepeat]
//		<n> = number of columns (1: auto)
//	%%grid 1 | -1	(above the tune | below the tune)
//			> 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
//	%%gridfont font_name size (default: 'serif 16')

abc2svg.grid = {

// function called before tune generation
    do_grid: function() {
    var	C = abc2svg.C,
    var	tsfirst = this.get_tsfirst(),
	voice_tb = this.get_voice_tb()
	tsfirst = this.get_tsfirst(),
	voice_tb = this.get_voice_tb(),

// constants from the abc2svg core
    var	BASE_LEN = 1536,
	BAR = 0,
	METER = 6,
	NOTE = 8,
	REST = 10,
	BLOCK = 16

    var	img, font_cl, cls,
	cfmt = this.cfmt()
	img, font_cl, cls,
	cfmt = this.cfmt(),
	grid = cfmt.grid

function get_beat(s) {
    var	beat = BASE_LEN / 4
    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 = BASE_LEN / s.a_meter[0].bot[0] |0
	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 = BASE_LEN / 8 * 3
		beat = C.BLEN / 8 * 3
	return beat
} // get_beat()

// generate the grid
function build_grid(chords, bars, font) {
    var	i, j, nr, line, bar, bar2, chord, cell, w, hr, x0, x, y,
	wmx = 0,
function build_grid(chords, bars, font, wmx) {
    var	i, j, k, l, nr, line, bar, w, hr, x0, x, y, yl,
	cell = '',
	pcell = '',
	cells = [],
	nc = grid.n
	nc = chords.length % 6 == 0 ? 6 : 8;	// number of columns

	// set some chord(s) in each cell
	function set_chords() {
	    var	i, ch,
		pch = '-'

	if (nc > chords.length)
		nc = chords.length;
		for (i = 0; i < chords.length; i++) {
			ch = chords[i]
			if (!ch[0])
				ch[0] = pch
			if (ch.length == 0)
				continue
			if (ch.length == 1) {
				pch = ch[0]
				continue
			}
			if (ch.length == 2) {
				ch[2] = ch[1];
				ch[1] = null;
				pch = ch[2]
				continue
			}
			if (ch.length == 3) {
				pch = ch[2]
				continue
			}
			if (!ch[2])
				ch[2] = ch[1] || ch[0];
			pch = ch[3]
		}
	} // set_chords()

	// set some chords in each cell
	set_chords()

	// build the content of the cells
	nr = 0
	for (i = 0; i < chords.length; i++) {
		if (i % nc == 0)
	if (!grid.ls) {
			nr++;			// number of rows
		chord = chords[i]
		cells = chords
		if (chord.length == 0) {
			cell = '%'
		} else {
	} else {				// with list of mesure numbers
			cell = ''
			for (j = 0; j < chord.length; j++) {
				if (chord[j]) {
					if (j != 0)
						cell += ' / ';
					cell += chord[j]
				} else if (j == 0) {
					cell += '%'
				}
			}
		}
		bar = bars[i];
		if (bar[bar.length - 1] == ':')
			cell = '  ' + cell
		bar2 = bars[i + 1]
		if (bar2 && bar2[0] == ':')
			cell += '  ';
		cells.push(cell)

		// and find their max width
		if (bar[bar.length - 1] == ':')
			cell += '  '
		if (bar2 && bar2[0] == ':')
			cell += '  ';
		bar = bars;
		bars = []
		for (i = 0; i < grid.ls.length; i++) {
			l = grid.ls[i]
			if (l.indexOf('-') < 0)
				l = [l, l]
			else
				l = l.split('-')
			for (k = l[0] - 1; k < l[1]; k++) {
				if (!chords[k])		// error
					break
				cells.push(chords[k]);
				bars.push(bar[k])
			}
		}
	}

	// get the number of columns and rows
	if (nc < 0)
		nc = -nc
	if (nc < 3)				// auto
		nc = cells.length % 6 == 0 ? 6 : 8
		w = this.strwh(cell)[0]
		if (w > wmx)
			wmx = w
	}
	if (wmx < 20)
		wmx = 20;
	if (nc > cells.length)
		nc = cells.length;
	nr = ((cells.length + nc - 1) / nc) |0;

	hr = font.size * 2
	if (wmx < hr * 1.4)
		wmx = hr * 1.4;				// cell width

	w = wmx * nc
	if (w > img.width) {
		nc /= 2;
		nr *= 2;
		w /= 2
	}

	// build the SVG image
	hr = font.size + 8;		// vert: 4 - cell - 4
	line = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1"\n\
	xmlns:xlink="http://www.w3.org/1999/xlink"\n\
	color="black" width="' + img.width.toFixed(0) +
			'px" height="' + (hr * nr + 6).toFixed(0) + 'px"'
			'px" height="' + (hr * nr + 6).toFixed(0) + 'px"';
	i = cfmt.bgcolor
	if (i)
		line += ' style="background-color: ' + i + '"';
	line += '>\n<style type="text/css">\n\
.mid {text-anchor:middle}\n'

	if (cfmt.fullsvg)
	if (cfmt.fullsvg || grid.nomusic)
		line += '\
.stroke {stroke: currentColor; fill: none}\n\
.' + font_cl + ' {' + this.style_font(font.name + '.' + font.size) +  '}\n'
.' + font_cl + ' {' + this.style_font(font) +  '}\n';
	line += '</style>\n'

	// draw the lines
	line += '<path class="stroke" d="\n';
	x0 = (img.width - w) / 2;
	y = 1
	for (j = 0; j <= nr; j++) {
		line += 'M' + x0.toFixed(2) + ' ' + y.toFixed(2) +
			'h' + w.toFixed(2)+ '\n';
		line += 'M' + x0.toFixed(1) + ' ' + y.toFixed(1) +
			'h' + w.toFixed(1)+ '\n';
		y += hr
	}
	x = x0
	for (i = 0; i <= nc; i++) {
		line += 'M' + x.toFixed(2) + ' 1v' + (hr * nr).toFixed(2) + '\n';
		line += 'M' + x.toFixed(1) + ' 1v' + (hr * nr).toFixed(1) + '\n';
		x += wmx
	}
	line += '"/>\n';

	// insert the chords
	y = -1 - hr * .2
	y = 1 - hr / 2 + font.size * .3;
	yl = 1
	for (i = 0; i < cells.length; i++) {
		cell = cells[i]
		if (i % nc == 0) {
			y += hr;			// new row
			yl += hr;
			x = x0 + wmx / 2
		}
		if (cell.length > 1) {
			line += '<path class="stroke" stroke-width="1" d="M' +
				(x - wmx / 2).toFixed(1) + ' ' +
				yl.toFixed(1) + 'l' +
				wmx.toFixed(1) + ' -' + hr.toFixed(1) +
				'"/>\n';
			if (cell[1]) {
			    line += '<path class="stroke" stroke-width="1" d="M' +
				(x - wmx / 2).toFixed(1) + ' ' +
				(yl - hr).toFixed(1) + 'l' +
				(wmx / 2).toFixed(1) + ' ' + (hr / 2).toFixed(1) +
				'"/>\n';
			    line += '<text class="' + cls + '" style="font-size:' +
				(font.size * .72).toFixed(1) + '" x="' +
				(x - wmx / 3).toFixed(1) + '" y="' +
				y.toFixed(1) + '">' +
				cell[0] + '</text>\n';
			    line += '<text class="' + cls + '" style="font-size:' +
				(font.size * .72).toFixed(1) + '" x="' +
				x.toFixed(1) + '" y="' +
				(y - hr / 3).toFixed(1) + '">' +
				cell[1] + '</text>\n'
			} else {
			    line += '<text class="' + cls + '" style="font-size:' +
				(font.size * .72).toFixed(1) + '" x="' +
				(x - wmx * .2).toFixed(1) + '" y="' +
				(y - hr / 4).toFixed(1) + '">' +
				cell[0] + '</text>\n'
			}
			if (cell.length >= 3) {
			  if (cell[3]) {
			    line += '<path class="stroke" stroke-width="1" d="M' +
				x.toFixed(1) + ' ' +
				(yl - hr / 2).toFixed(1) + 'l' +
				(wmx / 2).toFixed(1) + ' ' + (hr / 2).toFixed(1) +
				'"/>\n';
			    line += '<text class="' + cls + '" style="font-size:' +
				(font.size * .72).toFixed(1) + '" x="' +
				x.toFixed(1) + '" y="' +
				(y + hr / 3).toFixed(1) + '">' +
				cell[2] + '</text>\n';
			    line += '<text class="' + cls + '" style="font-size:' +
				(font.size * .72).toFixed(1) + '" x="' +
				(x + wmx / 3).toFixed(1) + '" y="' +
				y.toFixed(1) + '">' +
				cell[3] + '</text>\n'
			  } else {
			    line += '<text class="' + cls + '" style="font-size:' +
				(font.size * .72).toFixed(1) + '" x="' +
				(x + wmx * .2).toFixed(1) + '" y="' +
				(y + hr / 4).toFixed(1) + '">' +
				cell[2] + '</text>\n'
			  }
			}
		} else {
		line += '<text class="' + cls + '" x="' +
			x.toFixed(2) + '" y="' + y.toFixed(2) + '">' +
			cells[i] + '</text>\n';
			line += '<text class="' + cls + '" x="' +
				x.toFixed(1) + '" y="' + y.toFixed(1) + '">' +
				cell[0] + '</text>\n'
		}
		x += wmx
	}

	// show the repeat signs
	y = -1 - hr * .2;
	y = 1 - hr / 2 + font.size * .3;
	x = x0
	for (i = 0; i < bars.length; i++) {
		bar = bars[i]
		if (bar[0] == ':')
			line += '<text class="' + cls + '" x="' +
				(x - 5).toFixed(2) +
				'" y="' + y.toFixed(2) +
				(x - 5).toFixed(1) +
				'" y="' + y.toFixed(1) +
				'" style="font-weight:bold;font-size:' +
			(font.size + 2).toFixed(2) + '">:|</text>\n'
			(font.size + 2).toFixed(1) + '">:</text>\n'
		if (i % nc == 0) {
			y += hr;			// new row
			x = x0
		}
		if (bar[bar.length - 1] == ':')
			line += '<text class="' + cls + '" x="' +
				(x + 5).toFixed(2) +
				'" y="' + y.toFixed(2) +
				(x + 5).toFixed(1) +
				'" y="' + y.toFixed(1) +
				'" style="font-weight:bold;font-size:' +
			(font.size + 2).toFixed(2) + '">|:</text>\n'
			(font.size + 2).toFixed(1) + '">:</text>\n'
		x += wmx
	}

	return line + '</svg>'
} // build_grid()

    var	s, beat, cur_beat, i, beat_i, p_voice, n, font,
    var	s, beat, cur_beat, i, beat_i, p_voice, n, font, wm, bt, w, wmx, rep,
	bars = [],
	chords = [],
	chord = []
	chord = [];

	img = this.get_img();

	// get the beat
	beat = get_beat(voice_tb[0].meter);
	wm = voice_tb[0].meter.wmeasure;

	// set the text style
	if (!cfmt.gridfont)
		this.param_set_font("gridfont", "serif 16");
	font = this.get_font('grid');
	font_cl = this.font_class(font)
	cls = font_cl + " mid";
	this.set_font('grid');		// (for strwh())

	// scan the tune
	cur_beat = beat_i = n = 0;
	// scan the first voice of the tune
	cur_beat = beat_i = n = wmx = 0;
	bars.push('|')
	for (s = voice_tb[0].sym; s; s = s.next) {
		while (s.time > cur_beat) {
			if (beat_i < 3)		// only 2, 3 or 4 beats / measure...
			beat_i++;
				beat_i++;
			cur_beat += beat
		}
		switch (s.type) {
		case NOTE:
		case REST:
		case C.NOTE:
		case C.REST:
			if (s.a_gch) {		// 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] = s.a_gch[i].text;
							w = this.strwh(chord[beat_i])[0]
							if (w > wmx)
								wmx = w;
							n++
						}
						break
					}
				}
			}
			break
		case BAR:
			if (s.time < beat) {		// if anacrusis
				bars[0] = s.bar_type;
		case C.BAR:
			bt = grid.norep ? '|' : s.bar_type
			if (s.time < wm) {		// if anacrusis
				if (chord.length) {
					chords.push(chord);
					bars.push(bt)
				} else {
					bars[0] = bt
//				chord = [];
				beat_i = 0;
				cur_beat = s.time	// re-synchronize
				break
			}
			if (s.time != cur_beat)		// if out of time
				break
			chords.push(chord);
			bars.push(s.bar_type);
				}
			} else {
				if (!s.bar_num)		// if not normal measure bar
					break
				chords.push(chord);
				bars.push(bt)
			}
			chord = [];
			cur_beat = s.time;	// synchronize in case of error
			beat_i = 0
			if (bt.indexOf(':'))
				rep = true	// some repeat
			break
		case METER:
		case C.METER:
			beat = get_beat(s)
			wm = s.wmeasure
			break
		}
	}
	if (n == 0)				// no chord in this tune
		return

	if (chord.length != 0) {
		bars.push('')
		chords.push(chord)
	}

	// set the text style
	if (!this.cfmt().gridfont)
		this.param_set_font("gridfont", "serif 16");
	font = this.get_font('grid');
	font_cl = this.font_class(font)
	cls = font_cl + " mid";
	this.set_font('grid');		// (for strwh())

	// create the grid
	wmx += this.strwh(rep ? '    ' : '  ')[0];
	p_voice = voice_tb[this.get_top_v()]
	s = {
		type: BLOCK,
		type: C.BLOCK,
		subtype: 'ml',
		dur: 0,
		time: 0,
		p_v: p_voice,
		v: p_voice.v,
		text: build_grid.call(this, chords, bars, font)
		text: build_grid.call(this, chords, bars, font, wmx)
	}

	if (grid.nomusic) {		// if no music
		this.set_tsfirst(s)
		return
	}

	// and insert it in the tune
	if (cfmt.grid < 0) {		// below
	if (cfmt.grid.n < 0) {		// below
		for (var s2 = tsfirst; s2.ts_next; s2 = s2.ts_next)
			;
		s.time = s2.time;
		s.prev = p_voice.last_sym;
		s.ts_prev = s2;
		p_voice.last_sym.next = s;
		s2.ts_next = s
	} else {			// above
		s.time = 0;
		s.next = p_voice.sym;
		s.ts_next = tsfirst;
		tsfirst.ts_prev = s;
		tsfirst = s;
		this.set_tsfirst(s);
		p_voice.sym.prev = s;
		p_voice.sym = s
	}
    }, // do_grid()

    output_music: function(of) {
	if (this.cfmt().grid)
		abc2svg.grid.do_grid.call(this);
	of()
    },

    set_fmt: function(of, cmd, param, lock) {
    set_fmt: function(of, cmd, parm, lock) {
	if (cmd == "grid") {
		if (!parm)
			parm = "1";
		parm = parm.split(/\s+/)
		var grid = {n: Number(parm.shift())}
		if (isNaN(grid.n)) {
			if (parm.length) {
				this.syntax(1, this.errs.bad_val, "%%grid")
				return
			}
			grid.n = 1
		}
		while (parm.length) {
			var item = parm.shift()
			if (item == "norepeat")
				grid.norep = true
			else if (item == "nomusic")
				grid.nomusic = true
			else if (item.slice(0, 8) == "include=")
				grid.ls = item.slice(8).split(',')
		}
		this.cfmt().grid = param
		this.cfmt().grid = grid
		return
	}
	of(cmd, param, lock)
	of(cmd, parm, lock)
    },

    set_hooks: function(abc) {
	abc.output_music = abc2svg.grid.output_music.bind(abc, abc.output_music);
	abc.set_format = abc2svg.grid.set_fmt.bind(abc, abc.set_format)
    }
} // grid

abc2svg.modules.hooks.push(
abc2svg.modules.hooks.push(abc2svg.grid.set_hooks);
// export
	"font_class",
	"get_font",
	"param_set_font",
	"set_font",
	"strwh",
// hooks
	[ "output_music", "abc2svg.grid.output_music" ],
	[ "set_format", "abc2svg.grid.set_fmt" ]
)

// the module is loaded
abc2svg.modules.grid.loaded = true
Changes to modules/grid2.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
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


-
+


















-








+
+







// grid2.js - module to replace a voice in the music by a chord grid
//
// Copyright (C) 2018 Jean-Francois Moine - GPL3+
// Copyright (C) 2018-2019 Jean-Francois Moine - GPL3+
//
// This module is loaded when "%%grid2" appears in a ABC source.
//
// Parameters
//	%%grid2 y
// This command must appear in a voice.

abc2svg.grid2 = {

// function called before tune generation
    do_grid: function() {
    var s, v, p_v,
	voice_tb = this.get_voice_tb()

	for (v = 0; v < voice_tb.length; v++) {
		p_v = voice_tb[v]
		if (!p_v.grid2)
			continue
		p_v.stafflines = '...';		// no staff lines
		p_v.clef.invis = true;		// no clef
		p_v.key.k_sf = p_v.key.k_a_acc = 0; // no key signature
		p_v.staffnonote = 2		// draw the staff
		for (s = p_v.sym; s; s = s.next) {
			if (s.dur) {		// set all notes
				s.invis = true;	//  as invisible
				delete s.sl1;	//  with no slur
				s.ti1 = 0	//  and no tie
				if (s.tf)	// don't show the tuplets
					s.tf[0] = 1
			}
		}
	}
    }, // do_grid()

    // draw the chord symbol in the middle of the staff
    draw_chosym: function(s) {
︙
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
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







-
+


-
+
+

+



+
+
+
+
+
+



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



    },

    output_music: function(of) {
	abc2svg.grid2.do_grid.call(this);
	of()
    },

    set_format: function(of, cmd, param, lock) {
    set_fmt: function(of, cmd, param, lock) {
	if (cmd == "grid2") {
	    var	curvoice = this.get_curvoice()
		if (curvoice)
		if (curvoice) {
			this.set_v_param("stafflines", "...");	// no staff lines
			curvoice.grid2 = param
		}
		return
	}
	of(cmd, param, lock)
    },

    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.modules.hooks.push(abc2svg.grid2.set_hooks);
// export
	"set_dscale",
	"set_font",
	"use_font",
	"xy_str",
// hooks
	[ "draw_gchord",  "abc2svg.grid2.draw_gchord" ],
	[ "output_music", "abc2svg.grid2.output_music" ],
	[ "set_format", "abc2svg.grid2.set_format" ]
);

// the module is loaded
abc2svg.modules.grid2.loaded = true
Added modules/page.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
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
// page.js - module to generate one SVG image per page
//
// Copyright (C) 2018-2019 Jean-Francois Moine - GPL3+
//
// This module is loaded when "%%pageheight" appears in a ABC source.
//
// Parameters
//	%%pageheight <unit>

abc2svg.page = {

    // output a new block
    img_out: function(page, p) {
    var	cur_img_out = user.img_out;

	page.user_out(p)
	
	// user.img_out may have been changed ..
	if (user.img_out != cur_img_out) {
		page.user_out = user.img_out;
		if (cur_img_out == page.img_out_sav) {	// .. by the backend
			user.img_out = abc2svg.page.img_in.bind(page.abc);
			page.img_out_sav = user.img_out	// keep our reference
		} else {
			user.img_out = cur_img_out	// .. by an other extension
		}
	}
    },

    //function called at end of generation
    abc_end: function(of) {
    var page = this.page
	if (page.h) {
		abc2svg.page.img_out(page,
			page.head + page.style + page.hf + page.out + '</svg>');
		abc2svg.page.img_out(page, '</div>');
		page.h = 0;
		page.out = ''
	}
	of()
    }, // abc_end()

    // define the SVG header of the page
    svg_head: function(cfmt) {
	return '<svg xmlns="http://www.w3.org/2000/svg" version="1.1"\n\
 xmlns:xlink="http://www.w3.org/1999/xlink"\n\
 color="black" class="music" stroke-width=".7"\n\
 width="' + cfmt.pagewidth.toFixed(0) +
 'px" height="' + cfmt.pageheight.toFixed(0) + 'px"' +
 (cfmt.bgcolor ? (' style="background-color: ' + cfmt.bgcolor + '"') : '') +
 '>\n'
    }, // svg_head()

    // start a new page
    svg_out: function(abc, page) {
    var	h,
	cfmt = abc.cfmt()

	function header_footer(str) {
	    var	c, i, t,
		nl = 1,
		j = 0,
		r = ["", "", ""]

		if (str[0] == '"')
			str = str.slice(1, -1)
		if (str.indexOf('\t') < 0)		// if no TAB
			str = '\t' + str		// center

		for (i = 0; i < str.length; i++) {
			c = str[i]
			switch (c) {
			case '\t':
				if (j < 2)
					j++		// next column
				continue
			case '\\':			// hope '\n'
				for (j = 0; j < 3; j++)
					r[j] += '\n';
				nl++;
				j = 0;
				i++
				continue
			default:
				r[j] += c
				continue
			case '$':
				break
			}
			c = str[++i]
			switch (c) {
			case 'd':	// cannot know the modification date of the file
				break
			case 'D':
				r[j] += new Date().toUTCString()
				break
			case 'F':
				r[j] += abc.get_fname()
				break
			case 'I':
				c = str[++i]
			case 'T':
				t = abc.info()[c]
				if (t)
					r[j] += t.split('\n', 1)[0]
				break
			case 'P':
			case 'Q':
				t = c == 'P' ? page.pn : page.pna
				switch (str[i + 1]) {
				case '0':
					i++
					if (!(t & 1))
						r[j] += t
					break
				case '1':
					i++
					if (t & 1)
						r[j] += t
					break
				default:
					r[j] += t
					break
				}
				break
			case 'V':
				r[j] += "abc2svg-" + abc2svg.version
				break
//fixme: handle the font changes ($<number>) ?
			}
		}
		r[4] = nl		// number of lines
		return r
	} // header_footer()

	function font_class(font) {
		if (font.class)
			return 'f' + font.fid + cfmt.fullsvg + ' ' + font.class
		return 'f' + font.fid + cfmt.fullsvg
	}

	// generate a header or footer
	function gen_hf(up, font, str) {
	    var	a, i, j, k, x, y, y0, s,
		fh = font.size * 1.1,
		pos = [ '">',
			'" text-anchor="middle">',
			'" text-anchor="end">' ]

		if (str[0] == '-') {		// not on 1st page
			if (page.pn == 1)
				return 0
			str = str.slice(1)
		}

		a = header_footer(str)
		if (up)
			y0 = page.hbase + fh
		else
			y0 = cfmt.pageheight - page.topmargin - fh * a[4]
		for (i = 0; i < 3; i++) {
			str = a[i]
			if (!str)
				continue
			if (i == 0)
				x = cfmt.leftmargin
			else if (i == 1)
				x = cfmt.pagewidth / 2
			else
				x = cfmt.pagewidth - cfmt.rightmargin;
			x += page.gutter;
			y = y0;
			k = 0
			while (1) {
				j = str.indexOf('\n', k)
				if (j >= 0)
					s = str.slice(k, j)
				else
					s = str.slice(k)
				if (s)
					page.hf += '<text class="' +
							font_class(font) +
							'" x="' + x.toFixed(1) +
							'" y="' + y.toFixed(1) +
							pos[i] +
							s + '</text>\n'
				if (j < 0)
					break
				k = j + 1;
				y += fh
			}
					
		}
		return fh * a[4]
	} // gen_hf()

	// svg_out()

	// start a new SVG container for the page
	abc2svg.page.img_out(abc.page, '<div>');

	page.hbase = page.topmargin;
	page.hmax = cfmt.pageheight - page.topmargin - page.botmargin;
	page.pn++;
	page.pna++;
	page.gutter = -page.gutter;

	// define the header/footer
	page.hf = ''
	if (page.header) {
		h = gen_hf(true, abc.get_font("header"), page.header);
		page.hmax -= h;
		page.hbase += h
	}
	if (page.footer)
		page.hmax -= gen_hf(false, abc.get_font("footer"), page.footer);

	page.h = page.hb = 0;
	page.out = ''
    }, // svg_out()

    // handle the output flow of the abc2svg generator
    img_in: function(p) {
    var h, i,
	page = this.page

	// copy a block
	function blkcpy(page) {
	    var b, h, i

		if (!page.blk || !page.blk.length) {
			page.blk = null
			return
		}
		h = page.hb
		for (i = 0; i < page.blk.length; i++) {
			b = page.blk[i]
			page.out += b.p
			    .replace(/<svg(.|\n)*?>/,
				'<g transform="translate(' +
				page.gutter.toFixed(1) + ', ' +
				(h + page.hbase).toFixed(1) +
				')">')
			    .replace('</svg>', '</g>\n');
			h += b.h
		}
		page.blk = null
		page.h = h
	} // blkcpy()

	// get the style from the image and remove it from the block
	function get_style(p, page) {
	    var	i,
		sty = p.match(/<style.*?>((.|\n)*?)<\/style>/)

		if (!sty)
			return p
		sty = sty[1].split('\n')
		if (!page.style)
			page.style = '<style type="text/css">\n</style>\n'
		for (i = 0; i < sty.length; i++) {
			if (page.style.indexOf(sty[i]) < 0)
				page.style = page.style.replace('</style>\n',
						sty[i] + '\n</style>\n')
		}
		return p.replace(/<style(.|\n)*?\/style>\n/, '')
	} // get_style()

	// img_in()
	switch (p.slice(0, 4)) {
	case "<div":				// new block (tune / paragraph)
		if (p.indexOf('newpage') > 0
		 || (page.oneperpage && this.info().X)
		 || page.h == 0) {
			if (page.h) {
				abc2svg.page.img_out(page,
						page.head + page.style + page.hf +
						page.out + '</svg>');
				abc2svg.page.img_out(page, '</div>')
			}
			abc2svg.page.svg_out(this, page)
			if (!this.cfmt().fullsvg)
				page.style = ''
		}
		page.blk = [];
		page.hb = page.h
		break
	case "<svg":				// SVG image
		h = Number(p.match(/height="(\d+)px"/)[1])
		if (h + page.h >= page.hmax) {		// if page overflow
			if (!page.out)		// if at start of page
				blkcpy(page);	// output the start of tune
			abc2svg.page.img_out(page,
					page.head + page.style + page.hf +
					page.out + '</svg>');
			abc2svg.page.img_out(page, '</div>');
			abc2svg.page.svg_out(this, page);
			page.h = page.hb = this.cfmt().topspace;
			if (page.blk)
				blkcpy(page)	// output the start of tune
			if (!this.cfmt().fullsvg)
				page.style = ''
		}

		p = get_style(p, page)

		// if no overflow yet, keep the block
		if (page.blk) {
			page.blk.push({p: p, h: h})
		} else {
			page.out += p
			    .replace(/<svg(.|\n)*?>/,
				'<g transform="translate(' +
				page.gutter.toFixed(1) + ', ' +
				(page.h + page.hbase).toFixed(1) + ')">')
			    .replace('</svg>', '</g>\n')
		}
		page.h += h
		break
	case "</di":				// end of block
		blkcpy(page);
		page.out += '\n'
		break
//	default:
////fixme: %%beginml cannot be treated (no information about its height)
////		page.out += p
//		break
	}
    }, // img_in()

    // handle the page related parameters
    set_fmt: function(of, cmd, parm, lock) {
    var	v,
	cfmt = this.cfmt(),
	page = this.page

	if (cmd == "pageheight") {
		v = this.get_unit(parm)
		if (isNaN(v)) {
			this.syntax(1, errs.bad_val, '%%' + cmd)
			return
		}
		cfmt.pageheight = v

		// if first definition, install the hook
		if (!page && user.img_out && abc2svg.abc_end) {
			this.page = page = {
				abc: this,
				topmargin: 38,	// 1cm
				botmargin: 38,	// 1cm
				gutter: 0,
				h: 0,		// current page height
				pn: 0,		// page number
				pna: 0,		// absolute page number
				out: '',	// page content
				head: abc2svg.page.svg_head(cfmt),
				user_out: user.img_out
			}

			// don't let the backend handle the header/footer
			if (cfmt.header) {
				page.header = cfmt.header;
				cfmt.header = null
			}
			if (cfmt.footer) {
				page.footer = cfmt.footer;
				cfmt.footer = null
			}

			// get the previously defined page parameters
			if (cfmt.botmargin) {
				v = this.get_unit(cfmt.botmargin)
				if (!isNaN(v))
					page.botmargin = v
			}
			if (cfmt.topmargin) {
				v = this.get_unit(cfmt.topmargin)
				if (!isNaN(v))
					page.topmargin = v
			}
			if (cfmt.gutter) {
				v = this.get_unit(cfmt.gutter)
				if (!isNaN(v))
					page.gutter = (page.pn & 1) ? v : -v
			}
			if (cfmt.oneperpage)
				page.oneperpage = this.get_bool(cfmt.oneperpage)

			// set the hooks
			user.img_out = abc2svg.page.img_in.bind(this);
			page.img_out_sav = user.img_out;
			abc2svg.abc_end = abc2svg.page.abc_end.bind(this,
								abc2svg.abc_end)
		}
		return
	}
	if (page) {
		switch (cmd) {
		case "header":
		case "footer":
			page[cmd] = parm
			return
		case "newpage":
			if (!parm)
				break
			v = Number(parm)
			if (isNaN(v)) {
				this.syntax(1, errs.bad_val, '%%' + cmd)
				return
			}
			page.pn = v - 1
			return
		case "gutter":
		case "botmargin":
		case "topmargin":
			v = this.get_unit(parm)
			if (isNaN(v)) {
				this.syntax(1, errs.bad_val, '%%' + cmd)
				return
			}
			page[cmd] = v
			if (cmd == "gutter" && !(page.pn & 1))
				page.gutter = -page.gutter
			return
		case "oneperpage":
			page[cmd] = this.get_bool(parm)
			return
		}
	}
	of(cmd, parm, lock)
	if (page) {
		switch (cmd) {
		case "pagewidth":
		case "bgcolor":
			page.head = abc2svg.page.svg_head(cfmt)
			break
		}
	}
    }, // set_fmt()

    set_hooks: function(abc) {
	abc.set_format = abc2svg.page.set_fmt.bind(abc, abc.set_format)
    }
} // page

abc2svg.modules.hooks.push(abc2svg.page.set_hooks);

// the module is loaded
abc2svg.modules.pageheight.loaded = true
Changes to modules/perc.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// perc.js - module to handle %%percmap
//
// Copyright (C) 2018 Jean-Francois Moine - GPL3+
// Copyright (C) 2018-2019 Jean-Francois Moine - GPL3+
//
// This module is loaded when "%%percmap" appears in a ABC source.
//
// Parameters (from W. Vree)
//	%%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.
︙
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
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







-
+











-
+
-








    // convert a drum instrument to a note
    function tonote(p) {
    var	i, j, s,
	pit = Number(p)

	if (isNaN(pit)) {
		s = p.match(/^([_^]*)([A-Ga-g])([,']*)$/)	// '
		s = p.match(/^([_^=]*)([A-Ga-g])([,']*)$/)	// '
		if (s) {				// note name
			i = "CDEFGABcdefgab".indexOf(s[2]) + 16
			switch(s[3]) {
			case "'":
				i += 7 * s[3].length
				break
			case ',':
				i -= 7 * s[3].length
				break
			}
			note = {
				pit: i,
				pit: i
				apit: i
			}
			switch (s[1]) {
			case '^': note.acc = 1; break
			case '_': note.acc = -1; break
			}
			return note
		}
︙
186
187
188
189
190
191
192
193

194
195
196
197
198
199
200
201
185
186
187
188
189
190
191

192

193
194
195
196
197
198
199







-
+
-







	if (!pit)
		return

	p = ((pit / 12) | 0) * 7 - 19;	// octave
	pit = pit % 12;			// in octave
	p += pits[pit];
	note = {
		pit: p,
		pit: p
		apit: p
	}
	if (accs[pit])
		note.acc = accs[pit]
	return note
    } // tonote()

    // normalize a note for mapping
︙
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
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







-
+









-
+







-
+








    var	n, v,
	maps = this.get_maps(),
	a = parm.split(/\s+/);

	n = norm(a[1])
	if (!n) {
		this.syntax(1, abc.errs.bad_val, "%%percmap")
		this.syntax(1, this.errs.bad_val, "%%percmap")
		return
	}
	if (this.cfmt().sound != "play") {		// !play
		if (!a[3])
			return
		if (!maps.MIDIdrum)
			maps.MIDIdrum = {}
		v = tonote(n)
		if (!v) {
			this.syntax(1, abc.errs.bad_val, "%%percmap")
			this.syntax(1, this.errs.bad_val, "%%percmap")
			return
		}
		delete v.acc
		maps.MIDIdrum[n] = [[a[3]], v]
	} else {					// play
		v = tonote(a[2])
		if (!v) {
			this.syntax(1, abc.errs.bad_val, "%%percmap")
			this.syntax(1, this.errs.bad_val, "%%percmap")
			return
		}
		if (!maps.MIDIdrum)
			maps.MIDIdrum = {}
		maps.MIDIdrum[n] = [null, v]
	}
	this.set_v_param("perc", "MIDIdrum")
︙
272
273
274
275
276
277
278





279
280
281
282

283
284
285
286
287
288
289
290
291
292
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284

285







286
287
288







+
+
+
+
+



-
+
-
-
-
-
-
-
-



	else
		of(text)
    },

    set_vp: function(of, a) {
	abc2svg.perc.set_perc.call(this, a);
	of(a)
    },

    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.modules.hooks.push(abc2svg.perc.set_hooks);
// export
	"errs",
	"syntax",
// hooks
	[ "do_pscom", "abc2svg.perc.do_pscom" ],
	[ "set_vp", "abc2svg.perc.set_vp" ]
);

// the module is loaded
abc2svg.modules.percmap.loaded = true
Changes to modules/psvg.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// psvg.js - small PS to SVG convertor for abc2svg

// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-2019 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.
︙
69
70
71
72
73
74
75
76
77


78
79
80
81
82
83
84
69
70
71
72
73
74
75


76
77
78
79
80
81
82
83
84







-
-
+
+







			if (gcur.xoffs || gcur.yoffs) {
				var	x, xtmp = gcur.xoffs,
					y = gcur.yoffs,
					_sin = gcur.sin,
					_cos = gcur.cos;
				x = xtmp * _cos - y * _sin;
				y = xtmp * _sin + y * _cos;
				svgbuf += " translate(" + x.toFixed(2) + "," +
						y.toFixed(2) + ")";
				svgbuf += " translate(" + x.toFixed(1) + "," +
						y.toFixed(1) + ")";
				x_rot = gcur.xoffs;
				y_rot = gcur.yoffs;
				gcur.xoffs = 0;
				gcur.yoffs = 0
			}
			svgbuf += " rotate(" + gcur.rotate.toFixed(2) + ")"
		}
︙
149
150
151
152
153
154
155
156
157


158
159
160
161
162
163
164
149
150
151
152
153
154
155


156
157
158
159
160
161
162
163
164







-
-
+
+








    function path_def() {
	if (path)
		return
	setg(1);
	gcur.px = gcur.cx;
	gcur.py = gcur.cy;
	path = '<path d="m' + (gcur.xoffs + gcur.cx).toFixed(2) +
		' ' + (gcur.yoffs - gcur.cy).toFixed(2) + '\n'
	path = '<path d="m' + (gcur.xoffs + gcur.cx).toFixed(1) +
		' ' + (gcur.yoffs - gcur.cy).toFixed(1) + '\n'
    }

    function path_end() {
	svgbuf += path;
	path = ''
    }

︙
200
201
202
203
204
205
206
207
208


209
210
211
212
213
214
215
200
201
202
203
204
205
206


207
208
209
210
211
212
213
214
215







-
-
+
+








	if (gcur.cx != undefined) {
		if (path) {
			if (x1 != gcur.cx || y1 != gcur.cy)
				path += 'l'
			else
				path += 'm';
			path += (x1 - gcur.cx).toFixed(2) + " " +
				(-(y1 - gcur.cy)).toFixed(2)
			path += (x1 - gcur.cx).toFixed(1) + " " +
				(-(y1 - gcur.cy)).toFixed(1)
		} else {
			gcur.cx = x1;
			gcur.cy = y1;
			path_def()
		}
	} else {
		if (path)		// should not occur
︙
262
263
264
265
266
267
268
269
270
271



272
273
274
275
276
277
278
262
263
264
265
266
267
268



269
270
271
272
273
274
275
276
277
278







-
-
-
+
+
+







    Psvg.prototype.cy = function() {
	return gcur.cy
    }

    Psvg.prototype.curveto = function(x1, y1, x2, y2, x, y) {
	path_def();
	path += "\tC" + 
		(gcur.xoffs + x1).toFixed(2) + " " + (gcur.yoffs - y1).toFixed(2) + " " +
		(gcur.xoffs + x2).toFixed(2) + " " + (gcur.yoffs - y2).toFixed(2) + " " +
		(gcur.xoffs + x).toFixed(2) + " " + (gcur.yoffs - y).toFixed(2) + "\n";
		(gcur.xoffs + x1).toFixed(1) + " " + (gcur.yoffs - y1).toFixed(1) + " " +
		(gcur.xoffs + x2).toFixed(1) + " " + (gcur.yoffs - y2).toFixed(1) + " " +
		(gcur.xoffs + x).toFixed(1) + " " + (gcur.yoffs - y).toFixed(1) + "\n";
	gcur.cx = x;
	gcur.cy = y
    }

    Psvg.prototype.eofill = function() {
	path_end();
	svgbuf += '" fill-rule="evenodd" fill="currentColor"/>\n'
︙
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
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







-
+

-
+

-
-
+
+








-
-
+
+













-
-
-
+
+
+







-
+

-
+

-
-
+
+







-
-
+
+







	gcur = gc_stack.pop();
	gchg = true
    }

    Psvg.prototype.lineto = function(x, y) {
	path_def()
	if (x == gcur.cx)
		path += "\tv" + (gcur.cy - y).toFixed(2) + "\n"
		path += "\tv" + (gcur.cy - y).toFixed(1) + "\n"
	else if (y == gcur.cy)
		path += "\th" + (x - gcur.cx).toFixed(2) + "\n"
		path += "\th" + (x - gcur.cx).toFixed(1) + "\n"
	else
		path += "\tl" + (x - gcur.cx).toFixed(2) + " " +
			(gcur.cy - y).toFixed(2) + "\n";
		path += "\tl" + (x - gcur.cx).toFixed(1) + " " +
			(gcur.cy - y).toFixed(1) + "\n";
	gcur.cx = x;
	gcur.cy = y
    }

    Psvg.prototype.moveto = function(x, y) {
	gcur.cx = x;
	gcur.cy = y
	if (path) {
		path += "\tM" + (gcur.xoffs + gcur.cx).toFixed(2) + " " +
				(gcur.yoffs - gcur.cy).toFixed(2) + "\n"
		path += "\tM" + (gcur.xoffs + gcur.cx).toFixed(1) + " " +
				(gcur.yoffs - gcur.cy).toFixed(1) + "\n"
	} else if (g == 2) {
		svgbuf += "</text>\n";
		g = 1
	}
    }

    Psvg.prototype.newpath = function() {
	gcur.cx = gcur.cy = undefined
    }

    Psvg.prototype.rcurveto = function(x1, y1, x2, y2, x, y) {
	path_def();
	path += "\tc" + 
		x1.toFixed(2) + " " + (-y1).toFixed(2) + " " +
		x2.toFixed(2) + " " + (-y2).toFixed(2) + " " +
		x.toFixed(2) + " " + (-y).toFixed(2) + "\n";
		x1.toFixed(1) + " " + (-y1).toFixed(1) + " " +
		x2.toFixed(1) + " " + (-y2).toFixed(1) + " " +
		x.toFixed(1) + " " + (-y).toFixed(1) + "\n";
	gcur.cx += x;
	gcur.cy += y
    }

    function rlineto(x, y) {
	path_def()
	if (x == 0)
		path += "\tv" + (-y).toFixed(2) + "\n"
		path += "\tv" + (-y).toFixed(1) + "\n"
	else if (y == 0)
		path += "\th" + x.toFixed(2) + "\n"
		path += "\th" + x.toFixed(1) + "\n"
	else
		path += "\tl" + x.toFixed(2) + " " +
			(-y).toFixed(2) + "\n";
		path += "\tl" + x.toFixed(1) + " " +
			(-y).toFixed(1) + "\n";
	gcur.cx += x;
	gcur.cy += y
    }
    Psvg.prototype.rlineto = rlineto;

    Psvg.prototype.rmoveto = function(x, y) {
	if (path) {
		path += "\tm" + x.toFixed(2) + " " +
				(-y).toFixed(2) + "\n"
		path += "\tm" + x.toFixed(1) + " " +
				(-y).toFixed(1) + "\n"
	} else if (g == 2) {
		svgbuf += "</text>\n";
		g = 1
	}
	gcur.cx += x;
	gcur.cy += y
    }
︙
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
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







-
-
+
+


















-
+







	x = gcur.cx;
	y = gcur.cy
	if (span) {
		svgbuf += "<tspan\n\t";
		output_font(true);
		svgbuf += ">"
	} else if (g != 2) {
		svgbuf += '<text x="' + (x + gcur.xoffs).toFixed(2) + '" y="' +
				(gcur.yoffs - y).toFixed(2) + '">';
		svgbuf += '<text x="' + (x + gcur.xoffs).toFixed(1) + '" y="' +
				(gcur.yoffs - y).toFixed(1) + '">';
		g = 2
	}
	svgbuf += s.replace(/<|>|&|  /g, function(c){
			switch (c) {
			case '<': return "&lt;"
			case '>': return "&gt;"
			case '&': return "&amp;"
			case '  ': return '  '		// space + nbspace
			}
		})
	if (span)
		svgbuf += "</tspan>";
	gcur.cx = x + strw(s)
    }

    Psvg.prototype.stroke = function() {
	path_end()
	if (gcur.linewidth != 0.7)
		svgbuf += '" stroke-width="' + gcur.linewidth.toFixed(2);
		svgbuf += '" stroke-width="' + gcur.linewidth.toFixed(1);
	svgbuf += '" stroke="currentColor" fill="none"' + gcur.dash + '/>\n'
    }

    Psvg.prototype.translate = function(x, y) {
	gcur.xoffs += x;
	gcur.yoffs -= y;
	gcur.cx -= x;
︙
554
555
556
557
558
559
560
561

562
563
564
565
566
567
568
554
555
556
557
558
559
560

561
562
563
564
565
566
567
568







-
+







// common part
function pscall(f, x, y, script) {
	gcur.xorig = gcur.xoffs = abcobj.sx(0);
	gcur.yorig = gcur.yoffs = abcobj.sy(0);
	gcur.cx = 0;
	gcur.cy = 0;
	wps.parse(script +
		(x / abcobj.stv_g().scale).toFixed(2) + ' ' + y.toFixed(2) + ' ' + f);
		(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,
︙
579
580
581
582
583
584
585
586

587
588
589
590
591
592
593
579
580
581
582
583
584
585

586
587
588
589
590
591
592
593







-
+







		defl |= 2
	if (de.s.stem >= 0)
		defl |= 4;

	Os.pop();
	script = '/defl ' + defl + ' def '
	if (de.lden) {
		script += x.toFixed(2) + ' ' + y.toFixed(2) + ' ';
		script += x.toFixed(1) + ' ' + y.toFixed(1) + ' ';
		de2 = de.start;
		x = de2.x;
		y = de2.y + staff_tb[de2.st].y
		if (x > de.x - 20)
			x = de.x - 20
	}
	dd = de.dd
︙
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
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







-
+




















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



/turn{(turn).svg(xygl)3 .call0}.bdef\n\
/umrd{(umrd).svg(xygl)3 .call0}.bdef\n\
/y0{.svg(y0)1 .call}.bdef\n\
/y1{.svg(y1)1 .call}.bdef\n")

} // Psvg()

abc2svg.modules.psvg = {
abc2svg.psvg = {
	do_begin_end: function(of, type, opt, text) {
		if (type != "ps") {
			of(type, opt, text)
			return
		}
		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)
    }
abc2svg.modules.hooks.push(
// export
	"out_arp",
	"out_deco_str",
	"out_deco_val",
	"out_ltr",
	"xygl",
// hooks
	[ "do_begin_end", "abc2svg.modules.psvg.do_begin_end" ],
	[ "psdeco", "abc2svg.modules.psvg.psdeco" ],
} // psvg

abc2svg.modules.hooks.push(abc2svg.psvg.set_hooks);
	[ "psxygl", "abc2svg.modules.psvg.psxygl" ]
);

// the module is loaded
abc2svg.modules.beginps.loaded = true
Added 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
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
// soloffs.js - module to set the X offset of some elements at start of music line
//
// Copyright (C) 2018-2019 Jean-Francois Moine - GPL3+
//
// 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, lock) {
	if (cmd == "soloffs") {
	    var	i, v,
		C = abc2svg.C,
		soloffs = this.cfmt().soloffs = {}

		parm = parm.split(/\s+/)
		while (parm.length) {
			i = parm.shift().split('=')
			v = Number(i[1])
			if (isNaN(v))
				continue		// error
			switch (i[0]) {
//			case 'bar':
//				soloffs[C.BAR] = v
//				break
			case 'part':
				soloffs[C.PART] = v + 10	// see deco.js
				break
			case 'tempo':
				soloffs[C.TEMPO] = v + 16	// see deco.js
				break
			case 'space':
				soloffs[C.SPACE] = v
				break
//			default:
//				// error
//				break
			}
		}
		return
	}
	of(cmd, parm, lock)
    },

    set_sym_glue: function(of, width) {
    var	s,
	C = abc2svg.C,
	tsfirst = this.get_tsfirst(),
	soloffs = this.cfmt().soloffs;

	of(width)		// compute the x offset of the symbols
	if (!soloffs)
		return
	for (s = tsfirst; s; s = s.ts_next) {
		if (s.dur)
			break
		if (soloffs[s.type] != undefined)
			s.x = soloffs[s.type]
	}
    }, // set_sym_glue()

    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
Changes to modules/sth.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
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


-
+














-
-
+
+
+
+




-
-
+
+

-
+







// sth.js - module to set the stem heights
//
// Copyright (C) 2018 Jean-Francois Moine - GPL3+
// Copyright (C) 2018-2019 Jean-Francois Moine - GPL3+
//
// 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(),
	st = s.st,
	s2 = bm.s2
	y = staff_tb[s.st].y,
	s2 = bm.s2,
	y2 = staff_tb[s2.st].y

	if (s.sth)
		s.ys = s.sth
	if (s2.sth)
		s2.ys = s2.sth;
	bm.a = (s.ys- s2.ys) / (s.xs - s2.xs);
	bm.b = s.ys - s.xs * bm.a + staff_tb[st].y
	bm.a = (s.ys + y - s2.ys - y2) / (s.xs - s2.xs);
	bm.b = s.ys - s.xs * bm.a + y
	while (1) {
		s.ys = bm.a * s.xs + bm.b - staff_tb[st].y
		s.ys = bm.a * s.xs + bm.b - y
		if (s.stem > 0)
			s.ymx = s.ys + 2.5
		else
			s.ymn = s.ys - 2.5;
		s = s.next
		if (s == s2)
			break
︙
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
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







-
+





-
-
+
+

+
-
+

-
+



















+
-
-
+
+
+
+
+
+
+


-
+
-
-
-
-
-
-
-
-
-



			s.sth = s.ys
		}
	}
    }, // set_sth()

    calculate_beam: function(of, bm, s1) {
    var	done = of(bm, s1)
	if (done && bm.s2 && s1.sth)
	if (done && bm.s2 && (s1.sth || bm.s2.sth))
		abc2svg.sth.recal_beam.call(this, bm, s1)
	return done
    },

    new_note: function(of, grace, tp_fact) {
    var	NOTE = 8		// constant from the abc2svg core
    var	s = of(grace, tp_fact),
    var	C = abc2svg.C,
	s = of(grace, tp_fact),
	curvoice = this.get_curvoice()

	if (curvoice.sth && s && s.type == NOTE) {
	if (curvoice.sth && s && s.type == C.NOTE) {
		s.sth = curvoice.sth;
		curvoice.sth = null
		curvoice.sth = null	// some stem widths in this voice
	}
	return s
    },

    set_format: function(of, cmd, param, lock) {
	if (cmd == "sth") {
	    var	curvoice = this.get_curvoice()
		if (this.parse.state == 2)
			this.goto_tune()
		if (curvoice)
			curvoice.sth = param.split(/[ \t;-]+/)
		return
	}
	of(cmd, param, lock)
    },

    set_stems: function(of) {
	of();
	abc2svg.sth.set_sth.call(this)
    },
    }


    set_hooks: function(abc) {
	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_format.bind(abc, abc.set_format);
	abc.set_stems = abc2svg.sth.set_stems.bind(abc, abc.set_stems)
    }
} // sth

abc2svg.modules.hooks.push(
abc2svg.modules.hooks.push(abc2svg.sth.set_hooks);
// export
	"goto_tune",
	"parse",
// hooks
	[ "calculate_beam", "abc2svg.sth.calculate_beam" ],
	[ "new_note", "abc2svg.sth.new_note" ],
	[ "set_format", "abc2svg.sth.set_format" ],
	[ "set_stems", "abc2svg.sth.set_stems" ]
);

// the module is loaded
abc2svg.modules.sth.loaded = true
Added modules/temper.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
// temper.js - module to define the temperament
//
// Copyright (C) 2018-2019 Jean-Francois Moine - GPL3+
//
// This module is loaded when "%%temperament" appears in a ABC source.
//
// Parameters
//	%%temperament <list>
// The <list> must contain 12 integer values that are the detune values in cents
// of the 12 notes of the equal scale.
// Examples:
//
// % pythagore (~500 B.C)
// %%temperament +00 +14 +04 -06 +08 -02 +12 +02 +16 +06 -04 +10
//
// % just intonation
// %%temperament +00 -08 -18 -06 -14 -02 -10 +02 -08 -16 -04 -12
//
// % meantone (Pietro Aaron 1523)
// %%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 = {

    // move the temperament to the 1st voice
    set_bar_num: function(of) {
	of()
	if (this.cfmt().temper) {
	    var	v0 = this.get_voice_tb()[0];

		v0.temper = new Float32Array(12)
		for (var i = 0; i < 12; i++)
			v0.temper[i] = this.cfmt().temper[i] / 100
	}
    },

    // get the temperament
    set_fmt: function(of, cmd, param, lock) {
	if (cmd == "temperament") {
	    var	ls = new Float32Array(param.split(/ +/)),
		i = ls.length

		if (i == 12) {
			while (--i >= 0) {
				if (isNaN(parseInt(ls[i])))
					break
			}
			if (i < 0) {
				this.cfmt().temper = ls
				return
			}
		}
		this.syntax(1, this.errs.bad_val, "%%temperament")
		return
	}
	of(cmd, param, lock)
    },

    set_hooks: function(abc) {
	abc.set_bar_num = abc2svg.temper.set_bar_num.bind(abc, abc.set_bar_num);
	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
Changes to package.json.
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
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


-
+















+















+









+





+
+

-

+











-
-
+
+









-
+

-
+

{
  "name": "abc2svg",
  "version": "1.17.4",
  "version": "1.19.1",
  "description": "ABC music notation translator",
  "devDependencies": {
    "uglify-js": "^2.5.0"
  },
  "files": [
    "COPYING",
    "COPYING.LESSER",
    "MIDI-1.js",
    "Scc1t2/",
    "abc2odt",
    "abc2svg",
    "abc2svg-1.js",
    "abc2svg.ttf",
    "abcdoc-1.js",
    "abcemb-1.js",
    "abcemb2-1.js",
    "ambitus-1.js",
    "break-1.js",
    "capo-1.js",
    "clip-1.js",
    "cmdline.js",
    "combine-1.js",
    "diag-1.js",
    "edit-1.css",
    "edit-1.js",
    "edit-1.xhtml",
    "edit-de.js",
    "edit-en.js",
    "edit-fr.js",
    "edit-it.js",
    "edit-pt_BR.js",
    "equalbars-1.js",
    "err-de.js",
    "err-en.js",
    "err-fr.js",
    "err-it.js",
    "err-pt_BR.js",
    "follow-1.js",
    "grid-1.js",
    "grid2-1.js",
    "json-1.js",
    "page-1.js",
    "perc-1.js",
    "play-1.js",
    "psvg-1.js",
    "setmidi-1.js",
    "sth-1.js",
    "soloffs-1.js",
    "temper-1.js",
    "toabc.js",
    "toabw.js",
    "toaudio-1.js",
    "toabw.js",
    "toodt.js",
    "toxhtml.js"
  ],
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "bin": {
    "abc2odt": "./abc2odt",
    "abc2svg": "./abc2svg"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/moinejf/abc2svg.git"
    "type": "fossil",
    "url": "https://chiselapp.com/user/moinejf/repository/abc2svg"
  },
  "keywords": [
    "ABC",
    "music",
    "SVG"
  ],
  "author": "Jean-François Moine",
  "license": "LGPL-3.0",
  "bugs": {
    "url": "https://github.com/moinejf/abc2svg/issues"
    "url": "https://chiselapp.com/user/moinejf/repository/abc2svg/reportlist"
  },
  "homepage": "https://github.com/moinejf/abc2svg#readme"
  "homepage": "https://chiselapp.com/user/moinejf/repository/abc2svg"
}
Changes to toabc.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
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


-
+

















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













-
+
-
-







// abc2svg - toabc.js - convert ABC to ABC
//
// Copyright (C) 2016-2018 Jean-Francois Moine
// Copyright (C) 2016-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.
//
// 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/>.

// constants from core/abc2svg.js
    var	BAR = 0,
	CLEF = 1,
	CUSTOS = 2,
//	FORMAT = 3,
	GRACE = 4,
	KEY = 5,
	METER = 6,
	MREST = 7,
	NOTE = 8,
	PART = 9,
	REST = 10,
	SPACE = 11,
	STAVES = 12,
	STBRK = 13,
	TEMPO = 14,
//	TUPLET = 15,
	BLOCK = 16,
	REMARK = 17,

    var	C = abc2svg.C,
	SL_ABOVE = 0x01,
	SL_BELOW = 0x02,
	SL_AUTO = 0x03,
	SL_HIDDEN = 0x04,
	SL_DOTTED = 0x08,

	OPEN_BRACE = 0x01,
	CLOSE_BRACE = 0x02,
	OPEN_BRACKET = 0x04,
	CLOSE_BRACKET = 0x08,
	OPEN_PARENTH = 0x10,
	CLOSE_PARENTH = 0x20,
	STOP_BAR = 0x40,
	FL_VOICE = 0x80,
	OPEN_BRACE2 = 0x0100,
	CLOSE_BRACE2 = 0x0200,
	OPEN_BRACKET2 = 0x0400,
	CLOSE_BRACKET2 = 0x0800,
	MASTER_VOICE = 0x1000,
	MASTER_VOICE = 0x1000

	BASE_LEN = 1536

    var	deco_l = {			// decorations
		dot: '.',
		fermata: 'H',
		emphasis: 'L',
		lowermordent: 'M',
		coda: 'O',
︙
153
154
155
156
157
158
159
160
161
162



163
164
165
166
167
168
169
128
129
130
131
132
133
134



135
136
137
138
139
140
141
142
143
144







-
-
-
+
+
+







		case "pagescale":
		case "pagewidth":
		case "scale":
		case "staffwidth":
			ln += s.param
			break
		case "sep":
			ln += s.sk1.toFixed(2) + ' ' +
				s.l.toFixed(2) + ' ' +
				s.sk2.toFixed(2)
			ln += s.sk1.toFixed(1) + ' ' +
				s.l.toFixed(1) + ' ' +
				s.sk2.toFixed(1)
			break
		case "skip":
			ln += s.sk
			break
		case "text":
			if (s.text.indexOf('\n') <= 0
			 && (!s.opt || s.opt == 'c')) {
︙
221
222
223
224
225
226
227
228

229
230
231
232
233
234
235
196
197
198
199
200
201
202

203
204
205
206
207
208
209
210







-
+







			else
				line += '!' + n + '!'
		}
	} // deco_dump

	function dur_dump(dur, grace) {
	    var	d = 0,
		l = grace ? BASE_LEN / 4 : ulen
		l = grace ? C.BLEN / 4 : ulen
		if (dur == l)
			return
		while (1) {
			if (dur % l == 0) {
				dur /= l
				if (dur != 1)
					line += dur.toString()
︙
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
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







-
+


















-
+







					while (nly < ly.length)
						w[nly++] = ""
			}
			if (nly == 0)
				continue
			for (s = voice_tb[v].sym; s; s = s.next) {
				switch (s.type) {
				case BAR:
				case C.BAR:
					if (w.length == 0)
						continue
					if (++nb < 4)
						continue
					nb = 0
					if (!s.next)
						continue
					for (i = 0; i < nly; i++)
						w[i] += '\n'
//					t =  "|"
//					if (++nb >= 4) {
//						nb = 0;
//						t = "|\n"
//					}
//					for (i = 0; i < nly; i++)
//						w[i] += t
				default:
					continue
				case NOTE:
				case C.NOTE:
					break
				}
				ly = s.a_ly
				if (!ly) {
					for (i = 0; i < nly; i++)
						w[i] += "*"
					continue
︙
437
438
439
440
441
442
443
444

445
446
447
448

449
450
451
452
453
454
455
412
413
414
415
416
417
418

419
420
421
422

423
424
425
426
427
428
429
430







-
+



-
+







		case 2: line += '^^'; break
		case 3: line += '='; break
		}
		if (note.micro_n) {
			if (s.p_v.uscale)
				line += note.micro_n
			else
				line += dur_dump(BASE_LEN / 4 *
				line += dur_dump(C.BLEN / 4 *
							note.micro_n / note.micro_d,
						true)
		}
		p = note.apit
		p = note.pit
		if (p >= 23) {
			line += "abcdefg"[p % 7]
			if (p >= 30) {
				line += "'"
				if (p >= 37)
					line += "'"
			}
︙
468
469
470
471
472
473
474
475

476
477
478
479

480
481
482

483
484
485
486
487
488
489
443
444
445
446
447
448
449

450
451
452
453

454
455
456

457
458
459
460
461
462
463
464







-
+



-
+


-
+







		if (!tie_ch && note.ti1)
			slti_dump(note.ti1, '-')
		if (note.sl2)
			line += ')'
	} // note_dump()

	function slti_dump(fl, ty) {
		if (fl & SL_DOTTED)
		if (fl & C.SL_DOTTED)
			line += ".";
		line += ty
		switch (fl & 0x07) {
		case SL_ABOVE:
		case C.SL_ABOVE:
			line += "'"
			break
		case SL_BELOW:
		case C.SL_BELOW:
			line += ','
			break
		}
	} // slti_dump()

//fixme: missing: '+' (master voice) and '*' (floating voice)
	function staves_dump(s) {
︙
549
550
551
552
553
554
555
556

557
558
559
560
561
562
563
524
525
526
527
528
529
530

531
532
533
534
535
536
537
538







-
+







		if (staff.flags & CLOSE_BRACKET2)
			ln += ']'
		if (staff.flags & CLOSE_BRACKET)
			ln += ']';

		// output the following bars
		for (s = s.ts_next; s; s = s.ts_next) {
			if (s.type != BAR)
			if (s.type != C.BAR)
				break
			if (s.time != vti[s.v])
				continue
			sym_dump(s);
			s.del = true
			if (line) {
				vo[s.v].push(line);
︙
572
573
574
575
576
577
578
579

580
581
582
583
584
585
586
547
548
549
550
551
552
553

554
555
556
557
558
559
560
561







-
+








	function tempo_dump(s) {
	    var	i,
		ln = 'Q:'

		function qdur_dump(dur) {
		    var	d = 0,
			l = BASE_LEN
			l = C.BLEN
			if (dur == l)
				ln += "1/1"
			while (1) {
				if (dur % l == 0) {
					dur /= l;
					ln += dur.toString()
					break
︙
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
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







-
+






-
+












-
+


-
+

-
+









-
+


-
+


-
+




-
+









-
+







			slti_dump(tmp, '(');
			tmp >>= 4
		}
		if (s.a_gch)
			gch_dump(s.a_gch)
		if (s.a_dd)
			deco_dump(s.a_dd)
		if (s.invis && s.type != REST && s.type != SPACE)
		if (s.invis && s.type != C.REST && s.type != C.SPACE)
			line += "!invisible!"
		if (s.color)
			line += "!" + s.color + "!"
		if (s.feathered_beam)
			line += s.feathered_beam > 0 ? "!beam-accel!" : "!beam-rall!"
		switch (s.type) {
		case BAR:
		case C.BAR:
			if (s.beam_on)
				line += "!beamon!"
			if (s.bar_dotted)
				line += '.';
			line += s.bar_type
			if (s.text) {
				if (s.text[0] >= '0' && s.text[0] <= '9')
					line += s.text + ' '
				else
					line += '"' + s.text + '"'
			}
			break
		case CLEF:
		case C.CLEF:
			info_out("K: " + clef_dump(s))
			break
		case CUSTOS:
		case C.CUSTOS:
			break
		case GRACE:
		case C.GRACE:
			line += '{'
			if (s.sappo)
				line += '/'
			for (g = s.extra; g; g = g.next)
				sym_dump(g)
			if (s.gr_shift)
				line += ' ';
			line += '}'
			break
		case KEY:
		case C.KEY:
			info_out(key_dump(s))
			break
		case METER:
		case C.METER:
			info_out(meter_dump(s))
			break
		case MREST:
		case C.MREST:
			line += s.invis ? 'X' : 'Z'
			if (s.nmes != 1)
				line += s.nmes
			break
		case NOTE:
		case C.NOTE:
			if (s.beam_br1)
				line += "!beambr1!"
			if (s.beam_br2)
				line += "!beambr2!"
			if (s.trem1)
				line += '!' + "///".slice(0, s.ntrem) + '!'
			if (s.xstem)
				line += "!xstem!"
			if (s.stemless
			 && s.notes[0].dur < BASE_LEN)	// head duration
			 && s.notes[0].dur < C.BLEN)	// head duration
				line += "!stemless!"
			if (s.trem22)
				line += "!trem" + s.ntrem + "!"
			else if (s.trem2 && s.next && s.next.trem2)
				s.next.trem22 = true
			tie_ch = true
			if (s.notes.length == 1) {
︙
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
860
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







-
+


-
+



-
+




-
+




-
+




-
+


-
+



-
+














-
-
+
+










-
+
















-
+







				slti_dump(s.notes[0].ti1, '-');
			tmp = s.slur_end
			while (tmp) {
				line += ')';
				tmp--
			}
			break
		case PART:
		case C.PART:
			info_out('P:' + s.text)
			break
		case REST:
		case C.REST:
			line += s.invis ? 'x' : 'z';
			dur_dump(s.dur)
			break
		case SPACE:
		case C.SPACE:
			line += 'y'
			if (s.width != 10)
				line += s.width
			break
		case STAVES:
		case C.STAVES:
			if (nv == 1)
				break
			staves_dump(s)
			break
		case STBRK:
		case C.STBRK:
			voice_out();
			abc2svg.print('%%staffbreak ' + s.xmx.toString() +
				(s.stbrk_forced ? 'f' : ''))
			break
		case TEMPO:
		case C.TEMPO:
			tempo_dump(s)
			break
		case BLOCK:
		case C.BLOCK:
			voice_out();
			block_dump(s)
			break
		case REMARK:
		case C.REMARK:
			info_out('r:' + s.text)
			break
		default:
			voice_out();
			abc2svg.print('% ??sym: ' + music_types[s.type])
			break
		}
	} // sym_dump()

	abc2svg.print('\nX:' + info['X'])
	header_dump("TC")

	abc2svg.print(meter_dump(voice_tb[0].meter));

	ulen = voice_tb[0].ulen < 0 ? BASE_LEN / 4 : voice_tb[0].ulen;
	abc2svg.print('L:1/' + (BASE_LEN / ulen).toString());
	ulen = voice_tb[0].ulen < 0 ? C.BLEN / 4 : voice_tb[0].ulen;
	abc2svg.print('L:1/' + (C.BLEN / ulen).toString());

	header_dump("OABDFGRNPSZH")

	for (v = 0; v < nv; v++) {
		vo[v] = [];
		vti[v] = 0
	}

	if (info.Q) {
		for (s = tsfirst; s; s = s.ts_next) {
			if (s.type == TEMPO) {
			if (s.type == C.TEMPO) {
				tempo_dump(s);
				s.del = true
				break
			}
		}
	}
	abc2svg.print(key_dump(voice_tb[0].key, voice_tb[0].clef))

	// loop by time
	for (s = tsfirst; s; s = s.ts_next) {
		if (eoln && s.seqst)
			voice_out();
		if (s.del)
			continue
		line = "";
		// (all voices are synchronized on %%score)
		if (s.type != STAVES && s.time > vti[s.v]) {
		if (s.type != C.STAVES && s.time > vti[s.v]) {
//fixme: put 'X' if more than one measure
			line += 'x';
			dur_dump(s.time - vti[s.v]);
			vti[s.v] = s.time
		}
		sym_dump(s)
		if (s.dur)
︙
Changes to toabw.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - toabw.js - SVG generation for Abiword
//
// Copyright (C) 2018 Jean-Francois Moine
// Copyright (C) 2018-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.
︙
44
45
46
47
48
49
50
51
52


53
54
55
56
57
58
59
44
45
46
47
48
49
50


51
52
53
54
55
56
57
58
59







-
-
+
+







	seq = 1

// set a value in page unit
function set_unit(p) {
	if (typeof p == "string")
		return p
	if (page_type[0] == 'L')
		return (p / 96).toFixed(2) + 'in'
	return (p / 37.8).toFixed(2) + 'cm'
		return (p / 96).toFixed(1) + 'in'
	return (p / 37.8).toFixed(1) + 'cm'
}

function header_footer(str) {
    var	c, i, t,
	j = 0,
	r = ["", "", ""]

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







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







-
-
-
+
+
+
+




+
+
+







	if (typeof abc2svg.printErr == 'function')
		abc2svg.printErr(e.message + "\n*** Abort ***\n" + e.stack)
	else
		section += "<p>" + e.message + "\n*** Abort ***\n" + e.stack + "</p>\n";
	abc2svg.abc_end();
	abc2svg.quit()
}

function font_bug(str) {
    var i, k, l, r, w,
	j = 0

	while (1) {
		i = str.indexOf('font:', j)
		if (i < 0)
			return str
		if (str[i - 1] == '"') {
			j = str.indexOf('"', i)
		} else {
			j = str.indexOf('}', i);
			k = str.indexOf(';', i)
			if (j < 0 || (k >= 0 && k < j))
				j = k
		}
		w = str.slice(i + 5, j).match(/[^ \t"]+|".+?"/g) // "

		l = w.length;
		r = 'font-family:' + w[--l] +
			';font-size:' + w[--l]
		while (--l >= 0) {
			switch (w[l]) {
			case 'italic':
				r += ';font-style:italic'
				break
			case 'oblique':
				r += ';font-style:oblique'
				break
			case 'bold':
				r += ';font-weight:bold'
				break
			}
		}
		str = str.replace(str.slice(i, j), r)
	}
}

function svg_out(str) {
    var	r, w, h,
	cfmt = abc.cfmt()

	switch (str.slice(0, 4)) {
	case '<svg':
		r = str.slice(0, 200).match(/.*width="(.*?)px" height="(.*?)px"/);
		w = r[1] / 96;
		h = r[2] / 96;
//fixme: the shorthand 'font:' does not work in the library 'librsvg'
// used by libreoffice and abiword
// (https://gitlab.gnome.org/GNOME/librsvg/issues/34)
		str = font_bug(str)
		data += '<d name="g'+ (++seq).toString() +
			'" mime-type="image/svg+xml" base64="no">\n\
<![CDATA[' + str + ']]>\n\
</d>\n';
		r = str.slice(0, 200).match(/.*width="(.*?)px" height="(.*?)px"/);
		w = r[1] / 96;
		h = r[2] / 96;
		section += '<p style="Normal" xid="'+
			(seq + 1).toString() + '"><image dataid="g' +
			seq.toString() + '" xid="' +seq.toString() +
			'" props="height:' + h.toFixed(2) + 'in; width:' +
				w.toFixed(2) + 'in"/></p>\n';
		seq++

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







-
+



















+
+
+
-
-
+
+
+







				return '<c'
			case '</span>':
				return '</c>'
			case '<br/>':			// hope followed by '\n'!
				return ''
			default:			// size:..px
				var r = c.match(/size:(.+)px/)
				return 'size:' + (r[1] * 72 / 96).toFixed(2) + 'pt'
				return 'size:' + (r[1] * 72 / 96).toFixed(1) + 'pt'
			}
		})
		section += '\n'
		break
	}
}

// entry point from cmdline
abc2svg.abc_init = function() {

	// get the page parameters
	user.img_out = function(str) {
	    var cfmt = abc.cfmt(),
		pw = cfmt.pagewidth;

		page_type = pw > 800 ? 'Letter' : 'A4';
		page_size = pw > 800 ?
				'width="8.50" height="11.00" units="in"' :
				'width="210.00" height="297.00" units="mm"';
		if (abc.page) {
			topmargin = botmargin = 0
		} else {
		topmargin = set_unit(cfmt.topmargin || 37.8);
		botmargin = set_unit(cfmt.botmargin || 37.8);
			topmargin = set_unit(cfmt.topmargin || 37.8);
			botmargin = set_unit(cfmt.botmargin || 37.8)
		}

		// output the first generated string
		svg_out(str);

		// change the output function
		user.img_out = svg_out
	}
︙
Changes to tolead.js.
︙
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
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







-
-

+
-
-
+
+



-
+

-
+






-
+

















-
-
-
+
+
+










-
+













-
+







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

function lead(tsfirst, voice_tb, music_types, info) {
    var	C = abc2svg.C
	var	s, beat, cur_beat, i,
		line = '';
	s, beat, cur_beat, i,
	line = '';

	function get_beat(s) {
		if (s.a_meter[0].top[0] == 'C' || !s.a_meter[0].bot) {
			beat = BASE_LEN / 4
			beat = C.BLEN / 4
		} else {
			beat = BASE_LEN / s.a_meter[0].bot[0] |0
			beat = C.BLEN / s.a_meter[0].bot[0] |0
			if (isNaN(beat)) {
				abc2svg.print('** Cannot get the beat')
				return
			}
			if (s.a_meter[0].bot[0] == 8
			 && s.a_meter[0].top[0] % 3 == 0)
				beat = BASE_LEN / 8 * 3
				beat = C.BLEN / 8 * 3
		}
	} // get_beat()

	abc2svg.print('-- ' + info.T + ' --');

	// get the beat
	get_beat(voice_tb[0].meter)
	if (beat == undefined)
		return

	// treat only the first voice
	cur_beat = 0
	for (s = voice_tb[0].sym; s; s = s.next) {
		while (s.time > cur_beat) {
			line += '/ ';
			cur_beat += beat
		}
		switch (music_types[s.type]) {
		case 'note':
		case 'rest':
		switch (s.type) {
		case C.NOTE:
		case C.REST:
			if (s.a_gch) {		// search a chord symbol
				for (i = 0; i < s.a_gch.length; i++) {
					if (s.a_gch[i].type == 'g') {
						line += s.a_gch[i].text + ' ';
						cur_beat = s.time + beat
						break
					}
				}
			}
			break
		case 'bar':
		case C.BAR:
			if (s.eoln) {
				if (s.bar_type == '::')
					line += ':|\n|: '
				else
					line += s.bar_type +'\n'
			} else {
				if (s.bar_type == '::')
					line += ':|: '
				else
					line += s.bar_type + ' '
			}
			cur_beat = s.time	// re-synchronize
			break
		case 'meter':
		case C.METER:
			get_beat(s)
			break
		}
	}
	abc2svg.print(line)
}

︙
Changes to toodt.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// abc2svg - toodt.js - ABC translation to ODT+SVG
//
// Copyright (C) 2017-2018 Jean-Francois Moine
// 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.
︙
27
28
29
30
31
32
33
34

35
36
37
38
39
40
41
27
28
29
30
31
32
33

34
35
36
37
38
39
40
41







-
+







//
//  (this script must appear immediately after the command)
//
// 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_mid, page_right,
    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
︙
60
61
62
63
64
65
66
67
68


69
70
71
72
73
74
75
76

77
78
79
80
81
82
83
60
61
62
63
64
65
66


67
68
69
70
71
72
73
74
75

76
77
78
79
80
81
82
83







-
-
+
+







-
+







}

// convert a pixel value into page unit
function set_unit(p) {
	if (typeof p == "string")
		return p
	if (page_type[0] == 'L')
		return (p / 96).toFixed(2) + 'in'
	return (p / 37.8).toFixed(2) + 'cm'
		return (p / 96).toFixed(1) + 'in'
	return (p / 37.8).toFixed(1) + 'cm'
}

// output a header or a footer
function gen_hf(type, stype, str) {
    var	c, i, res_left,
	j = 0,
	res = '<style:' + type + '>\n\
<text:p text:style-name="' + stype + '\">'
<text:p text:style-name="' + stype + '\"><text:tab/>'

	if (str[0] == '"')
		str = str.slice(1, -1)
	if (str.indexOf('\t') < 0)		// if no TAB
		str = '\t' + str		// center

	for (i = 0; i < str.length; i++) {
︙
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
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







-
+














+










+













-
+







 xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"\
 xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"\
 xmlns:ooo="http://openoffice.org/2004/office"\
 xmlns:ooow="http://openoffice.org/2004/writer"\
 office:version="1.1">\n\
 <office:styles>\n\
  <style:default-style style:family="paragraph">\n\
   <style:paragraph-properties fo:orphans="2" fo:widows="2"/>\n\
   <style:paragraph-properties fo:orphans="5" fo:widows="5"/>\n\
   <style:text-properties style:use-window-font-color="true"\
 style:font-name="Liberation Serif" fo:font-size="12pt"/>\n\
  </style:default-style>\n\
 <style:style style:name="Standard" style:family="paragraph" style:class="text"/>\n\
 <style:style style:name="P" style:family="paragraph"\
 style:parent-style-name="Standard"/>\n\
 <style:style style:name="Pbr" style:family="paragraph"\
 style:parent-style-name="Standard">\n\
  <style:paragraph-properties fo:break-before="page"/>\n\
 </style:style>\n\
<style:style style:name="Header" style:family="paragraph"\
 style:parent-style-name="Standard" style:class="extra">\n\
 <style:paragraph-properties>\n\
  <style:tab-stops>\n\
   <style:tab-stop style:position="' + page_left + '" style:type="left"/>\n\
   <style:tab-stop style:position="' + page_mid + '" style:type="center"/>\n\
   <style:tab-stop style:position="' + page_right + '" style:type="right"/>\n\
  </style:tab-stops>\n\
 </style:paragraph-properties>\n\
 <style:text-properties ' + headerfont + '/>\n\
</style:style>\n\
<style:style style:name="Footer" style:family="paragraph"\
 style:parent-style-name="Standard" style:class="extra">\n\
 <style:paragraph-properties>\n\
  <style:tab-stops>\n\
   <style:tab-stop style:position="' + page_left + '" style:type="left"/>\n\
   <style:tab-stop style:position="' + page_mid + '" style:type="center"/>\n\
   <style:tab-stop style:position="' + page_right + '" style:type="right"/>\n\
  </style:tab-stops>\n\
 </style:paragraph-properties>\n\
 <style:text-properties ' + footerfont + '/>\n\
</style:style>\n\
 </office:styles>\n\
 <office:automatic-styles>\n\
 <style:style style:family="graphic" style:name="graphic1" style:display-name="graphic1" style:parent-style-name="Graphics">\n\
  <style:graphic-properties style:wrap="run-through" style:run-through="foreground" style:vertical-pos="top" style:vertical-rel="baseline"/>\n\
 </style:style>\n\
 <style:page-layout style:name="Standard">\n\
  <style:page-layout-properties ' + margins + '\
 fo:margin-left="1.5cm" fo:margin-right="1.5cm"/>\n\
 fo:margin-left="0" fo:margin-right="0"/>\n\
 </style:page-layout>\n\
 </office:automatic-styles>\n\
 <office:master-styles>\n\
  <style:master-page style:name="Standard" style:page-layout-name="Standard">\n' +
	(header || '') +
	(footer || '') + '\
  </style:master-page>\n\
︙
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
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







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




















+
+
+
+
+







			"\n*** Abort ***\n" + e.stack + "</text:p>\n";
	odt_out();
	abc2svg.quit()
}

// convert a CSS font definition (in pixels) to ODT (in points)
function def_font(font) {
    var	ws = '',
	css_font = abc.style_font(abc.cfmt()[font]),
	r = css_font.match(/font-family:(.+?); (.*)font-size:(.+)px/)

// r[2] may be empty or
// font-weight:bold, font-style:italic or font-style:oblique
	if (r[2])
		ws = r[2].replace(/(font-.+?):(.+?);/g,
			'fo:$1="$2"')
	return 'style:font-name="' + r[1] + '" ' + ws +
		'fo:font-size="' + (r[3] * 72 / 96).toFixed(1) + 'pt"'
    var	css_font = abc.style_font(abc.cfmt()[font])
			.slice(5)		// remove 'font:'
			.split(' '),
	l = css_font.length,
	fo = 'fo:font-family="' + css_font[--l] + '"',
	i = css_font[--l].slice(0, -2)

	fo += ' fo:font-size="' +
		(i * 72 / 96).toFixed(1) + 'pt"'
	while (--l >= 0) {
		i = css_font[l]
		switch (i) {
		case 'italic':
		case 'oblique':
			fo += ' fo:font-style="' + i + '"'
			break
		case 'bold':
			fo += ' fo:font-weight="' + i + '"'
			break
		}
	}
	return fo
}

function font_bug(str) {
    var i, k, l, r, w,
	j = 0

	while (1) {
		i = str.indexOf('font:', j)
		if (i < 0)
			return str
		if (str[i - 1] == '"') {
			j = str.indexOf('"', i)
		} else {
			j = str.indexOf('}', i);
			k = str.indexOf(';', i)
			if (j < 0 || (k >= 0 && k < j))
				j = k
		}
		w = str.slice(i + 5, j).match(/[^ \t"]+|".+?"/g) // "

		l = w.length;
		r = 'font-family:' + w[--l] +
			';font-size:' + w[--l]
		while (--l >= 0) {
			switch (w[l]) {
			case 'italic':
				r += ';font-style:italic'
				break
			case 'oblique':
				r += ';font-style:oblique'
				break
			case 'bold':
				r += ';font-weight:bold'
				break
			}
		}
		str = str.replace(str.slice(i, j), r)
	}
}

function svg_out(str) {
    var	img, r, w, h,
	cfmt = abc.cfmt()

	switch (str.slice(0, 4)) {
	case '<svg':

		// get the first header/footer
		if (header == undefined) {
			r = cfmt.header;
			header = r ? gen_hf("header", "Header", r) : '';
			headerfont = def_font("headerfont")
		}
		if (footer == undefined) {
			r = cfmt.footer;
			footer = r ? gen_hf("footer", "Footer", r) : '';
			footerfont = def_font("footerfont")
		}

//fixme: the shorthand 'font:' does not work in the library 'librsvg'
// used by libreoffice and abiword
// (https://gitlab.gnome.org/GNOME/librsvg/issues/34)
		str = font_bug(str)

		// save the image
		img = 'Pictures/abc' + (++seq).toString() + '.svg';
		zip.file(img, str, { compression: "DEFLATE" });

		// it is part of the document
		imgs +='\
︙
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
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
557
558
559







-











+
-
-
+
+



+
-
-
+
+


+
+
-
-
+
+
+







	zip.file('mimetype',
		'application/vnd.oasis.opendocument.text',
		{ compression: "STORE" });

	// define some functions in the Abc object
	abc.tosvg("toodt", "\
%%fullsvg 1\n\
%%printmargin 1.5cm\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"';
			page_left = set_unit(cfmt.leftmargin);
			page_mid = '3.66in';	// with margin = 1.5cm = 0.59in
			page_right = '7.32in'
			page_mid = '4.25in';
			page_right = set_unit(816 - cfmt.rightmargin)
		} else {
			page_type = 'A4';
			page_size = 'fo:page-width="21cm" fo:page-height="29.7cm"';
			page_left = set_unit(cfmt.leftmargin);
			page_mid = '9cm';	// with margin 1.5cm
			page_right = '18cm'
			page_mid = '10.5cm';
			page_right = set_unit(793.8 - cfmt.rightmargin)
		}

		// if abc2svg page formatting
		if (abc.page)
		// top and bottom margins default = 1cm
		margins = 'fo:margin-top="' +
			margins = 'fo:margin-top="0" fo:margin-bottom="0"'
		else
		    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);

︙
Changes to toxhtml.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
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


-
+
















-
-
+







+

-
-







// abc2svg - toxhtml.js - SVG generation
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-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.
//
// 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	o_font, c_font, wto,
	init_done, pw, ml, mr, pkf, lkf
    var	init_done, pw, ml, mr, pkf, lkf

// 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;"
		}
		if (c == '&')
			return "&amp;"
		return c
	})
}

abc2svg.abort = function(e) {
	if (!init_done)				// if empty document
		user.img_out('')
︙
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
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







-
+





-
+

















-
+

-

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







	cfmt = abc.cfmt(),
	psty = '';

	nml = cfmt.leftmargin;
	if (nml != ml) {
		if (ml == undefined)
			ml = nml;
		psty += 'margin-left:' + nml.toFixed(2) + 'px;'
		psty += 'margin-left:' + nml.toFixed(1) + 'px;'
	}
	nmr = cfmt.rightmargin;
	if (nmr != mr) {
		if (mr == undefined)
			mr = nmr;
		psty += 'margin-right:' + nmr.toFixed(2) + 'px;'
		psty += 'margin-right:' + nmr.toFixed(1) + 'px;'
	}
	nlkf = cfmt.lineskipfac;
	if (nlkf != lkf) {
		if (lkf == undefined)
			lkf = nlkf;
		psty += 'line-height:' + ((nlkf * 100) | 0).toString() + '%;'
	}
	npkf = cfmt.parskipfac;
	if (npkf != pkf) {
		if (pkf == undefined)
			pkf = npkf;
		psty += 'margin-bottom:' + npkf.toFixed(2) + 'em;'
	}
	npw = cfmt.pagewidth
	if (npw != pw || nml != ml || nmr != mr) {
		if (pw == undefined)
			pw = npw;
		psty += 'width:' + (npw - nml - nmr).toFixed(2) + 'px;'
		psty += 'width:' + (npw - nml - nmr).toFixed(1) + 'px;'
	}

	return psty
}

function para_start(action, skip) {
    var	r,
	cfmt = abc.cfmt(),
	sc = cfmt.scale,
	newpage = abc.get_newpage() ? 'newpage ' : '',
	sty = '<p class="' + newpage,
	psty = set_pstyle()

	if (o_font.class)
		sty += o_font.class
	else
		sty += 'f' + o_font.fid

	if (skip)
		psty += 'margin-top:' + skip.toFixed(2) + 'px;'

	switch (action) {
	case 'c':
		psty += 'text-align:center;'
		break
	case 'r':
		psty += 'text-align:right;'
		break
	case 'j':
		psty += 'text-align:justify;'
		break
	}
	if (psty)
		sty += '" style="' + psty
	return sty + '">'
} // para_start()

function para_build(str) {
    var	n_font, txt,
	 span = ''

	if (c_font != o_font) {
		span += '<span class="'
		if (c_font.class)
			span += c_font.class
		else
			span += 'f' + c_font.fid
		span += '">'
	}
	txt = str.replace(/<|>|&.*?;|&|  |\$./g, function(c){
		switch (c[0]) {
		case '<': return "&lt;"
		case '>': return "&gt;"
		case '&':
			if (c == '&')
				 return "&amp;"
			return c
		case ' ':
			return '  '		// space + nbspace
		case '$':
			if (c[1] == '0')
				n_font = o_font
			else if (c[1] >= '1' && c[1] <= '9')
				n_font = abc.get_font("u" + c[1])
			else
				return c
			c = ''
			if (n_font == c_font)
				return c
			if (c_font != o_font)
				c = "</span>";
			c_font = n_font
			if (c_font == o_font)
				return c
			if (c_font.class)
				return c + '<span class="' + c_font.class + '">'
			return c + '<span class="f' + c_font.fid + '">'
		}
	})
	if (c_font != o_font)
		txt += '</span>'
	return span + txt
} // para_build()

// output a text (called from write_text)
function write_xhtml(text, action) {
    var i, j, text2, skip

	abc.svg_flush();
	skip = abc.get_posy()		// handle %%vskip

	// output the XHTML header if not done yet
	if (!init_done)
		user.img_out('');

	o_font = c_font = abc.get_font("text")
	while (1) {
		i = text.indexOf('\n\n')
		if (i > 0) {
			text2 = text.slice(i + 2);
			text = text.slice(0, i)
		}
		text = para_build(text)
		switch (action) {
		default:		// left
//		case 'c':		// center
//		case 'r':		// right
			user.img_out(para_start(action, skip) +
				text.replace(/\n/g, '<br/>\n') + '</p>')
			break
		case 'f':		// fill
		case 'j':		// justify
			user.img_out(para_start(action, skip) + text + '</p>')
			break
		}
		if (i <= 0)
			break
		text = text2;
		skip = 0
	}
} // write_xhtml()

// replacement of Abc write_text()
function write_text(text, action) {
	if (action == 's')		// skip
		return
	if (!abc.get_multi())
		write_xhtml(text, action)
	else
		wto(text, action)
}

// entry point from cmdline
abc2svg.abc_init = function() {
    var cfmt = abc.cfmt()

	// output a header or footer
︙
338
339
340
341
342
343
344




345
346
347
348
349
350
351
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225







+
+
+
+







		counter-increment: page;\n\
		content: counter(page);\n\
	}\n\
	div.left {text-align: left}\n\
	div.center {text-align: center}\n\
	div.right {text-align: right}\n\
}';

		// no margin / header / footer when SVG page formatting
		if (abc.page)
			topmargin = botmargin = header = footer = 0;

		abc2svg.print('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"\n\
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1.dtd">\n\
<html xmlns="http://www.w3.org/1999/xhtml">\n\
<head>\n\
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>\n\
<meta name="generator" content="abc2svg-' + abc2svg.version + '"/>\n\
︙
367
368
369
370
371
372
373
374

375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
241
242
243
244
245
246
247

248
249


250
251
252
253
254
255
256
257
258
259
260
261
262







-
+

-
-













			gen_hf("footer", footer);

		// output the first generated string
		abc2svg.print(str);
		init_done = true;

		// change the output function
		user.img_out = function(str) { abc2svg.print(str) }
		user.img_out = abc2svg.print
	}

	wto = abc.set_xhtml(write_text)		// switch write_text()
}

abc2svg.abc_end = function() {
    var	font_style = abc.get_font_style()

	if (!init_done)				// if empty document
		user.img_out('')
	if (user.errtxt)
		abc2svg.print("<pre>" + clean_txt(user.errtxt) + "</pre>")
	if (font_style)				// if some %%text at the end
		abc2svg.print('<style type="text/css">' + font_style + '\n</style>');
	abc2svg.print("</body>\n</html>")
}
Changes to util/abcdoc.js.
1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







//#javascript
// abcdoc-1.js file to include in html pages with abc2svg-1.js
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-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.
︙
87
88
89
90
91
92
93



94
95
96
97
98
99
100
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103







+
+
+







			alert('error loading ' + fn)
		}
		document.head.appendChild(s)
	}

	var page = document.body.innerHTML

	// accept page formatting
	abc2svg.abc_end = function() {}

	// load the required modules
	if (!abc2svg.modules.load(page, dom_loaded))
		return

	// search the ABC tunes and add their rendering as SVG images
	var	i = 0, j, k, res,
		re = /\n%abc|\nX:/g,		// start on "%abc" or "X:"
︙
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
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







-
+














-
+












-
+


-
+



+






-
+










		if (!res)
			break
		j = re.lastIndex - res[0].length;
		new_page += page.slice(i, j);

		// get the end of the ABC sequence
		// including the %%beginxxx/%%endxxx sequences
		re_stop.lastIndex = j
		re_stop.lastIndex = ++j
		while (1) {
			res = re_stop.exec(page)
			if (!res || res[0] == "\n<")
				break
			k = page.indexOf(res[0].replace("begin", "end"),
					re_stop.lastIndex)
			if (k < 0)
				break
			re_stop.lastIndex = k
		}
		if (!res || k < 0)
			k = page.length
		else
			k = re_stop.lastIndex - 2;
		tune = page.slice(j + 1, k);
		tune = page.slice(j, k);
		new_page += '<pre style="display:inline-block; vertical-align: top">' +
				clean_txt(tune) +
				'</pre>\n\
<div style="display:inline-block; vertical-align: top">\n'
// not "float:right"
		try {
			abc.tosvg('abcdoc', tune)
		} catch (e) {
			alert("abc2svg javascript error: " + e.message +
				"\nStack:\n" + e.stack)
		}
		if (errtxt) {
			i = page.indexOf("\n", j + 1);
			i = page.indexOf("\n", j);
			i = page.indexOf("\n", i + 1);
			alert("Errors in\n" +
				page.slice(j + 1, i) +
				page.slice(j, i) +
				"\n...\n\n" + errtxt);
			errtxt = ""
		}
		abc2svg.abc_end();	// close the page if %%pageheight
		new_page += '</div><br/>\n';
		i = k
		if (k >= page.length)
			break
		re.lastIndex = i
	}
//console.log('result:\n' + new_page)

	try {
		document.body.innerHTML = new_page + page.slice(i)
	} catch (e) {
		alert("abc2svg bad generated SVG: " + e.message +
			"\nStack:\n" + e.stack)
	}
}

// wait for the page to be loaded
document.addEventListener("DOMContentLoaded", dom_loaded, false)
Changes to util/abcemb.js.
1
2
3
4

5
6
7
8
9
10
11
1
2
3

4
5
6
7
8
9
10
11



-
+







//#javascript
// abcemb-1.js file to include in html pages with abc2svg-1.js
//
// Copyright (C) 2014-2018 Jean-Francois Moine
// Copyright (C) 2014-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.
︙
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
84
85
86
87
88
89
90





91
92
93
94
95
96
97







-
-
-
-
-








	if (!abcplay) {
		if (typeof AbcPlay == "undefined") { // as play-1.js not loaded,
			playseq = function(){}	     // don't come here anymore
			return
		}
		abcplay = AbcPlay(playconf);
		outputs = abcplay.get_outputs()
		if (outputs.length == 0) {
			playseq = function(){}
			return			// playing is not possible
		}
	}
	if (playing) {
		abcplay.stop();
		return
	}
	playing = true
	if (!a_pe[seq]) {		// if no playing event
︙
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
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







+
+
+

-
-
+
+
+
+
+
+







-
+






-
+







			alert('error loading ' + fn)
		}
		document.head.appendChild(s)
	}

	page = document.body.innerHTML;

	// accept page formatting
	abc2svg.abc_end = function() {}

	// load the required modules
	if (!abc2svg.modules.load(page, dom_loaded))
		return
	if (abc2svg.modules.load(page, render))
		render()
}

function render() {
	page = document.body.innerHTML;

	// search the ABC tunes,
	// replace them by SVG images with play on click
	var	i = 0, j, k, res, src,
		seq = 0,
		re = /\n%abc|\nX:/g,
		re_stop = /\nX:|\n<|\n%.begin/g,
		select = window.location.hash.slice(1)
		select = window.location.hash.slice(1);

	abc = new abc2svg.Abc(user)

	// check if a selection
	if (select) {
		select = decodeURIComponent(select);
		select = page.indexOf(select)
		select = page.search(select)
		if (select < 0)
			select = 0
	}

	for (;;) {

		// get the start of a ABC sequence
︙
210
211
212
213
214
215
216

217
218
219
220
221
222
223
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226







+








		try {
			abc.tosvg('abcemb', page, j, k)
		} catch (e) {
			alert("abc2svg javascript error: " + e.message +
				"\nStack:\n" + e.stack)
		}
		abc2svg.abc_end()		// close the page if %%pageheight
		if (errtxt) {
			i = page.indexOf("\n", j);
			i = page.indexOf("\n", i + 1);
			alert("Errors in\n" +
				page.slice(j, i) +
				"\n...\n\n" + errtxt);
			errtxt = ""
︙
Added util/abcemb2.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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
//#javascript
// abcemb2-1.js file to include in html pages with abc2svg-1.js
//
// Copyright (C) 2018-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.
//
// 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/>.

window.onerror = function(msg, url, line) {
	if (typeof msg == 'string')
		alert("window error: " + msg +
			"\nURL: " + url +
			"\nLine: " + line)
	else if (typeof msg == 'object')
		alert("window error: " + msg.type + ' ' + msg.target.src)
	else
		alert("window error: " + msg)
	return false
}

var	errtxt = '',
	abc,				// (must be global for follow.js)
	elts,				// ABC HTML elements
	tunes = '',			// source of the ABC sequences
	indx = [],			// indexes of the tunes in tunes
	select,
	playing,
	abcplay,
	playconf = {
		onend: endplay
	},
	a_pe = [],			// index: #sequence, value: playing events
	glop,				// global sequence index for play
	old_gm,
	jsdir = document.currentScript ?
		document.currentScript.src.match(/.*\//) :
		(function() {
			var scrs = document.getElementsByTagName('script');
			return scrs[scrs.length - 1].src.match(/.*\//) || ''
		})()

// -- abc2svg init argument
var user = {
	errmsg: function(msg, l, c) {	// get the errors
		errtxt += clean_txt(msg) + '\n'
	},
	img_out: function(str) {	// image output
		new_page += str
	},
	page_format: true		// define the non-page-breakable blocks
}

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

function endplay() {
	playing = false
}

// function called on click on the music
function playseq(i) {
    var	outputs

	if (!abcplay) {
		if (typeof AbcPlay == "undefined") { // as play-1.js not loaded,
			playseq = function(){}	     // don't come here anymore
			return
		}
		abcplay = AbcPlay(playconf);
	}
	if (playing) {
		abcplay.stop()
		return
	}
	playing = true
	if (!a_pe[i]) {			// if no playing event
		abc = new abc2svg.Abc(user);

		abcplay.clear();
		abc.tosvg("play", "%%play")
		if (select)
			abc.tosvg('abcemb2', select)
		try {
			if (glop != undefined)
				abc.tosvg("abcemb2", tunes, indx[glop], indx[glop + 1]);
			abc.tosvg("abcemb2-" + i, tunes, indx[i], indx[i + 1])
		} catch(e) {
			alert(e.message + '\nabc2svg tosvg bug - stack:\n' + e.stack);
			playing = false;
			a_pe[seq] = null
			return
		}
		a_pe[i] = abcplay.clear()	// keep the playing events
	}
	abcplay.play(0, 100000, a_pe[i])
}

// function called when the page is loaded
function dom_loaded() {

	// loop until abc2svg is fully loaded
	if (typeof abc2svg != "object"
	 || !abc2svg.modules) {
		setTimeout(dom_loaded, 500)
		return
	}

	// convert HTML to ABC
	function toabc(s) {
		return s.replace(/&gt;/g, '>')
			.replace(/&lt;/g, '<')
			.replace(/&amp;/g, '&')
			.replace(/[ \t]+(%%)/g, '$1')
			.replace(/[ \t]+(.:)/g, '$1')
	}

// function to load javascript files
	abc2svg.loadjs = function(fn, relay, onerror) {
		var s = document.createElement('script');
		if (/:\/\//.test(fn))
			s.src = fn		// absolute URL
		else
			s.src = jsdir + fn;
		s.type = 'text/javascript'
		if (relay)
			s.onload = relay;
		s.onerror = onerror || function() {
			alert('error loading ' + fn)
		}
		document.head.appendChild(s)
	}

	// extract the ABC code
	elts = document.getElementsByClassName('abc')
	for (var i = 0; i < elts.length; i++) {
		var elt = elts[i];
		indx[i] = tunes.length;
		tunes += toabc(elt.innerHTML) + '\n'
	}
	indx[i] = tunes.length;
	ready()
}

function ready() {
    var	i, j

	// load the required modules
	if (!abc2svg.modules.load(tunes, ready))
		return

	// accept page formatting
	abc2svg.abc_end = function() {}

	var sel = window.location.hash.slice(1)
	if (sel)
		select = '%%select ' + decodeURIComponent(sel);

	abc = new abc2svg.Abc(user)

	// generate and replace
	for (var i = 0; i < elts.length; i++) {
		new_page = ""

		// set the playing callback
		j = tunes.indexOf('X:', indx[i])
		if (j >= 0 && j < indx[i + 1])
			new_page += '<div onclick="playseq(' + i + ')">\n'
		else if (glop == undefined)
			glop = i

		if (sel) {
			abc.tosvg('abcemb2', select);
			sel = ''
		}

		try {
			abc.tosvg('abcemb2', tunes, indx[i], indx[i + 1])
		} catch (e) {
			alert("abc2svg javascript error: " + e.message +
				"\nStack:\n" + e.stack)
		}
		if (errtxt) {
			new_page += '<p style="background:#ff8080">' +
					errtxt + "</p>\n";
			errtxt = ""
		}
		try {
			elts[i].innerHTML = new_page
		} catch (e) {
			alert("abc2svg bad generated SVG: " + e.message +
				"\nStack:\n" + e.stack)
		}

		if (j >= 0 && j < indx[i + 1])
			new_page += '</div>\n'
		abc2svg.abc_end()		// close the page if %%pageheight
	}

	// prepare for playing
	delete user.img_out;		// stop SVG generation
	old_gm = user.get_abcmodel;
	user.get_abcmodel = function(tsfirst, voice_tb, music_types, info) {
			if (old_gm)
				old_gm(tsfirst, voice_tb, music_types, info);
			abcplay.add(tsfirst, voice_tb)
		}
} // dom_loaded()

// wait for the page to be loaded
document.addEventListener("DOMContentLoaded", dom_loaded, false)
Changes to util/follow.js.
1
2

3
4
5

6
7
8
9
10
11
12
1

2
3
4

5
6
7
8
9
10
11
12

-
+


-
+







// follow-1.js - file to include in html pages after
//	abc2svg-1.js, abcemb-1.js and play-1.js.
//	abc2svg-1.js, abcemb[2]-1.js and play-1.js.
//	This script permits to follow the notes while playing.
//
// Copyright (C) 2015-2018 Jean-Francois Moine
// Copyright (C) 2015-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.
︙
Changes to util/midi.js.
︙
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
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







-
+
-
-
-
-
-
-










+







//
//		// The MIDI pitches are stored in the notes
//		//	s.notes[i].midi
//	}

// AbcMIDI creation
function AbcMIDI() {

    var	C = abc2svg.C
	// constants from Abc
	var	BAR = 0,
		CLEF = 1,
		GRACE = 4,
		KEY = 5,
		NOTE = 8

	// add MIDI pitches
	AbcMIDI.prototype.add = function(s,		// starting symbol
					voice_tb) {	// voice table

		var	scale = new Int8Array(		// note to pitch
					[0, 2, 4, 5, 7, 9, 11]),
			bmap = new Int8Array(7),	// measure base map
			map = new Int8Array(70),	// current map - 10 octaves
			tie_map,			// index = MIDI pitch
			tie_time,
			v,
			transp				// clef transpose

		// re-initialize the map on bar
		function bar_map() {
			for (var j = 0; j < 10; j++)
				for (var i = 0; i < 7; i++)
︙
89
90
91
92
93
94
95
96

97
98
99
100
101
102
103
84
85
86
87
88
89
90

91
92
93
94
95
96
97
98







-
+







		} // key_map()

		// convert ABC pitch to MIDI
		function pit2midi(p, a) {
			if (a)
				map[p] = a == 3 ? 0 : a; // (3 = natural)
			return ((p / 7) | 0) * 12 + scale[p % 7] +
						(tie_map[p] ||  map[p])
					(tie_time[p] ? tie_map[p] :  map[p])
		} // pit2midi()

		// initialize the clefs and keys
		for (v = 0; v < voice_tb.length; v++) {
			if (!voice_tb[v].sym)
				continue
			s = voice_tb[v].clef
︙
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
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







-



+








-
+






-
+




-
+








-
+






-
+

-
+



-
+




-
+


-
+


-
+

-
+







			// and loop on the symbols of the voice
			vloop(v)
		}
	    function vloop(v) {
		var	i, g, p, note,
			s = voice_tb[v].sym,
			vtime = s.time,		// next time
			tie_time = [],
			rep_tie_map = []

		tie_map = []
		tie_time = []
		while (s) {
			if (s.time > vtime) {	// if time skip
				bar_map()	// force a measure bar
				vtime = s.time
			}
			if (s.dur)
				vtime = s.time + s.dur
			switch (s.type) {
			case BAR:
			case C.BAR:
//fixme: pb when lack of measure bar (voice overlay, new voice)
				// x times repeat
				if (s.text) {
					if (s.text[0] == '1') {	// 1st time
						rep_tie_map = [];
						rep_tie_time = []
						for (i in tie_map)
						for (i = 0; i < tie_map.length; i++)
							rep_tie_map[i] = tie_map[i]
					} else if (rep_tie_map.length != 0) {
						tie_map = []
						tie_time = []
						for (i in rep_tie_map) {
						for (i = 0; i < rep_tie_map.length; i++) {
							tie_map[i] = rep_tie_map[i];
							tie_time[i] = s.time
						}
					}
				}
				if (!s.invis)
					bar_map()
				break
			case CLEF:
			case C.CLEF:
				if (!s.clef_octave
				 || s.clef_oct_transp)
					transp = 0
				else
					transp = s.clef_octave
				break
			case GRACE:
			case C.GRACE:
				for (g = s.extra; g; g = g.next) {
					if (!g.type != NOTE)
					if (!g.type != C.NOTE)
						continue
					for (i = 0; i <= g.nhd; i++) {
						note = g.notes[i];
						p = note.apit + 19 + transp;
						p = note.pit + 19 + transp;
						note.midi = pit2midi(p, note.acc)
					}
				}
				break
			case KEY:
			case C.KEY:
				key_map(s)
				break
			case NOTE:
			case C.NOTE:
				for (i = 0; i <= s.nhd; i++) {
					note = s.notes[i];
					p = note.apit + 19 +	// pitch from C-1
					p = note.pit + 19 +	// pitch from C-1
							transp
					if (tie_map[p]) {
					if (tie_time[p]) {
						if (s.time > tie_time[p]) {
							delete tie_map[p]
							delete tie_time[p]
						}
					}
					note.midi = pit2midi(p, note.acc)
					if (note.ti1) {
︙
Changes to util/play.js.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







// play-1.js - file to include in html pages with abc2svg-1.js for playing
//
// Copyright (C) 2015-2018 Jean-Francois Moine
// Copyright (C) 2015-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.
︙
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
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







-
-
-
-








-
-
-



+



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


-
+
-
-
-
-
-
-







// This file is a wrapper around
// - ToAudio (toaudio.js - convert ABC to audio sequences)
// - Audio5 (toaudio5.js - play the audio sequences with webaudio and SF2)
// - Midi5 (tomidi5.js - play the audio sequences with webmidi)

// AbcPlay methods:
//
// get_outputs() - return an array of output devices
//
// set_output() - set the output type/port
//
// set_sfu() - get/set the soundfont URL
// @url: URL - undefined = return current value
//
// set_speed() - get/set the play speed
// @speed: < 1 slower, > 1 faster - undefined = return current value
//
// set_vol() - get/set the current sound volume
// @volume: range [0..1] - undefined = return current value
//
// set_follow() - get/set the flag to call or not the 'onnote' callback
// @follow: boolean - undefined = return current value

function AbcPlay(i_conf) {
    var	conf = i_conf,
	init = {},
	audio = ToAudio(),
	audio5, midi5, current,
	abcplay = {				// returned object (only instance)

		// get the output type/ports
		get_outputs: function() {
		    var o,
			outputs = []

			if (midi5) {
				o = midi5.get_outputs()
				if (o)
					outputs = o
			}
			if (audio5) {
				o = audio5.get_outputs()
				if (o)
					outputs = outputs.concat(o)
			}
			return outputs
		},
		set_output: set_output,
		clear: audio.clear,
		add: audio.add,
		set_sft: vf
		set_sft: vf,
,
		set_follow: function(v) {
			if (v == undefined)
				return conf.follow
			conf.follow = v
		},
		set_sfu: function(v) {
			if (v == undefined)
				return conf.sfu
			conf.sfu = v
		},
		set_speed: function(v) {
			if (v == undefined)
︙
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
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







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

-
-
+
+
+
+
+
-


-
+








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



-
-
+
+
+
+


-











-
+
-
-
-







		stop: vf
	}

	function vf() {}			// void function

	// start playing when no defined output
	function play(istart, i_iend, a_e) {
		init.istart = istart;
		init.i_iend = i_iend;
		init.a_e = a_e
		if (midi5)
			midi5.get_outputs(play2) // get the MIDI ports
		else
			play2()
	} // play()

	// if set, out contains an array of the MIDI output ports
	function play2(out) {
	    var o,
		os = abcplay.get_outputs()
		if (os.length == 1) {
			o = 0
	    var o

		if (!out)
			out = []
		o = audio5.get_outputs()	// get the HTML5 audio port
		if (o)
			out = out.concat(o)
		if (out.length == 0) {
			if (conf.onend)		// no output port
				conf.onend()
		}
		if (out.length == 1) {
			o = 0			// only one port
		} else {
			o = -1
			var res = window.prompt('Use \n0: ' + os[0] +
			o = -1			// ask which port?
			var pr = "Use"
			for (var i = 0; i < out.length; i++)
				pr += "\n " + i + ": " + out[i]
			var res = window.prompt(pr, '0')
					'\n1: ' + os[1] + '?', '0')
			if (res) {
				o = Number(res)
				if (isNaN(o) || o < 0 || o >= os.length)
				if (isNaN(o) || o < 0 || o >= out.length)
					o = -1
			}
			if (!res || o < 0) {
				if (conf.onend)
					conf.onend()
				return
			}
		}
		set_output(os[o]);
		abcplay.play(istart, i_iend, a_e)
	}


	// set the current output changing the play functions
		// set the current output changing the play functions
	function set_output(name) {
		current = name == 'sf2' ? audio5 : midi5
		current = out[o] == 'sf2' ? audio5 : midi5;
		if (!current)
			return
		abcplay.play = current.play;
		abcplay.stop = current.stop
		if (current.set_output)
			current.set_output(name)
	} // set_output()
			current.set_output(out[o]);
		abcplay.play(init.istart, init.i_iend, init.a_e);
		init = {}
	} // play2()

	// set default configuration values
	conf.follow = true;
	conf.gain = 0.7;
	conf.speed = 1;

	// get the play parameters from localStorage
	(function get_param() {
		try {
			if (!localStorage)
				return
		} catch (e) {
			return
		}
	    var	v = localStorage.getItem("follow")
	    var	v = localStorage.getItem("sfu")
		if (v)
			conf.follow = v != "0";
		v = localStorage.getItem("sfu")
		if (v)
			conf.sfu = v;
		v = localStorage.getItem("volume")
		if (v)
			conf.gain = Number(v)
	})()

︙
Changes to util/sf2-parser.js.
1
2
3
4
5
6
7
8
9
10
11
12
13

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

13
14
15
16
17
18
19
20












-
+







/*! JavaScript SoundFont 2 Parser. Copyright 2013-2015 imaya/GREE Inc and Colin Clark. Licensed under the MIT License. */

/*
 * JavaScript SoundFont 2 Parser
 *
 * Copyright 2013 imaya/GREE Inc
 * Copyright 2015 Colin Clark
 *
 * Based on code from the "SoundFont Synthesizer for WebMidiLink"
 *   https://github.com/gree/sf2synth.js
 *
 * Adapted to abc2svg
 * Copyright (C) 2018 Jean-Francois Moine
 * Copyright (C) 2018-2019 Jean-Francois Moine
 *
 * Licensed under the MIT License.
 */

/*global require*/

(function (root, factory) {
︙
Changes to util/toaudio.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
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


-
+



















-
-
+
-
-
-
-
-
-
-
-











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












+
















+






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




















-
-
-
-
+
+
+
+
+







// toaudio.js - audio generation
//
// Copyright (C) 2015-2018 Jean-Francois Moine
// Copyright (C) 2015-2019 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/>.

// ToAudio creation
function ToAudio() {

// constants from Abc
  var	BAR = 0,
  var	C = abc2svg.C,
	CLEF = 1,
	GRACE = 4,
	KEY = 5,
	NOTE = 8,
	REST = 10,
	STAVES = 12,
	TEMPO = 14,
	BASE_LEN = 1536,

	scale = new Uint8Array([0, 2, 4, 5, 7, 9, 11]),	// note to pitch conversion

	a_e,				// event array

	p_time,				// last playing time
	abc_time,			// last ABC time
	play_factor;			// play time factor

// ToAudio
  return {

// clear the playing events and return the old ones
// clear the playing events and
// return the old ones as an array of Float32Array:
//	[0]: index of the note in the ABC source
//	[1]: time in seconds
//	[2]: if >= 0: MIDI instrument (MIDI GM number - 1)
//		else: MIDI control message
//	[3]: MIDI note pitch (with cents) / controller
//	[4]: duration			  / controller value
//	[5]: volume (0..1)
//	[6]: voice number
    clear: function() {
	var a_pe = a_e;
	a_e = null
	return a_pe
    }, // clear()

// add playing events from the ABC model
    add: function(start,		// starting symbol
		 voice_tb) {		// voice table
	var	kmaps = [],		// accidentals per voice from key signature
		cmaps = [],		// current accidental table
		map,			// map of the current voice - 10 octaves
		temper,			// temperament
		i, n, dt, d, v,
		top_v,			// top voice
		rep_st_s,		// start of sequence to be repeated
		rep_en_s,		// end ("|1")
		rep_nx_s,		// restart at end of repeat
		rep_st_transp,		// transposition at start of repeat sequence
		rep_st_map,		// and map
		rep_st_fac,		// and play factor
		transp,			// clef transposition per voice
		instr = [],		// instrument per voice
		s = start

	// set the accidentals, transpositions and instruments of the voices
	function set_voices() {
	    var v, p_v, s, mi

		temper = voice_tb[0].temper;	// (set by the module temper.js)
		transp = new Int8Array(voice_tb.length)
		for (v = 0; v < voice_tb.length; v++) {
			p_v = voice_tb[v];

			mi = p_v.instr || 0
			if (p_v.midictl) {
				if (p_v.midictl[32])		// bank LSB
					mi += p_v.midictl[32] * 128
				if (p_v.midictl[0])		// bank MSB
					mi += p_v.midictl[0] * 128 * 128
				p_v.midictl.forEach(function(val, i) {
					switch(i) {
					case 0:		// bank MSB
						mi += val * 128 * 128
						break
					case 32:	// bank LSB
						mi += val * 128
						break
					default:	// generate a MIDI control
						a_e.push(new Float32Array([
							p_v.sym.istart,
							1,	// (time)
							-1,	// MIDI control
							i,
							val,
							1,
							v]))
					}
				})
			}
			instr[v] = mi;			// MIDI instrument

			s = p_v.clef;
			transp[v] = (!s.clef_octave || s.clef_oct_transp) ?
					0 : s.clef_octave

			kmaps[v] = new Float32Array(70);
			cmaps[v] = new Float32Array(70);
			p_v.key.v = v;
			key_map(p_v.key)
		}
	} // set_voices()

	// define the accidentals of a voice
	function key_map(s) {
	    var i, bmap

	    if (s.k_bagpipe) {
		// detune for just intonation in A (C is C#, F is F# and G is Gnat)
		bmap = new Float32Array([100-13.7, -2, 2, 100-15.6, -31.2, 0, 3.9])
		for (i = 0; i < 7; i++)
			bmap[i] = (bmap[i] + 150.6) / 100 // 'A' bagpipe = 480Hz
				// 150.6 = (Math.log2(480/440) - 1)*1200
//		bmap = new Float32Array([100-13.7, -2, 2, 100-15.6, -31.2, 0, 3.9])
//		for (i = 0; i < 7; i++)
//			bmap[i] = (bmap[i] + 150.6) / 100 // 'A' bagpipe = 480Hz
//				// 150.6 = (Math.log2(480/440) - 1)*1200
		bmap = new Float32Array([2.37, 1.49, 1.53, 2.35, 1.19, 1.51, 1.55])
	    } else {
		bmap = new Float32Array(7)
		switch (s.k_sf) {
		case 7: bmap[6] = 1
		case 6: bmap[2] = 1
		case 5: bmap[5] = 1
		case 4: bmap[1] = 1
︙
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
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







-
-
-
+
+











+
+

-
+
+
+
+






-
+







	    for (i = 0; i < 10; i++)
		kmaps[s.v].set(bmap, i * 7);
	    cmaps[s.v].set(kmaps[s.v])
	} // key_map()

	// convert ABC pitch to MIDI index
	function pit2mid(s, i) {
		var	n, oct,
			note = s.notes[i];
			p = note.apit + 19, // pitch from C-1
		var	note = s.notes[i],
			p = note.pit + 19,	// pitch from C-1
			a = note.acc

		if (transp[s.v])
			p += transp[s.v]
		if (a) {
			if (a == 3)		// (3 = natural)
				a = 0
			else if (note.micro_n)
				a = (a < 0 ? -note.micro_n : note.micro_n) /
						note.micro_d * 2;
			map[p] = a
		} else {
			a = map[p]
		}
		return ((p / 7) | 0) * 12 + scale[p % 7] + map[p]
		p = ((p / 7) | 0) * 12 + scale[p % 7] + a
		if (!temper || a | 0 != a)	// if equal temperament or micro-tone
			return p
		return p + temper[p % 12]
	} // pit2mid()

	// handle the ties
	function do_tie(s, note, d) {
		var	n,
			end_time = s.time + s.dur,
			pit = note.apit,
			pit = note.pit,
			p = pit + 19,
			a = note.acc

		if (transp[s.v])
			p += transp[s.v]

		// search the end of the tie
︙
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
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







-
+





-
+















-
-
-
+
+
+


















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

-
+





-
+




-
+












-
+




-
+
+
+










-
+






-
-
+
+
+




















-
+







					s = s.ts_next
				if (!s)
					return d
				end_time = s.time
			}
			if (s.time != end_time)
				return d
			if (s.type == NOTE)
			if (s.type == C.NOTE)
				break
		}
		n = s.notes.length
		for (i = 0; i < n; i++) {
			note = s.notes[i]
			if (note.apit == pit) {
			if (note.pit == pit) {
				d += s.dur / play_factor;
				note.ti2 = true
				return note.ti1 ? do_tie(s, note, d) : d
			}
		}
		return d
	} // do_tie()

	// generate the grace notes
	function gen_grace(s) {
		var	g, i, n, t, d, s2,
			next = s.next

		// before beat
		if (s.sappo) {
			d = BASE_LEN / 16
		} else if ((!next || next.type != NOTE)
			&& s.prev && s.prev.type == NOTE) {
			d = C.BLEN / 16
		} else if ((!next || next.type != C.NOTE)
			&& s.prev && s.prev.type == C.NOTE) {
			d = s.prev.dur / 2

		// on beat
		} else {

			// keep the sound elements in time order
			next.ts_prev.ts_next = next.ts_next;
			next.ts_next.ts_prev = next.ts_prev;
			for (s2 = next.ts_next; s2; s2 = s2.ts_next) {
				if (s2.time != next.time) {
					next.ts_next = s2
					next.ts_prev = s2.ts_prev;
					next.ts_prev.ts_next = next;
					s2.ts_prev = next
					break
				}
			}

			if (!next.dots)
				d = next.dur / 2
			else if (next.dots == 1)
				d = next.dur / 3
//			if (!next.dots)
//				d = next.dur / 2
//			else if (next.dots == 1)
//				d = next.dur / 3
//			else
//				d = next.dur * 2 / 7;
			d = next.dur / 12
			if (d & (d - 1) == 0)
				d = next.dur / 2	// no dot
			else
				d = next.dur * 2 / 7;
				d = next.dur / 3;
			next.time += d;
			next.dur -= d
		}
		n = 0
		for (g = s.extra; g; g = g.next)
			if (g.type == NOTE)
			if (g.type == C.NOTE)
				n++;
		d /= n * play_factor;
		t = p_time
		for (g = s.extra; g; g = g.next) {
			if (g.type != NOTE)
			if (g.type != C.NOTE)
				continue
			gen_notes(g, t, d);
			t += d
		}
	} // gen_grace()

	// generate the notes
	function gen_notes(s, t, d) {
		for (var i = 0; i <= s.nhd; i++) {
		    var	note = s.notes[i]
			if (note.ti2)
				continue
			a_e.push([
			a_e.push(new Float32Array([
				s.istart,
				t,
				instr[s.v],
				pit2mid(s, i),
				note.ti1 ? do_tie(s, note, d) : d])
				note.ti1 ? do_tie(s, note, d) : d,
				1,
				s.v]))
		}
	} // gen_note()

	// add() main

	set_voices();			// initialize the voice parameters

	if (!a_e) {			// if first call
		a_e = []
		abc_time = rep_st_t = p_time = 0;
		play_factor = BASE_LEN / 4 * 120 / 60	// default: Q:1/4=120
		play_factor = C.BLEN / 4 * 120 / 60	// default: Q:1/4=120
	} else if (s.time < abc_time) {
		abc_time = rep_st_t = s.time
	}

	// loop on the symbols
	while (s) {
		if (s.type == TEMPO
		 && s.tempo) {
//		if (s.type == C.TEMPO
//		 && s.tempo) {
		if (s.tempo) {				// tempo change
			d = 0;
			n = s.tempo_notes.length
			for (i = 0; i < n; i++)
				d += s.tempo_notes[i];
			play_factor = d * s.tempo / 60
		}

		dt = s.time - abc_time
		if (dt > 0) {
			p_time += dt / play_factor;
			abc_time = s.time
		}

		if (s == rep_en_s) {			// repeat end
			s = rep_nx_s;
			abc_time = s.time
		}

		map = cmaps[s.v]
		switch (s.type) {
		case BAR:
		case C.BAR:
//fixme: does not work if different measures per voice
			if (s.v != top_v)
				break

			// right repeat
			if (s.bar_type[0] == ':') {
				s.bar_type = '|' +
︙
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
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







-
+



-
+




-
-
+
+





-
+


-
-
+
+

-
+


-
-
+
+




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

-
+

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











				break

			// 1st time repeat
			} else if (s.text && s.text[0] == '1') {
				rep_en_s = s
			}
			break
		case CLEF:
		case C.CLEF:
			transp[s.v] = (!s.clef_octave || s.clef_oct_transp) ?
					0 : s.clef_octave
			break
		case GRACE:
		case C.GRACE:
			if (s.time == 0		// if before beat at start time
			 && abc_time == 0) {
				dt = 0
				if (s.sappo)
					dt = BASE_LEN / 16
				else if (!s.next || s.next.type != NOTE)
					dt = C.BLEN / 16
				else if (!s.next || s.next.type != C.NOTE)
					dt = d / 2;
				abc_time -= dt
			}
			gen_grace(s)
			break
		case KEY:
		case C.KEY:
			key_map(s)
			break
		case REST:
		case NOTE:
		case C.REST:
		case C.NOTE:
			d = s.dur
			if (s.next && s.next.type == GRACE) {
			if (s.next && s.next.type == C.GRACE) {
				dt = 0
				if (s.next.sappo)
					dt = BASE_LEN / 16
				else if (!s.next.next || s.next.next.type != NOTE)
					dt = C.BLEN / 16
				else if (!s.next.next || s.next.next.type != C.NOTE)
					dt = d / 2;
				s.next.time -= dt;
				d -= dt
			}
			d /= play_factor
			if (s.type == NOTE)
				gen_notes(s, p_time, d / play_factor)
			if (s.type == C.NOTE)
				gen_notes(s, p_time, d)
			else
				a_e.push(new Float32Array([
					s.istart,
					p_time,
					0,
					0,
					d,
					0,
					s.v]))
			break
		case STAVES:
		case C.STAVES:
			top_v = s.sy.top_voice
			break
		case C.BLOCK:
			if (s.subtype != "midictl")
				break
			a_e.push(new Float32Array([	// generate a MIDI control
				s.istart,
				p_time,
				-1,			// MIDI control
				s.ctrl,
				s.val,
				1,
				s.v]))
			break
		}
		s = s.ts_next
	}
    } // add()
  } // return
} // ToAudio

// nodejs
if (typeof module == 'object' && typeof exports == 'object')
	exports.ToAudio = ToAudio
Changes to util/toaudio5.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
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


-
+

















-
+

-
-
+
+






+
+
+
+
+
+
+
+

+
+
+
+
+








-
+
-
-
-
+


-
+
+







// toaudio5.js - audio output using HTML5 audio
//
// Copyright (C) 2015-2018 Jean-Francois Moine
// Copyright (C) 2015-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.
//
// 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/>.

// Audio5 creation
// one argument:

// @conf: configuration object - all items are optional:
//	ac: audio context
//	sfu: soundfont URL (sf2 base64 encoded)
//	ac: audio context - (default: created on play start)
//	sfu: soundfont URL (sf2 base64 encoded - default: "Scc1t2")
//	onend: callback function called at end of playing
//		(no arguments)
//	onnote: callback function called on note start/stop playing
//		Arguments:
//			i: start index of the note in the ABC source
//			on: true on note start, false on note stop
//	instr_load: function to load the sound font of an instrument
//			(default: js_instr_load)
//		Arguments:
//			instr: MIDI instrument number
//			done: callback function in case of success
//				Arguments: soundfont in binary format
//			fail: callback function in case of error
//				no argument
//	errmsg: function called on error (default: alert)
//
//  When playing, the following items must/may be set:
//	gain: (mandatory) volume, must be set to [0..1]
//	speed: (mandatory) must be set to 1
//	new_speed: (optional) new speed value

// Audio5 methods

// get_outputs() - get the output devices
//	return ['sf2'] or null
//
// play() - start playing
// @start_index -
// @stop_index: play the notes found in ABC source between
// @stop_index: indexes of the play_event array
//		the start and stop indexes
// @play_event: optional (default: previous generated events)
//	array of array
// @play_event: array of array
//		[0]: index of the note in the ABC source
//		[1]: time in seconds
//		[2]: MIDI instrument (MIDI GM number - 1)
//		[2]: if >= 0: MIDI instrument (MIDI GM number - 1)
//			else: MIDI control message (not treated here)
//		[3]: MIDI note pitch (with cents)
//		[4]: duration
//		[5]: volume (0..1 - optional)
//
// stop() - stop playing
//
// set_vol() - set the current sound volume
︙
66
67
68
69
70
71
72
73
74















75
76
77
78
79
80
81
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







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







	// instruments/notes
		params = [],		// [instr][key] note parameters per instrument
		rates = [],		// [instr][key] playback rates
		w_instr = 0,		// number of instruments being loaded

	// -- play the memorized events --
		evt_idx,		// event index while playing
		iend,			// source stop index
		stime			// start playing time
		iend,			// play array stop index
		stime,			// start playing time
		timouts = []		// note start events

	// default sound font load function
	function js_instr_load(instr, done, fail) {
		abc2svg.loadjs(conf.sfu + '/' + instr + '.js',
			function() {
				 done(b64dcod(abcsf2[instr]))
			},
			fail
		)
	}
	if (!conf.instr_load)
		conf.instr_load = js_instr_load

	// base64 stuff
	    var b64d = []
	function init_b64d() {
	    var	b64l = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
		l = b64l.length
		for (var i = 0; i < l; i++)
︙
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
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







-
+

-
-
-
+
+
+


-
+
+





-
+
+









-
+


-
+

-
+







							(j + tune) * scale);
				params[instr][j] = parm
			}
		}
	} // sf2_create()

	// load an instrument (.js file)
	function load_instr(instr) {
	function load_instr(instr, a_e) {
		w_instr++;
		abc2svg.loadjs(conf.sfu + '/' + instr + '.js',
			function() {
			    var	parser = new sf2.Parser(b64dcod(abcsf2[instr]));
		conf.instr_load(instr,
			function(sf2_bin) {
			    var	parser = new sf2.Parser(sf2_bin);
				parser.parse();
				sf2_create(parser, instr);
				w_instr--
				if (--w_instr == 0)
					play_start(a_e)
			},
			function() {
				errmsg('could not find the instrument ' +
					((instr / 128) | 0).toString() + '-' +
					(instr % 128).toString());
				w_instr--
				if (--w_instr == 0)
					play_start(a_e)
			})
	} // load_instr()

	// start loading the instruments
	function load_res(a_e) {
		var i, e, instr

		for (i = evt_idx; ; i++) {
			e = a_e[i]
			if (!e || e[0] > iend)
			if (!e || evt_idx >= iend)
				break
			instr = e[2]
			if (!params[instr]) {
			if (instr >= 0 && !params[instr]) {
				params[instr] = [];
				load_instr(instr)
				load_instr(instr, a_e)
			}
		}
	}

	// create a note
	// @e[2] = instrument index
	// @e[3] = MIDI key + detune
︙
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
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







+
-
-
+
+
-













+





+
-
+


-
+

-

-
+




-
+










-
+

-
+




-
+
+

-
+
+

-
+
-

-







	} // note_run()

	// play the next time sequence
	function play_next(a_e) {
		var	t, e, e2, maxt, st, d;

		// play the next events
		if (a_e)			// if not stop
		e = a_e[evt_idx]
		if (!e
			e = a_e[evt_idx]
		if (!e || evt_idx >= iend) {
		 || e[0] > iend) {		// if source ref > source end
			onend()
			return
		}

		// if speed change, shift the start time
		if (conf.new_speed) {
			stime = ac.currentTime -
					(ac.currentTime - stime) *
						conf.speed / conf.new_speed;
			conf.speed = conf.new_speed;
			conf.new_speed = 0
		}

		timouts = [];
//fixme: better, count the number of events?
		t = e[1] / conf.speed;		// start time
		maxt = t + 3			// max time = evt time + 3 seconds
		while (1) {
			d = e[4] / conf.speed
			if (e[2] >= 0) {	// if not a MIDI control message
			if (e[5] != 0)		// if not a rest
			    if (e[5] != 0)		// if not a rest
				note_run(e, t + stime, d)

			if (conf.follow) {
			// follow the notes while playing
			    var	i = e[0];

				st = (t + stime - ac.currentTime) * 1000;
				setTimeout(onnote, st, i, true);
				timouts.push(setTimeout(onnote, st, i, true));
				setTimeout(onnote, st + d * 1000, i, false)
			}

			e = a_e[++evt_idx]
			if (!e) {
			if (!e || evt_idx >= iend) {
				setTimeout(onend,
					(t + stime - ac.currentTime + d) * 1000)
				return
			}
			t = e[1] / conf.speed
			if (t > maxt)
				break
		}

		// delay before next sound generation
		setTimeout(play_next, (t + stime - ac.currentTime)
		timouts.push(setTimeout(play_next, (t + stime - ac.currentTime)
				* 1000 - 300,	// wake before end of playing
				a_e)
				a_e))
	} // play_next()

	// wait for all resources, then start playing
	function play_start(a_e) {
		if (iend == 0)		// play stop
		if (iend == 0) {	// play stop
			onend()
			return

		}

		// wait for instruments
		if (w_instr != 0) {
		if (w_instr != 0)
			setTimeout(play_start, 300, a_e)
			return
		}

		// all resources are there
		gain.connect(ac.destination);
		stime = ac.currentTime + .2		// start time + 0.2s
			- a_e[evt_idx][1] * conf.speed;
		play_next(a_e)
	} // play_start()
︙
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
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







-
+
















-
+
-
-
-
-
-
-







+
+
+
+













	get_outputs: function() {
		return (window.AudioContext || window.webkitAudioContext) ?
				['sf2'] : null
	}, // get_outputs()

	// play the events
	play: function(istart, i_iend, a_e) {
		if (!a_e || !a_e.length) {
		if (!a_e || istart >= a_e.length) {
			onend()			// nothing to play
			return
		}

		// initialize the audio subsystem if not done yet
		// (needed for iPhone/iPad/...)
		if (!gain) {
			ac = conf.ac
			if (!ac)
				conf.ac = ac = new (window.AudioContext ||
							window.webkitAudioContext);
			gain = ac.createGain();
			gain.gain.value = conf.gain
		}

		iend = i_iend;
		evt_idx = 0
		evt_idx = istart;
		while (a_e[evt_idx] && a_e[evt_idx][0] < istart)
			evt_idx++
		if (!a_e[evt_idx]) {
			onend()			// nothing to play
			return
		}
		load_res(a_e);
		play_start(a_e)
	}, // play()

	// stop playing
	stop: function() {
		iend = 0
		timouts.forEach(function(id) {
					clearTimeout(id)
				})
		play_next()
		if (gain) {
			gain.disconnect();
			gain = null
		}
	}, // stop()

	// set volume
	set_vol: function(v) {
		if (gain)
			gain.gain.value = v
	} // set_vol()
    }
} // end Audio5
Changes to util/tomidi5.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
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













-
+

















-
+







+
+
+
+









-
+
-
-
-
+


-
-
-
+
+
+
+

+







+



-
+
-



-
-
+
+
+




+





+
+
-
+
+
+
+

+
+
-
-
-
+
+
+
+






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

-
+







+
+
-
+




-
-
-
-
-
-
-









+




+
-
+


-
+

-
+

+
+
+



-
+










-
+

-
+

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







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




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




-
+




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

+


-
-






+
+
+
+






-
-
-
-
-
-
-
-
-
-
-
// tomidi5.js - audio output using HTML5 MIDI
//
// Copyright (C) 2018 Jean-Francois Moine
// Copyright (C) 2018-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.
//
// 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/>.

// Midi5 creation
// one argument:

// @conf: configuration object - all items are optional:
//	onend: callback function called at end of playing
//		(no arguments)
//	onnote: callback function called on note start/stop playing
//		Arguments:
//			i: start index of the note in the ABC source
//			on: true on note start, false on note stop

//  When playing, the following items must/may be set:
//	speed: (mandatory) must be set to 1
//	new_speed: (optional) new speed value

// Midi5 methods

// get_outputs() - get the output ports
//
// set_output() - set the output port
//
// play() - start playing
// @start_index -
// @stop_index: play the notes found in ABC source between
// @stop_index: indexes of the play_event array
//		the start and stop indexes
// @play_event: optional (default: previous generated events)
//	array of array
// @play_event: array of array
//		[0]: index of the note in the ABC source
//		[1]: time in seconds
//		[2]: MIDI instrument (MIDI GM number - 1)
//		[3]: MIDI note pitch (with cents)
//		[4]: duration
//		[2]: if >= 0: MIDI instrument (MIDI GM number - 1)
//			else: MIDI control message
//		[3]: MIDI note pitch (with cents) / controller
//		[4]: duration			  / controller value
//		[5]: volume (0..1 - optional)
//		[6]: voice number
//
// stop() - stop playing

function Midi5(i_conf) {
    var	conf = i_conf,		// configuration
	onend = conf.onend || function() {},
	onnote = conf.onnote || function() {},
	rf,			// get_outputs result function

// MIDI variables
	op,			// output port
	instr,			// instrument -> channel
	v_i = [],		// voice (channel) to instrument
	ch,			// channel allocation

// -- play the memorized events --
	evt_idx,		// event index while playing
	iend,			// source stop index
	stime			// start playing time in ms
	iend,			// play array stop index
	stime,			// start playing time in ms
	timouts = []		// note start events

// create a note
// @e[2] = instrument index
// @e[3] = MIDI key + detune
// @e[6] = voice (channel) number
// @t = audio start time (ms)
// @d = duration adjusted for speed (ms)
    function note_run(e, t, d) {
    var	k = e[3] | 0,
	i = e[2],
	c = e[6] & 0x0f,	//fixme
	a = (e[3] * 100) % 100	// detune in cents
	c = instr[i]

	if (i == 16384) {			// if bank 128
		c = 9				// channel 10 (percussion)
	} else if (i != v_i[c]) {		// if program change

		// at channel start, reset all controllers
//fixme: does not work with fluidsynth
	if (c == undefined) {
		c = ch++;
		instr[i] = c;
		if (v_i[c] == undefined)
			op.send(new Uint8Array([0xb0 + c, 121, 0]));

		v_i[c] = i
		op.send(new Uint8Array([
				0xb0 + c, 0, (i >> 14) & 0x7f,	// MSB bank
				0xb0 + c, 32, (i >> 7) & 0x7f,	// LSB bank
				0xc0 + c, i & 0x7f		// program
			]))
	}
	if (a && Midi5.ma.sysexEnabled) {	// if microtone
// fixme: should cache the current microtone values
		op.send(new Uint8Array([
			0xf0, 0x7f,	// realtime SysEx
			0x7f,		// all devices
			0x08,		// MIDI tuning standard
			0x02,		// note change
			i & 0x7f,		// tuning prog number
			0x01,		// number of notes
				k,		// key
				k,		// note
				a / .78125,	// MSB fract
				0,		// LSB fract
			0xf7		// SysEx end
			]), t);
	}
	op.send(new Uint8Array([0x90 + c, k, 127]), t);		// note on
	op.send(new Uint8Array([0x80 + c, k, 0x40]), t + d - 20) // note off
	op.send(new Uint8Array([0x80 + c, k, 0]), t + d - 20) // note off
    } // note_run()

// play the next time sequence
    function play_next(a_e) {
    var	t, e, e2, maxt, st, d

	// play the next events
	if (a_e)			// if not stop
		e = a_e[evt_idx]
	if (!op) {
	if (!op || evt_idx >= iend || !e) {
		onend()
		return
	}
			
	e = a_e[evt_idx]
	if (!e
	 || e[0] > iend) {		// if source ref > source end
		onend()
		return
	}

	// if speed change, shift the start time
	if (conf.new_speed) {
		stime = window-performance.now() -
				(window.performance.now() - stime) *
					conf.speed / conf.new_speed;
		conf.speed = conf.new_speed;
		conf.new_speed = 0
	}

	timouts = [];
	t = e[1] / conf.speed * 1000;	// start time
	maxt = t + 3000			// max time = evt time + 3 seconds
	while (1) {
		d = e[4] / conf.speed * 1000
		if (e[2] >= 0) {		// if not a MIDI control message
		if (e[5] != 0)		// if not a rest
		    if (e[5] != 0)		// if not a rest
			note_run(e, t + stime, d)

		if (conf.follow) {
		// follow the notes while playing
			st = t + stime - window.performance.now();
			setTimeout(onnote, st, e[0], true);
			timouts.push(setTimeout(onnote, st, e[0], true));
			setTimeout(onnote, st + d, e[0], false)
		} else {				// MIDI control
			op.send(new Uint8Array([0xb0 + (e[6] & 0x0f),
						e[3], e[4]]), t + stime)
		}

		e = a_e[++evt_idx]
		if (!e) {
		if (!e || evt_idx >= iend) {
			setTimeout(onend,
				t + stime - window.performance.now() + d)
			return
		}
		t = e[1] / conf.speed * 1000
		if (t > maxt)
			break
	}

	// delay before next sound generation
	setTimeout(play_next, (t + stime - window.performance.now())
	timouts.push(setTimeout(play_next, (t + stime - window.performance.now())
			- 300,		// wake before end of playing
			a_e)
			a_e))
    } // play_next()

    // MIDI output is possible,
    // return the possible ports in return to get_outputs()
    function send_outputs(access) {
    var	o, os,
	out = [];

	Midi5.ma = access;	// store the MIDI access in the Midi5 function

	if (access && access.outputs.size > 0) {
		os = access.outputs.values()
		while (1) {
			o = os.next()
			if (!o || o.done)
				break
			out.push(o.value.name)
		}
	}
	rf(out)
    } // send_outputs()

// Midi5 object creation (only one instance)

// public methods
    return {

	// get outputs
	get_outputs: function() {
//fixme: just the first output port for now...
		if (Midi5.ma)
			op = Midi5.ma.outputs.values().next().value
			if (op)
				return [op.name]
	get_outputs: function(f) {
		if (!navigator.requestMIDIAccess) {
			f()			// no MIDI
			return
		}
		rf = f;

		// open MIDI with SysEx
		navigator.requestMIDIAccess({sysex: true}).then(
			send_outputs,
			function(msg) {

				// open MIDI without SysEx
				navigator.requestMIDIAccess().then(
					send_outputs,
					function(msg) {
						rf()
					}
				)
			}
		)
	}, // get_outputs()

	// set the output port
	set_output: function(name) {
//fixme: todo
//		if (!Midi5.ma)
//			return
	    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
			}
		}
	},

	// play the events
	play: function(istart, i_iend, a_e) {
		if (!a_e || !a_e.length) {
		if (!a_e || istart >= a_e.length) {
			onend()			// nothing to play
			return
		}
		iend = i_iend;
		evt_idx = 0
		evt_idx = istart;
		while (a_e[evt_idx] && a_e[evt_idx][0] < istart)
			evt_idx++
		if (!a_e[evt_idx]) {
			onend()			// nothing to play
			return
		}
if (0) {
// temperament
	op.send(new Uint8Array([
			0xf0, 0x7f,	// realtime SysEx
			0x7f,		// all devices
			0x08,		// MIDI tuning standard
			0x02,		// note change
			0x00,		// tuning prog number
			0x01,		// number of notes
				0x69,		// key
				0x69,		// note
				0x00,		// MSB fract
				0,		// LSB fract
			0xf7		// SysEx end
			]), t);
}

		v_i = [];		// must do a reset of all channels
		stime = window.performance.now() + 200	// start time + 0.2s
			- a_e[evt_idx][1] * conf.speed * 1000;
		instr = [];
		ch = 0;
		play_next(a_e)
	}, // play()

	// stop playing
	stop: function() {
		iend = 0
		timouts.forEach(function(id) {
					clearTimeout(id)
				})
		play_next()
//fixme: op.clear() should exist...
		if (op && op.clear)
			op.clear()
	} // stop()
    }
} // end Midi5

// check MIDI access at script load time
function onMIDISuccess(access) {
	Midi5.ma = access	// store the MIDI access in the Midi5 function
} // onMIDISuccess()

function onMIDIFailure(msg) {
} // onMIDIFailure()

if (navigator.requestMIDIAccess)
	navigator.requestMIDIAccess().then(onMIDISuccess, onMIDIFailure)