]> git.donarmstrong.com Git - lilypond.git/blob - mf/feta-noteheads.mf
87d9034713359aeb5e9cd0d4266334c8cbbf23ae
[lilypond.git] / mf / feta-noteheads.mf
1 % Feta (not the Font-En-Tja) music font -- implement noteheads
2 % This file is part of LilyPond, the GNU music typesetter.
3 %
4 % Copyright (C) 1997--2011 Jan Nieuwenhuizen <janneke@gnu.org>
5 % & Han-Wen Nienhuys <hanwen@xs4all.nl>
6 % & Juergen Reuter <reuter@ipd.uka.de>
7 %
8 %
9 % LilyPond is free software: you can redistribute it and/or modify
10 % it under the terms of the GNU General Public License as published by
11 % the Free Software Foundation, either version 3 of the License, or
12 % (at your option) any later version.
13 %
14 % LilyPond is distributed in the hope that it will be useful,
15 % but WITHOUT ANY WARRANTY; without even the implied warranty of
16 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 % GNU General Public License for more details.
18 %
19 % You should have received a copy of the GNU General Public License
20 % along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
21
22 test_outlines := 0;
23
24
25 save remember_pic;
26 picture remember_pic;
27
28
29 % Most beautiful noteheads are pronounced, not circular,
30 % and not even symmetric.
31 % These examples are inspired by [Wanske]; see literature list.
32
33
34
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 % NOTE HEAD VARIABLES
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38
39 save half_notehead_width, whole_notehead_width;
40 save solfa_noteheight;
41
42 numeric whole_notehead_width;
43 numeric half_notehead_width;
44
45 fet_begingroup ("noteheads");
46
47
48 %
49 % solfa heads should not overlap on chords.
50 %
51 solfa_noteheight# := staff_space# - stafflinethickness#;
52
53 def undraw_inside_ellipse (expr ellipticity, tilt, superness, clearance) =
54 begingroup
55         save pat;
56         path pat;
57
58         pat := superellipse ((ellipticity, 0), (0, 1.0),
59                              (-ellipticity, 0), (0, -1.0),
60                              superness);
61         pat := pat rotated tilt;
62
63         save top_point, right_point;
64         pair top_point, right_point;
65
66         top_point := directionpoint left of pat;
67         right_point := directionpoint up of pat;
68
69         save height, scaling;
70
71         height# = staff_space# + stafflinethickness# - clearance;
72         scaling# = height# / (2 ypart (top_point));
73         define_pixels (scaling);
74         pat := pat scaled scaling shifted (w / 2, .5 (h - d));
75
76         if test_outlines = 1:
77                 draw pat;
78         else:
79                 unfill pat;
80         fi
81 endgroup;
82 enddef;
83
84
85 %
86 % dimensions aren't entirely right.
87 %
88 def draw_longa (expr up) =
89         save stemthick, fudge;
90
91         stemthick# = 2 stafflinethickness#;
92         define_whole_blacker_pixels (stemthick);
93
94         fudge = hround (blot_diameter / 2);
95
96         draw_outside_ellipse (1.80, 0, 0.707, 0);
97         undraw_inside_ellipse (1.30, 125, 0.68, 2 stafflinethickness#);
98
99         pickup pencircle scaled stemthick;
100
101         if up:
102                 bot y1 = -d;
103                 top y2 = h;
104                 rt x1 - fudge = 0;
105                 x1 = x2;
106
107                 fudge + lft x3 = w;
108                 x4 = x3;
109                 top y4 = h + 3.0 staff_space;
110                 y3 = y1;
111         else:
112                 bot y1 = -d - 3.0 staff_space;
113                 top y2 = h;
114                 rt x1 - fudge = 0;
115                 x1 = x2;
116
117                 fudge + lft x3 = w;
118                 x4 = x3;
119                 y4 = y2;
120                 bot y3 = -d;
121         fi;
122
123         draw_gridline (z1, z2, stemthick);
124         draw_gridline (z3, z4, stemthick);
125
126         labels (1, 2, 3, 4);
127 enddef;
128
129
130 fet_beginchar ("Longa notehead", "uM2");
131         draw_longa (true);
132
133         draw_staff (-2, 2, 0);
134 fet_endchar;
135
136
137 fet_beginchar ("Longa notehead", "dM2");
138         draw_longa (false);
139
140         draw_staff (-2, 2, 0);
141 fet_endchar;
142
143
144 if test > 0:
145         fet_beginchar ("Longa notehead", "uM2");
146                 draw_longa (true);
147
148                 draw_staff (-2, 2, 0.5);
149         fet_endchar;
150
151
152         fet_beginchar ("Longa notehead", "dM2");
153                 draw_longa (false);
154
155                 draw_staff (-2, 2, 0.5);
156         fet_endchar;
157 fi;
158
159
160 def draw_brevis (expr linecount, line_thickness_multiplier) =
161         save stemthick, fudge, gap;
162
163         stemthick# = line_thickness_multiplier * 2 * stafflinethickness#;
164         define_whole_blacker_pixels (stemthick);
165
166         % double-lined breves of smaller design sizes should have
167         % bigger gap between the lines.
168         gap# := (0.95 - 0.008 * design_size) * stemthick#;
169
170         % Breves of smaller design sizes should have their lines farther
171         % apart (the overlap with notehead ellipsoid should be smaller).
172         fudge = hround (blot_diameter
173                         * min (max (-0.15,
174                                     (0.8
175                                      - (20 / (design_size + 4))
176                                      + .1 linecount)),
177                                0.3));
178
179         draw_outside_ellipse (1.80, 0, 0.707, 0);
180         undraw_inside_ellipse (1.30, 125, 0.68, 2 stafflinethickness#);
181
182         set_char_box (stemthick# * linecount + gap# * (linecount - 1),
183                       width# + stemthick# * linecount + gap# * (linecount - 1),
184                       noteheight# / 2,
185                       noteheight# / 2);
186
187         define_pixels (gap);
188         pickup pencircle scaled stemthick;
189
190         % Breves of smaller design sizes should have their lines longer.
191         line_length := min (max (0.7, (64/60 - (design_size / 60))), 0.85);
192
193         % Line lengths between 0.72 and 0.77 are not nice
194         % because they are neither separate nor connected
195         % when there is an interval of fourth.
196         if line_length < 0.75:
197                 quanted_line_length := min (0.72, line_length);
198         else:
199                 quanted_line_length := max (0.77, line_length);
200         fi;
201
202         bot y1 = -quanted_line_length * staff_space;
203         top y2 = quanted_line_length * staff_space;
204         rt x1 - fudge = 0;
205         x1 = x2;
206
207         fudge + lft x3 = width;
208         x4 = x3;
209         y4 = y2;
210         y3 = y1;
211
212         for i := 0 step 1 until linecount - 1:
213                 line_distance := i * (gap + stemthick);
214                 draw_gridline (z1 - (line_distance, 0),
215                                z2 - (line_distance, 0),
216                                stemthick);
217                 draw_gridline (z3 + (line_distance, 0),
218                                z4 + (line_distance, 0),
219                                stemthick);
220         endfor;
221 enddef;
222
223
224 fet_beginchar ("Brevis notehead", "sM1");
225         draw_brevis (1, 1);
226
227         draw_staff (-2, 2, 0);
228 fet_endchar;
229
230
231 if test > 0:
232         fet_beginchar ("Brevis notehead", "sM1");
233                 draw_brevis(1, 1);
234
235                 draw_staff (-2, 2, 0.5);
236         fet_endchar;
237 fi;
238
239
240 fet_beginchar ("Double-lined brevis notehead", "sM1double");
241         draw_brevis (2, 0.8);
242
243         draw_staff (-2, 2, 0);
244 fet_endchar;
245
246
247 if test > 0:
248         fet_beginchar ("Double-lined brevis notehead", "sM1double");
249                 draw_brevis (2, 0.8);
250
251                 draw_staff (-2, 2, 0.5);
252         fet_endchar;
253 fi;
254
255
256 fet_beginchar ("Whole notehead", "s0");
257         draw_outside_ellipse (1.80 - puff_up_factor / 3.0, 0, 0.707, 0);
258         undraw_inside_ellipse (1.30, 125 - puff_up_factor * 10,
259                                0.68, 2 stafflinethickness#);
260
261         whole_notehead_width# := charwd;
262
263         draw_staff (-2, 2, 0);
264 fet_endchar;
265
266
267 if test > 0:
268         fet_beginchar ("Whole notehead", "s0");
269                 draw_outside_ellipse (1.80 - puff_up_factor / 3.0, 0,
270                                       0.707, 0);
271                 undraw_inside_ellipse (1.30, 125 - puff_up_factor * 10,
272                                        0.68, 2 stafflinethickness#);
273
274                 draw_staff (-2, 2, 0.5);
275         fet_endchar;
276 fi;
277
278
279 fet_beginchar ("Half notehead", "s1");
280         draw_outside_ellipse (1.53 - puff_up_factor / 3.0, 34, 0.66, 0.17);
281         undraw_inside_ellipse (3.25, 33, 0.81, 2.5 stafflinethickness#);
282
283         half_notehead_width# := charwd;
284
285         draw_staff (-2, 2, 0);
286 fet_endchar;
287
288
289 if test > 0:
290         fet_beginchar ("Half notehead", "s1");
291                 draw_outside_ellipse (1.53 - puff_up_factor / 3.0, 34,
292                                       0.66, 0.17);
293                 undraw_inside_ellipse (3.25, 33, 0.81,
294                                        2.5 stafflinethickness#);
295
296                 draw_staff (-2, 2, 0.5);
297         fet_endchar;
298 fi;
299
300
301 fet_beginchar ("Quarter notehead", "s2");
302         draw_quarter_path;
303         draw_staff (-2, 2, 0);
304 fet_endchar;
305
306
307 if test > 0:
308         fet_beginchar ("Quarter notehead", "s2");
309                 draw_outside_ellipse (1.49 - puff_up_factor / 3.0, 31,
310                                       0.707, 0);
311
312                 draw_staff (-2, 2, 0.5);
313         fet_endchar;
314 fi;
315
316
317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318
319
320 fet_beginchar ("Whole diamondhead", "s0diamond");
321         draw_outside_ellipse (1.80, 0, 0.495, 0);
322         undraw_inside_ellipse (1.30, 125, 0.6,
323                                .4 staff_space# + stafflinethickness#);
324
325         draw_staff (-2, 2, 0);
326 fet_endchar;
327
328
329 if test > 0:
330         fet_beginchar ("Whole diamondhead", "s0diamond");
331                 draw_outside_ellipse (1.80, 0, 0.495, 0);
332                 undraw_inside_ellipse (1.30, 125, 0.6,
333                                        .4 staff_space# + stafflinethickness#);
334
335                 draw_staff (-2, 2, 0.5);
336         fet_endchar;
337 fi;
338
339
340 fet_beginchar ("Half diamondhead", "s1diamond");
341         draw_outside_ellipse (1.50, 34, 0.49, 0.17);
342         undraw_inside_ellipse (3.5, 33, 0.80,
343                                .3 staff_space# + 1.5 stafflinethickness#);
344
345         draw_staff (-2, 2, 0);
346 fet_endchar;
347
348
349 if test > 0:
350         fet_beginchar ("Half diamondhead", "s1diamond");
351                 draw_outside_ellipse (1.50, 34, 0.49, 0.17);
352                 undraw_inside_ellipse (3.5, 33, 0.80,
353                                        .3 staff_space#
354                                        + 1.5 stafflinethickness#);
355
356                 draw_staff (-2, 2, 0.5);
357         fet_endchar;
358 fi;
359
360
361 fet_beginchar ("Quarter diamondhead", "s2diamond");
362         draw_outside_ellipse (1.80, 35, 0.495, -0.25);
363
364         draw_staff (-2, 2, 0);
365 fet_endchar;
366
367
368 if test > 0:
369         fet_beginchar ("Quarter diamondhead", "s2diamond");
370                 draw_outside_ellipse (1.80, 35, 0.495, -0.25);
371
372                 draw_staff (-2, 2, 0.5);
373         fet_endchar;
374 fi;
375
376
377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378
379
380 vardef penposx@# (expr d) =
381 begingroup;
382         save pat;
383         path pat;
384
385         pat = top z@#
386               .. lft z@#
387               .. bot z@#
388               .. rt z@#
389               .. cycle;
390         z@#l = pat intersectionpoint (z@# -- infinity * dir (d + 180));
391         z@#r = pat intersectionpoint (z@# -- infinity * dir (d));
392 endgroup
393 enddef;
394
395
396 %
397 % UGH: xs not declared as argument.
398 %
399 def define_triangle_shape (expr stemdir) =
400         save triangle_a, triangle_b, triangle_c;
401         save triangle_out_a, triangle_out_b, triangle_out_c;
402         save triangle_in, triangle_out;
403         save width, depth, height;
404         save origin, left_up_dir;
405         save exact_left_point, exact_right_point, exact_down_point;
406
407         path triangle_a, triangle_b, triangle_c;
408         path triangle_out_a, triangle_out_b, triangle_out_c;
409         path triangle_in, triangle_out;
410         pair origin, left_up_dir;
411         pair exact_down_point, exact_left_point, exact_right_point;
412
413         save pen_thick;
414         pen_thick# = stafflinethickness# + .1 staff_space#;
415         define_pixels (llap);
416         define_blacker_pixels (pen_thick);
417
418         left_up_dir = llap# * dir (90 + tilt);
419
420         xpart (left_up_dir) * xs - (pen_thick# * xs) / 2 + xpart origin = 0;
421         ypart origin = 0;
422
423         exact_left_point := origin + (left_up_dir xscaled xs);
424         exact_down_point := origin + (left_up_dir rotated 120 xscaled xs);
425         exact_right_point := origin + (left_up_dir rotated 240 xscaled xs);
426
427         height# = ypart (exact_left_point + origin) + pen_thick# / 2;
428         depth# = -ypart (exact_down_point + origin) + pen_thick# / 2;
429         width# = xpart (exact_right_point - exact_left_point)
430                  + pen_thick# * xs;
431
432         set_char_box (0, width#, depth#, height#);
433
434         % Formerly, the shape has simply been drawn with an elliptical pen
435         % (`scaled pen_thick xscaled xs'), but the envelope of such a curve
436         % is of 6th degree.  For the sake of mf2pt1, we approximate it.
437
438         pickup pencircle scaled pen_thick xscaled xs;
439
440         z0 = (hround_pixels (xpart origin), 0);
441
442         z1 = z1' = z0 + llap * dir (90 + tilt) xscaled xs;
443         z2 = z2' = z0 + llap * dir (90 + tilt + 120) xscaled xs;
444         z3 = z3' = z0 + llap * dir (90 + tilt + 240) xscaled xs;
445
446         z12 = caveness [.5[z1, z2], z3];
447         z23 = caveness [.5[z2, z3], z1];
448         z31 = caveness [.5[z3, z1], z2];
449
450         triangle_a = z1 .. z12 .. z2;
451         triangle_b = z2 .. z23 .. z3;
452         triangle_c = z3 .. z31 .. z1;
453
454         penposx1 (angle (direction 0 of triangle_a) - 90);
455         penposx2 (angle (direction 0 of triangle_b) - 90);
456         penposx3 (angle (direction 0 of triangle_c) - 90);
457
458         penposx1' (angle (direction infinity of triangle_c) + 90);
459         penposx2' (angle (direction infinity of triangle_a) + 90);
460         penposx3' (angle (direction infinity of triangle_b) + 90);
461
462         penposx12 (angle (z12 - z0));
463         penposx23 (angle (z23 - z0));
464         penposx31 (angle (z31 - z0));
465
466         z10 = (z0 -- z1) intersectionpoint (z1l .. z12l .. z2'r);
467         z20 = (z0 -- z2) intersectionpoint (z2l .. z23l .. z3'r);
468         z30 = (z0 -- z3) intersectionpoint (z3l .. z31l .. z1'r);
469
470         triangle_in = z10
471                       .. z12l
472                       .. z20
473                       & z20
474                       .. z23l
475                       .. z30
476                       & z30
477                       .. z31l
478                       .. z10
479                       & cycle;
480
481         triangle_out_a = z1r .. z12r .. z2'l;
482         triangle_out_b = z2r .. z23r .. z3'l;
483         triangle_out_c = z3r .. z31r .. z1'l;
484
485         triangle_out = top z1
486                        .. lft z1
487                        .. z1r{direction 0 of triangle_out_a}
488                        & triangle_out_a
489                        & {direction infinity of triangle_out_a}z2'l
490                        .. lft z2
491                        .. bot z2
492                        .. z2r{direction 0 of triangle_out_b}
493                        & triangle_out_b
494                        & {direction infinity of triangle_out_b}z3'l
495                        .. rt z3
496                        .. top z3
497                        .. z3r{direction 0 of triangle_out_c}
498                        & triangle_out_c
499                        & {direction infinity of triangle_out_c}z1'l
500                        .. cycle;
501
502         labels (0, 10, 20, 30);
503         penlabels (1, 1', 2, 2', 3, 3', 12, 23, 31);
504
505         % attachment Y
506         if stemdir = 1:
507                 charwy := ypart exact_right_point;
508                 charwx := xpart exact_right_point + .5 pen_thick# * xs;
509         else:
510                 charwy := -ypart exact_down_point;
511                 charwx := width# - (xpart exact_down_point - .5 pen_thick# * xs);
512         fi
513 enddef;
514
515
516 def draw_whole_triangle_head =
517         save hei, xs;
518         save llap;
519         save tilt;
520
521         tilt = 40;
522         llap# = 3/4 noteheight#;
523
524         xs = 1.5;
525         caveness := 0.1;
526         define_triangle_shape (1);
527         fill triangle_out;
528         unfill triangle_in;
529 enddef;
530
531
532 fet_beginchar ("Whole trianglehead", "s0triangle");
533         draw_whole_triangle_head;
534
535         draw_staff (-2, 2, 0);
536 fet_endchar;
537
538
539 if test > 0:
540         fet_beginchar ("Whole trianglehead", "s0triangle");
541                 draw_whole_triangle_head;
542
543                 draw_staff (-2, 2, 0.5);
544         fet_endchar;
545 fi;
546
547
548 def draw_small_triangle_head (expr dir) =
549         save hei, xs;
550         save llap;
551         save tilt;
552
553         tilt = 40;
554         llap# = 2/3 noteheight#;
555         xs = 1.2;
556         caveness := 0.1;
557         define_triangle_shape (dir);
558
559         pickup feta_fillpen;
560
561         filldraw triangle_out;
562         unfilldraw triangle_in;
563 enddef;
564
565
566 fet_beginchar ("Half trianglehead (downstem)", "d1triangle");
567         draw_small_triangle_head (-1);
568
569         draw_staff (-2, 2, 0);
570 fet_endchar;
571
572
573 fet_beginchar ("Half trianglehead (upstem)", "u1triangle");
574         draw_small_triangle_head (1);
575
576         draw_staff (-2, 2, 0.5);
577 fet_endchar;
578
579
580 def draw_closed_triangle_head (expr dir) =
581         save hei, xs;
582         save llap;
583         save tilt;
584
585         tilt = 40;
586         llap# = 2/3 noteheight#;
587         xs = 1.0;
588         caveness := 0.1;
589         define_triangle_shape (dir);
590         fill triangle_out;
591 enddef;
592
593
594 fet_beginchar ("Quarter trianglehead (upstem)", "u2triangle");
595         draw_closed_triangle_head (1);
596
597         draw_staff (-2, 2, 0);
598 fet_endchar;
599
600
601 fet_beginchar ("Quarter trianglehead (downstem)", "d2triangle");
602         draw_closed_triangle_head (-1);
603
604         draw_staff (-2, 2, 0.5);
605 fet_endchar;
606
607
608 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
609 %
610 % Slash heads are for indicating improvisation.  They are
611 % twice as high as normal heads.
612 %
613 def draw_slash (expr hwid_hash) =
614         save exact_height;
615         save ne, nw_dist;
616         pair ne, nw_dist;
617         exact_height = staff_space# + stafflinethickness# / 2;
618
619         set_char_box (0, 2 exact_height / slash_slope + hwid_hash,
620                       exact_height, exact_height);
621
622         charwx := charwd;
623         charwy := charht;
624
625         clearxy;
626
627         d := d - feta_shift;
628
629         pickup pencircle scaled blot_diameter;
630
631         bot y1 = -d;
632         top y2 = h;
633         lft x1 = 0;
634         lft x2 = 2 h / slash_slope;
635
636         rt x3 = w;
637         y3 = y2;
638         y4 = y1;
639         x3 - x2 = x4 - x1;
640
641         ne = unitvector (z3 - z4);
642         nw_dist = (ne rotated 90) * 0.5 blot_diameter;
643
644         fill bot z1{left}
645              .. (z1 + nw_dist){ne}
646              -- (z2 + nw_dist){ne}
647              .. top z2{right}
648              -- top z3{right}
649              .. (z3 - nw_dist){-ne}
650              -- (z4 - nw_dist){-ne}
651              .. bot z4{left}
652              -- cycle;
653
654         if hwid_hash > 2 slash_thick#:
655                 save th;
656
657                 th = slash_thick - blot_diameter;
658                 y6 = y7;
659                 y5 = y8;
660                 y3 - y7 = th;
661                 y5 - y1 = th;
662                 z6 - z5 = whatever * ne;
663                 z8 - z7 = whatever * ne;
664
665                 z5 = z1 + whatever * ne + th * (ne rotated -90);
666                 z8 = z4 + whatever * ne + th * (ne rotated 90);
667
668                 unfill z5
669                        -- z6
670                        -- z7
671                        -- z8
672                        -- cycle;
673         fi
674         labels (range 1 thru 10);
675 enddef;
676
677
678 fet_beginchar ("Whole slashhead", "s0slash");
679         draw_slash (4 slash_thick# + 0.5 staff_space#);
680
681         draw_staff (-2, 2, 0);
682 fet_endchar;
683
684
685 fet_beginchar ("Half slashhead", "s1slash");
686         draw_slash (3.0 slash_thick# + 0.15 staff_space#);
687
688         draw_staff (-2, 2, 0);
689 fet_endchar;
690
691
692 fet_beginchar ("Quarter slashhead", "s2slash");
693         draw_slash (1.5 slash_thick#);
694
695         draw_staff (-2, 2, 0);
696 fet_endchar;
697
698
699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
700 %
701 % `thick' is the distance between the NE/SW parallel lines in the cross
702 % (distance between centres of lines) in multiples of stafflinethickness
703 %
704 def draw_cross (expr thick) =
705         save ne, nw;
706         save ne_dist, nw_dist, rt_dist, up_dist;
707         save crz_in, crz_out;
708         save thickness;
709         pair ne, nw;
710         pair ne_dist, nw_dist, rt_dist, up_dist;
711         path crz_in, crz_out;
712
713         pen_thick# := 1.2 stafflinethickness#;
714         thickness# := thick * stafflinethickness#;
715         define_pixels (thickness);
716         define_blacker_pixels (pen_thick);
717
718         pickup pencircle scaled pen_thick;
719
720         h := h - feta_shift;
721
722         top y3 = h;
723         ne = unitvector ((1, (2 h - pen_thick) / (w - pen_thick)));
724         rt x4 = w / 2;
725         y5 = 0;
726         z4 - z5 = whatever * ne;
727         x6 = 0;
728         z6 - z3 = whatever * ne;
729         z3 - z4 = whatever * (ne yscaled -1);
730
731         z4 - z3 = whatever * (ne) + (ne rotated -90) * thickness;
732
733
734         x1 = charwd / 2 - .5 pen_thick#;
735         z1 = whatever * ne
736              + thick / 2 * stafflinethickness# * (ne rotated -90);
737
738         % labels (1, 2, 3, 4, 5, 6);
739
740         nw = unitvector (z3 - z4);
741
742         up_dist = up * 0.5 pen_thick / cosd (angle (ne));
743         rt_dist = right * 0.5 pen_thick / sind (angle (ne));
744         nw_dist = (ne rotated 90) * 0.5 pen_thick;
745         ne_dist = (nw rotated -90) * 0.5 pen_thick;
746
747         x4' := x4;
748         x5' := x5;
749         y6' := y6;
750
751         x4 := hround (x4' + .5 pen_thick) - .5 pen_thick;
752         x5 := hfloor (x5' + xpart rt_dist) - xpart rt_dist;
753         y6 := vfloor (y6' + ypart up_dist) - ypart up_dist;
754
755         crz_out = (z6 + up_dist)
756                   -- (z3 + nw_dist){ne}
757                   .. (top z3)
758                   .. (z3 + ne_dist){-nw}
759                   -- (z4 + ne_dist){-nw}
760                   .. (rt z4)
761                   .. (z4 - nw_dist){-ne}
762                   -- (z5 + rt_dist);
763         crz_out := crz_out shifted (0, feta_shift)
764                    -- reverse crz_out yscaled -1 shifted (0, -feta_eps);
765         fill crz_out
766              -- reverse crz_out xscaled -1 shifted (-feta_eps, 0)
767              -- cycle;
768
769         if (thick > 1):
770                 x4 := hround (x4' - xpart rt_dist) + xpart rt_dist;
771                 x5 := hceiling (x5' - .5 pen_thick) + .5 pen_thick;
772                 y6 := vfloor (y6' - .5 pen_thick) + .5 pen_thick;
773
774                 crz_in = (bot z6){right}
775                          .. (z6 - nw_dist){ne}
776                          -- (z3 - up_dist)
777                          -- (z4 - rt_dist)
778                          -- (z5 + nw_dist){-ne}
779                          .. {down}(lft z5);
780                 crz_in := crz_in shifted (0, feta_shift)
781                           -- reverse crz_in yscaled -1 shifted (0, -feta_eps);
782                 unfill crz_in
783                        -- reverse crz_in xscaled -1 shifted (-feta_eps, 0)
784                        -- cycle;
785         fi
786
787         % ugh
788         currentpicture := currentpicture shifted (hround (w / 2), 0);
789
790         charwx := charwd;
791         charwy := y1 + feta_shift;
792
793         z12 = (charwx * hppp, y1 * vppp);
794
795         labels (12);
796 enddef;
797
798
799 fet_beginchar ("Whole Crossed notehead", "s0cross");
800         save wid, hei;
801
802         wid# := black_notehead_width# + 4 stafflinethickness#;
803         hei# := noteheight# + stafflinethickness#;
804
805         set_char_box (0, wid#, hei# / 2, hei# / 2);
806
807         draw_cross (3.75);
808
809         remember_pic := currentpicture;
810
811         draw_staff (-2, 2, 0);
812 fet_endchar;
813
814
815 if test > 0:
816         fet_beginchar ("Whole Crossed notehead", "s0cross");
817                 save wid, hei;
818
819                 wid# := black_notehead_width# + 4 stafflinethickness#;
820                 hei# := noteheight# + stafflinethickness#;
821
822                 set_char_box (0, wid#, hei# / 2, hei# / 2);
823
824                 currentpicture := remember_pic;
825
826                 draw_staff (-2, 2, 0.5);
827         fet_endchar;
828 fi;
829
830
831 fet_beginchar ("Half Crossed notehead", "s1cross");
832         save wid, hei;
833
834         wid# := black_notehead_width# + 2 stafflinethickness#;
835         hei# := noteheight# + stafflinethickness# / 2;
836
837         set_char_box (0, wid#, hei# / 2, hei# / 2);
838
839         draw_cross (3.0);
840
841         remember_pic := currentpicture;
842
843         draw_staff (-2, 2, 0);
844 fet_endchar;
845
846
847 if test > 0:
848         fet_beginchar ("Half Crossed notehead", "s1cross");
849                 save wid, hei;
850
851                 wid# := black_notehead_width# + 2 stafflinethickness#;
852                 hei# := noteheight# + stafflinethickness# / 2;
853
854                 set_char_box (0, wid#, hei# / 2, hei# / 2);
855
856                 currentpicture := remember_pic;
857
858                 draw_staff (-2, 2, 0.5);
859         fet_endchar;
860 fi;
861
862
863 fet_beginchar ("Crossed notehead", "s2cross");
864         wid# := black_notehead_width#;
865         hei# := noteheight#;
866         set_char_box (0, wid#, hei# / 2, hei# / 2);
867
868         draw_cross (1.0);
869
870         remember_pic := currentpicture;
871
872         draw_staff (-2, 2, 0);
873 fet_endchar;
874
875
876 if test > 0:
877         fet_beginchar ("Crossed notehead", "s2cross");
878                 wid# := black_notehead_width#;
879                 hei# := noteheight#;
880                 set_char_box (0, wid#, hei# / 2, hei# / 2);
881
882                 currentpicture := remember_pic;
883
884                 draw_staff (-2, 2, 0.5);
885         fet_endchar;
886 fi;
887
888
889 fet_beginchar ("X-Circled notehead", "s2xcircle");
890         save wid, hei;
891         save cthick, cxd, cyd, dy;
892
893         wid# := black_notehead_width# * sqrt (sqrt2);
894         hei# := noteheight# * sqrt (sqrt2);
895
896         set_char_box (0, wid#, hei# / 2, hei# / 2);
897
898         d := d - feta_space_shift;
899
900         cthick# := (1.2 + 1/4) * stafflinethickness#;
901         define_blacker_pixels (cthick);
902
903         cxd := w - cthick;
904         cyd := h + d - cthick / 2;
905
906         dy = .5 (h - d);
907
908         pickup pencircle scaled cthick;
909
910         fill fullcircle xscaled (cxd + cthick)
911                         yscaled (cyd + cthick)
912                         shifted (w / 2, dy);
913         unfill fullcircle xscaled (cxd - cthick)
914                           yscaled (cyd - cthick)
915                           shifted (w / 2, dy);
916
917         xpos := .5 cxd / sqrt2;
918         ypos := .5 cyd / sqrt2;
919
920         pickup penrazor scaled cthick rotated (angle (xpos, ypos) + 90);
921         draw (-xpos + w / 2, -ypos + dy)
922              -- (xpos + w / 2, ypos + dy);
923
924         pickup penrazor scaled cthick rotated (angle (xpos, -ypos) + 90);
925         draw (-xpos + w / 2, ypos + dy)
926              -- (xpos + w / 2, -ypos + dy);
927
928         charwx := charwd;
929         charwy := 0;
930
931         z12 = (charwx * hppp, charwy * vppp);
932         labels (12);
933
934         remember_pic := currentpicture;
935
936         draw_staff (-2, 2, 0);
937 fet_endchar;
938
939
940 if test > 0:
941         fet_beginchar ("X-Circled notehead", "s2xcircle");
942                 save wid, hei;
943                 save cthick, cxr, cyr;
944
945                 wid# := black_notehead_width# * sqrt (sqrt2);
946                 hei# := noteheight# * sqrt (sqrt2);
947
948                 set_char_box (0, wid#, hei# / 2, hei# / 2);
949
950                 currentpicture := remember_pic;
951
952                 draw_staff (-2, 2, 0.5);
953         fet_endchar;
954 fi;
955
956
957 %%%%%%%%
958 %
959 % SOLFA SHAPED NOTES
960 %
961 %
962 % Note: For whole and half notes, the `fill' curve (p_out) is offset from
963 %       the points that specify the outer geometry, because we need to add
964 %       the rounding.  In contrast, the inner curve is not offset, because
965 %       there is no rounding.
966 %
967 %       This means that to get a line of thick_factor * pen_thickness,
968 %       we need to offset the inner curve by
969 %
970 %         (thick_factor - 0.5) * pen_thickness
971 %
972 %       or by
973 %
974 %         (2 * thick_factor - 1) * half_pen_thickness
975 %
976 save solfa_pen_thick;
977 solfa_pen_thick# = 1.3 stafflinethickness#;
978 define_blacker_pixels (solfa_pen_thick);
979
980 save solfa_pen_radius;
981 solfa_pen_radius = 0.5 solfa_pen_thick;
982
983 save solfa_base_notewidth;
984 solfa_base_notewidth# := black_notehead_width#;
985
986 solfa_whole_width := 1.0;
987 solfa_half_width := 1.0;
988 solfa_quarter_width := 1.0;
989
990
991 %%% Do head
992 %
993 % Triangle with base parallel to staff lines.
994 %
995
996 def draw_do_head (expr width_factor, dir, thickness_factor) =
997         save p_in, p_out;
998         save left_dist, right_dist, bottom_dist;
999         path p_in, p_out;
1000         pair left_dist, right_dist, bottom_dist;
1001
1002         set_char_box (0, width_factor * solfa_base_notewidth#,
1003                       0.5 solfa_noteheight#, 0.5 solfa_noteheight#);
1004
1005         bottom_thick_factor := 2 * thickness_factor - 1;
1006         % no different thickness for left side if we want uniform thickness
1007         if thickness_factor = 1:
1008                 left_thick_factor := 1;
1009         else:
1010                 left_thick_factor := 0.7 * bottom_thick_factor;
1011         fi
1012
1013         save pen_radius;
1014         pen_radius := min (solfa_pen_radius,
1015                            (h + d) / (3 * (1 + bottom_thick_factor)));
1016
1017         pickup pencircle scaled (2 * pen_radius);
1018
1019         bot y1 = -d;
1020         y1 = y2;
1021         lft x1 = 0;
1022         rt x2 = w;
1023         top y3 = h;
1024         x3 = .5 [x1, x2];
1025
1026         left_dist = (unitvector (z3 - z1) rotated 90) * pen_radius;
1027         right_dist = (unitvector (z2 - z3) rotated 90) * pen_radius;
1028         bottom_dist = (0,1) * pen_radius;
1029
1030         save pa, pb, pc;
1031         path pa, pb, pc;
1032         save point_a, point_b, point_c;
1033         pair point_a, point_b, point_c;
1034
1035         pa := (z1 - left_thick_factor * left_dist)
1036               -- (z3 - left_thick_factor * left_dist);
1037         pb := (z1 + bottom_thick_factor * bottom_dist)
1038               -- (z2 + bottom_thick_factor * bottom_dist);
1039         pc := (z2 - right_dist)
1040               -- (z3 - right_dist);
1041
1042         point_a := pa intersectionpoint pb;
1043         point_b := pb intersectionpoint pc;
1044         point_c := pc intersectionpoint pa;
1045
1046         p_in := point_a
1047                 -- point_b
1048                 -- point_c
1049                 -- cycle;
1050
1051         p_out := bot z1
1052                  -- bot z2{right}
1053                  .. rt z2{up}
1054                  .. (z2 + right_dist){z3 - z2}
1055                  -- (z3 + right_dist){z3 - z2}
1056                  .. top z3{left}
1057                  .. (z3 + left_dist){z1 - z3}
1058                  -- (z1 + left_dist){z1 - z3}
1059                  .. lft z1{down}
1060                  .. {right}cycle;
1061
1062         labels (1, 2, 3);
1063
1064         charwx := charwd;
1065         charwy := -chardp + 0.5 stafflinethickness#;
1066         if dir = -1:
1067                 charwy := -charwy;
1068         fi;
1069 enddef;
1070
1071 save do_weight;
1072 do_weight := 2;
1073
1074
1075 fet_beginchar ("Whole dohead", "s0do");
1076         draw_do_head (solfa_whole_width, 1, do_weight);
1077         fill p_out;
1078         unfill p_in;
1079 fet_endchar;
1080
1081
1082 fet_beginchar ("Half dohead", "d1do");
1083         draw_do_head (solfa_half_width, -1, do_weight);
1084         fill p_out;
1085         unfill p_in;
1086 fet_endchar;
1087
1088
1089 fet_beginchar ("Half dohead", "u1do");
1090         draw_do_head (solfa_half_width, 1, do_weight);
1091         fill p_out;
1092         unfill p_in;
1093 fet_endchar;
1094
1095
1096 fet_beginchar ("Quarter dohead", "d2do");
1097         draw_do_head (solfa_quarter_width, -1, do_weight);
1098         fill p_out;
1099 fet_endchar;
1100
1101
1102 fet_beginchar ("Quarter dohead", "u2do");
1103         draw_do_head (solfa_quarter_width, 1, do_weight);
1104         fill p_out;
1105 fet_endchar;
1106
1107
1108 fet_beginchar ("Whole thin dohead", "s0doThin");
1109         draw_do_head (solfa_whole_width, 1, 1);
1110         fill p_out;
1111         unfill p_in;
1112 fet_endchar;
1113
1114
1115 fet_beginchar ("Half thin dohead", "d1doThin");
1116         draw_do_head (solfa_half_width, -1, 1);
1117         fill p_out;
1118         unfill p_in;
1119 fet_endchar;
1120
1121
1122 fet_beginchar ("Half thin dohead", "u1doThin");
1123         draw_do_head (solfa_half_width, 1, 1);
1124         fill p_out;
1125         unfill p_in;
1126 fet_endchar;
1127
1128
1129 fet_beginchar ("Quarter thin dohead", "d2doThin");
1130         draw_do_head (solfa_quarter_width, -1, 1);
1131         fill p_out;
1132 fet_endchar;
1133
1134
1135 fet_beginchar ("Quarter thin dohead", "u2doThin");
1136         draw_do_head (solfa_quarter_width, 1, 1);
1137         fill p_out;
1138 fet_endchar;
1139
1140
1141 %
1142 % re - flat top, curved bottom:
1143 %
1144 %   (0,h/2) {dir -90}
1145 %   .. (w/2,-h/2)
1146 %   .. {dir 90} (w,h/2)
1147 %   -- cycle;
1148 %
1149 % (broader along the base and with more vertical sides for half and
1150 % whole notes)
1151 %
1152 % Note: According to some shape-note singers, there should be no size
1153 %       differences for half and whole notes, contrary to the comment above.
1154 %       Consequently, we have made them all the same width.
1155 %
1156 % stem attachment: h/2
1157 %
1158 def draw_re_head (expr width_factor, dir, thickness_factor) =
1159         save p_in, p_out;
1160         path p_in, p_out;
1161
1162         set_char_box (0, width_factor * solfa_base_notewidth#,
1163                       0.5 solfa_noteheight#, 0.5 solfa_noteheight#);
1164
1165         save offset;
1166         offset = (2 * thickness_factor - 1);
1167
1168         save curve_start;
1169         curve_start = 0.7;
1170
1171         save pen_radius;
1172
1173         pen_radius := min (solfa_pen_radius,
1174                            (h + d) * (1-curve_start) / (1+ offset));
1175
1176         pickup pencircle scaled (2 * pen_radius);
1177
1178         lft x1 = 0;
1179         top y1 = h;
1180         x2 = x1;
1181         y2 = curve_start [y3, y1];
1182         bot y3 = -d;
1183         x3 = .5 [x2, x4];
1184         rt x4 = w;
1185         y4 = y2;
1186         y5 = y1;
1187         x5 = x4;
1188
1189         labels (range 1 thru 5);
1190
1191         p_in := (z1 + pen_radius * (1, -1 * offset))
1192                 -- rt z2{down}
1193                 .. ((top z3) + (0, offset * pen_radius))
1194                 .. lft z4{up}
1195                 -- (z5 + pen_radius * (-1, -1 * offset))
1196                 -- cycle;
1197
1198         p_out := lft z1
1199                  -- lft z2{down}
1200                  .. bot z3
1201                  .. rt z4{up}
1202                  -- rt z5{up}
1203                  .. top z5{left}
1204                  -- top z1{left}
1205                  .. {down}cycle;
1206
1207         charwx := charwd;
1208         charwy := curve_start [-chardp, charht];
1209
1210         if dir = -1:
1211                 charwy := -charwy;
1212         fi;
1213 enddef;
1214
1215
1216 save re_weight;
1217 re_weight := 2;
1218
1219 fet_beginchar ("Whole rehead", "s0re");
1220         draw_re_head (solfa_whole_width, 1, re_weight);
1221         fill p_out;
1222         unfill p_in;
1223 fet_endchar;
1224
1225
1226 fet_beginchar ("Half up rehead", "u1re");
1227         draw_re_head (solfa_half_width, 1, re_weight);
1228         fill p_out;
1229         unfill p_in;
1230 fet_endchar;
1231
1232
1233 fet_beginchar ("Half down rehead", "d1re");
1234         draw_re_head (solfa_half_width, -1, re_weight);
1235         fill p_out;
1236         unfill p_in;
1237 fet_endchar;
1238
1239
1240 fet_beginchar ("Quarter up rehead", "u2re");
1241         draw_re_head (solfa_quarter_width, 1, re_weight);
1242         fill p_out;
1243 fet_endchar;
1244
1245
1246 fet_beginchar ("Quarter down rehead", "d2re");
1247         draw_re_head (solfa_quarter_width, -1, re_weight);
1248         fill p_out;
1249 fet_endchar;
1250
1251
1252 fet_beginchar ("Whole thin rehead", "s0reThin");
1253         draw_re_head (solfa_whole_width, 1, 1);
1254         fill p_out;
1255         unfill p_in;
1256 fet_endchar;
1257
1258
1259 fet_beginchar ("Half up thin rehead", "u1reThin");
1260         draw_re_head (solfa_half_width, 1, 1);
1261         fill p_out;
1262         unfill p_in;
1263 fet_endchar;
1264
1265
1266 fet_beginchar ("Half down thin rehead", "d1reThin");
1267         draw_re_head (solfa_half_width, -1, 1);
1268         fill p_out;
1269         unfill p_in;
1270 fet_endchar;
1271
1272
1273 fet_beginchar ("Quarter thin rehead", "u2reThin");
1274         draw_re_head (solfa_quarter_width, 1, 1);
1275         fill p_out;
1276 fet_endchar;
1277
1278
1279 fet_beginchar ("Quarter thin rehead", "d2reThin");
1280         draw_re_head (solfa_quarter_width, -1, 1);
1281         fill p_out;
1282 fet_endchar;
1283
1284
1285 %%%% mi head -- diamond shape
1286 %
1287 % two versions, depending on whether the `strong' lines are on the nw & se
1288 % or the ne & sw
1289 %
1290 def draw_mi_head (expr width_factor, thickness_factor, mirror) =
1291         save path_out, path_in;
1292         save ne_dist, se_dist, ne, se;
1293         save path_a, path_b, path_c, path_d;
1294         path path_out, path_in;
1295         pair ne_dist, se_dist, ne, se;
1296         path path_a, path_b, path_c, path_d;
1297         save inner_path;
1298         path inner_path;
1299
1300         set_char_box (0, width_factor * solfa_base_notewidth#,
1301                       0.5 solfa_noteheight#, 0.5 solfa_noteheight#);
1302
1303         save offset;
1304         offset := 2 * thickness_factor - 1;
1305
1306         save note_diagonal;
1307
1308         note_diagonal := w / 2 ++ (h + d) / 2;
1309
1310         save pen_radius;
1311
1312         pen_radius := min (solfa_pen_radius,
1313                            .3 * note_diagonal / (1 + offset));
1314
1315         pickup pencircle scaled (2 * pen_radius);
1316
1317         lft x1 = 0;
1318         y1 = 0;
1319         bot y2 = -d;
1320         x2 = .5 [x1, x3];
1321         rt x3 = w;
1322         x4 = x2;
1323         y3 = y1;
1324         top y4 = h;
1325
1326         % inner sides are parallel to outer sides
1327         z6 - z5 = whatever * (z2 - z1);
1328         z8 - z7 = whatever * (z4 - z3);
1329         z8 - z5 = whatever * (z4 - z1);
1330         z7 - z6 = whatever * (z3 - z2);
1331
1332         ne = unitvector (z4 - z1);
1333         se = unitvector (z2 - z1);
1334
1335         ne_dist = (ne rotated 90) * pen_radius;
1336         se_dist = (se rotated 90) * pen_radius;
1337
1338         path_a := (z1 + se_dist)
1339                   -- (z2 + se_dist);
1340         path_b := (z2 + (ne_dist * offset))
1341                   -- (z3 + (ne_dist * offset));
1342         path_c := (z3 - se_dist)
1343                   -- (z4 - se_dist);
1344         path_d := (z4 - (ne_dist * offset))
1345                   -- (z1 - (ne_dist * offset));
1346
1347         z5 = path_a intersectionpoint path_d;
1348         z7 = path_b intersectionpoint path_c;
1349
1350         labels (range 1 thru 8);
1351
1352         inner_path := z5
1353                       -- z6
1354                       -- z7
1355                       -- z8
1356                       -- cycle;
1357
1358         if mirror:
1359                 path_in := inner_path;
1360         else:
1361                 path_in := inner_path reflectedabout (z2, z4);
1362         fi
1363
1364         path_out := lft z1 {down}
1365                     .. (z1 - se_dist){se}
1366                     -- (z2 - se_dist){se}
1367                     .. bot z2 {right}
1368                     .. (z2 - ne_dist){ne}
1369                     -- (z3 - ne_dist){ne}
1370                     .. rt z3 {up}
1371                     .. (z3 + se_dist){-se}
1372                     -- (z4 + se_dist){-se}
1373                     .. top z4 {left}
1374                     .. (z4 + ne_dist){-ne}
1375                     -- (z1 + ne_dist){-ne}
1376                     .. cycle;
1377 enddef;
1378
1379
1380 save mi_weight, mi_width;
1381 mi_weight := 2;
1382 mi_width := 1.2;
1383
1384 fet_beginchar ("Whole mihead", "s0mi");
1385         draw_mi_head (mi_width * solfa_whole_width, mi_weight, false);
1386         fill path_out;
1387         unfill path_in;
1388 fet_endchar;
1389
1390
1391 fet_beginchar ("Half mihead", "s1mi");
1392         draw_mi_head (mi_width * solfa_quarter_width, mi_weight, false);
1393         fill path_out;
1394         unfill path_in;
1395 fet_endchar;
1396
1397
1398 fet_beginchar ("Quarter mihead", "s2mi");
1399         draw_mi_head (mi_width * solfa_quarter_width, mi_weight, false);
1400         fill path_out;
1401 fet_endchar;
1402
1403
1404 fet_beginchar ("Whole mirror mihead", "s0miMirror");
1405         draw_mi_head (mi_width * solfa_whole_width, mi_weight, true);
1406         fill path_out;
1407         unfill path_in;
1408 fet_endchar;
1409
1410
1411 fet_beginchar ("Half  mirror mihead", "s1miMirror");
1412         draw_mi_head (mi_width * solfa_quarter_width, mi_weight, true);
1413         fill path_out;
1414         unfill path_in;
1415 fet_endchar;
1416
1417
1418 fet_beginchar ("Quarter mirror mihead", "s2miMirror");
1419         draw_mi_head (mi_width * solfa_quarter_width, mi_weight, true);
1420         fill path_out;
1421 fet_endchar;
1422
1423
1424 fet_beginchar ("Whole thin mihead", "s0miThin");
1425         draw_mi_head (mi_width * solfa_whole_width, 1, false);
1426         fill path_out;
1427         unfill path_in;
1428 fet_endchar;
1429
1430
1431 fet_beginchar ("Half thin mihead", "s1miThin");
1432         draw_mi_head (mi_width * solfa_quarter_width, 1, false);
1433         fill path_out;
1434         unfill path_in;
1435 fet_endchar;
1436
1437
1438 fet_beginchar ("Quarter thin mihead", "s2miThin");
1439         draw_mi_head (mi_width * solfa_quarter_width, 1, false);
1440         fill path_out;
1441 fet_endchar;
1442
1443
1444 %%%% fa head
1445 %
1446 % Right triangle, hypotenuse from nw to se corner.  Stem attaches on
1447 % vertical side in direction of horizontal side.
1448 %
1449 def draw_fa_head (expr width_factor, thickness_factor) =
1450         set_char_box (0, width_factor * solfa_base_notewidth#,
1451                       0.5 solfa_noteheight#, 0.5 solfa_noteheight#);
1452
1453         save p_down_in, p_down_out, p_up_in, p_up_out, nw_dist, nw;
1454         path p_down_in, p_down_out, p_up_in, p_up_out;
1455         save path_a, path_b, path_c;
1456         path path_a, path_b, path_c;
1457         pair nw_dist, nw;
1458
1459         save offset;
1460         offset := 2 * thickness_factor - 1;
1461
1462         save pen_radius;
1463         pen_radius := min (solfa_pen_radius,
1464                            .33 * (h + d) / (1 + offset));
1465
1466         pickup pencircle scaled (2 * pen_radius);
1467
1468         lft x1 = 0;
1469         top y1 = h;
1470
1471         rt x2 = w;
1472         y2 = y1;
1473         bot y3 = -d;
1474         x3 = x2;
1475
1476         y4 = y3;
1477         x4 = x1;
1478
1479         labels (1, 2, 3, 4);
1480
1481         nw = unitvector (z1 - z3);
1482         nw_dist = (nw rotated 90) * pen_radius;
1483
1484         path_a := (z1 - (0,1) * offset * pen_radius)
1485                   -- (z2 - (0,1) * offset * pen_radius);
1486         path_b := (z2 - (1,0) * pen_radius)
1487                   -- (z3 - (1,0) * pen_radius);
1488         path_c := (z3 - nw_dist)
1489                   -- (z1 - nw_dist);
1490
1491         p_up_in := (path_a intersectionpoint path_b)
1492                    -- (path_b intersectionpoint path_c)
1493                    -- (path_c intersectionpoint path_a)
1494                    -- cycle;
1495
1496         p_up_out := lft z1{down}
1497                     .. (z1 + nw_dist){-nw}
1498                     -- (z3 + nw_dist){-nw}
1499                     .. bot z3{right}
1500                     .. rt z3{up}
1501                     -- rt z2{up}
1502                     .. top z2{left}
1503                     -- top z1{left}
1504                     .. cycle;
1505
1506         p_down_in := p_up_in rotated 180 shifted (w, 0);
1507         p_down_out := p_up_out rotated 180 shifted (w, 0);
1508
1509         charwy := 0.0;
1510         charwx := charwd;
1511 enddef;
1512
1513 save fa_weight;
1514 fa_weight := 1.75;
1515
1516 fet_beginchar ("Whole fa up head", "u0fa");
1517         draw_fa_head (solfa_whole_width, fa_weight);
1518         fill p_up_out;
1519         unfill p_up_in;
1520 fet_endchar;
1521
1522
1523 fet_beginchar ("Whole fa down head", "d0fa");
1524         draw_fa_head (solfa_whole_width, fa_weight);
1525         fill p_down_out;
1526         unfill p_down_in;
1527 fet_endchar;
1528
1529
1530 fet_beginchar ("half fa up head", "u1fa");
1531         draw_fa_head (solfa_half_width, fa_weight);
1532         fill p_up_out;
1533         unfill p_up_in;
1534 fet_endchar;
1535
1536
1537 fet_beginchar ("Half fa down head", "d1fa");
1538         draw_fa_head (solfa_half_width, fa_weight);
1539         fill p_down_out;
1540         unfill p_down_in;
1541 fet_endchar;
1542
1543
1544 fet_beginchar ("Quarter fa up head", "u2fa");
1545         draw_fa_head (solfa_quarter_width, fa_weight);
1546         fill p_up_out;
1547 fet_endchar;
1548
1549
1550 fet_beginchar ("Quarter fa down head", "d2fa");
1551         draw_fa_head (solfa_quarter_width, fa_weight);
1552         fill p_down_out;
1553 fet_endchar;
1554
1555
1556 fet_beginchar ("Whole thin fa up head", "u0faThin");
1557         draw_fa_head (solfa_whole_width, 1);
1558         fill p_up_out;
1559         unfill p_up_in;
1560 fet_endchar;
1561
1562
1563 fet_beginchar ("Whole thin fa down head", "d0faThin");
1564         draw_fa_head (solfa_whole_width, 1);
1565         fill p_down_out;
1566         unfill p_down_in;
1567 fet_endchar;
1568
1569
1570 fet_beginchar ("half thin fa up head", "u1faThin");
1571         draw_fa_head (solfa_half_width, 1);
1572         fill p_up_out;
1573         unfill p_up_in;
1574 fet_endchar;
1575
1576
1577 fet_beginchar ("Half thin fa down head", "d1faThin");
1578         draw_fa_head (solfa_half_width, 1);
1579         fill p_down_out;
1580         unfill p_down_in;
1581 fet_endchar;
1582
1583
1584 fet_beginchar ("Quarter thin fa up head", "u2faThin");
1585         draw_fa_head (solfa_quarter_width, 1);
1586         fill p_up_out;
1587 fet_endchar;
1588
1589
1590 fet_beginchar ("Quarter thin fa down head", "d2faThin");
1591         draw_fa_head (solfa_quarter_width, 1);
1592         fill p_down_out;
1593 fet_endchar;
1594
1595
1596
1597 %%%% sol head
1598 %
1599 % Note: sol head is the same shape as a standard music head, and doesn't
1600 %       vary from style to style.  However, width is constant with duration,
1601 %       so we can't just use the standard note font.
1602 %
1603 def draw_sol_head (expr filled) =
1604         draw_outside_ellipse (1.53 - puff_up_factor / 3.0, 34, 0.66, 0.17);
1605         if not filled:
1606           undraw_inside_ellipse (3.25, 33, 0.81, 2.5 stafflinethickness#);
1607         fi
1608         draw_staff (-2, 2, 0);
1609 enddef;
1610
1611 fet_beginchar ("Whole solhead", "s0sol");
1612         draw_sol_head ( false);
1613 fet_endchar;
1614
1615
1616 fet_beginchar ("Half solhead", "s1sol");
1617         draw_sol_head ( false);
1618 fet_endchar;
1619
1620
1621 fet_beginchar ("Quarter solhead", "s2sol");
1622         draw_sol_head ( true);
1623 fet_endchar;
1624
1625
1626 %%%% la head
1627 %
1628 %   Rectangle head
1629 %
1630 def draw_la_head (expr width_factor, thickness_factor) =
1631         set_char_box (0, width_factor * solfa_base_notewidth#,
1632                       0.5 solfa_noteheight#, 0.5 solfa_noteheight#);
1633         save p_in, p_out;
1634         path p_in, p_out;
1635
1636         save offset;
1637         offset := 2 * thickness_factor - 1;
1638
1639         save pen_radius;
1640         pen_radius := min (solfa_pen_radius,
1641                            .35 * (h + d) / (1 + offset));
1642
1643         pickup pencircle scaled (2 * pen_radius);
1644
1645         lft x1 = 0;
1646         top y1 = h;
1647
1648         rt x2 = w;
1649         y2 = y1;
1650         bot y3 = -d;
1651         x3 = x2;
1652
1653         y4 = y3;
1654         x4 = x1;
1655
1656         labels (range 1 thru 4);
1657
1658         p_in := (z1 + pen_radius * (1, -offset))
1659                 -- (z2 + pen_radius * (-1, -offset))
1660                 -- (z3 + pen_radius * (-1, offset))
1661                 -- (z4 + pen_radius * (1, offset))
1662                 -- cycle;
1663
1664         p_out := top z1
1665                  -- top z2{right}
1666                  .. rt z2{down}
1667                  -- rt z3{down}
1668                  .. bot z3{left}
1669                  -- bot z4{left}
1670                  .. lft z4{up}
1671                  -- lft z1{up}
1672                  .. cycle;
1673 enddef;
1674
1675
1676 save la_weight;
1677 la_weight := 2;
1678
1679 fet_beginchar ("Whole lahead", "s0la");
1680         draw_la_head (solfa_whole_width, la_weight);
1681         fill p_out;
1682         unfill p_in;
1683 fet_endchar;
1684
1685
1686 fet_beginchar ("Half lahead", "s1la");
1687         draw_la_head (solfa_half_width, la_weight);
1688         fill p_out;
1689         unfill p_in;
1690 fet_endchar;
1691
1692
1693 fet_beginchar ("Quarter lahead", "s2la");
1694         draw_la_head (solfa_quarter_width, la_weight);
1695         fill p_out;
1696 fet_endchar;
1697
1698
1699 fet_beginchar ("Whole thin lahead", "s0laThin");
1700         draw_la_head (solfa_whole_width, 1);
1701         fill p_out;
1702         unfill p_in;
1703 fet_endchar;
1704
1705
1706 fet_beginchar ("Half thin lahead", "s1laThin");
1707         draw_la_head (solfa_half_width, 1);
1708         fill p_out;
1709         unfill p_in;
1710 fet_endchar;
1711
1712
1713 fet_beginchar ("Quarter lahead", "s2laThin");
1714         draw_la_head (solfa_quarter_width, 1);
1715         fill p_out;
1716 fet_endchar;
1717
1718
1719 %%%% ti head
1720 %
1721 %   `Snow-cone', V with rounded top.
1722 %
1723 def draw_ti_head (expr width_factor, dir, thickness_factor) =
1724         set_char_box (0, width_factor * solfa_base_notewidth#,
1725                       0.5 solfa_noteheight#, 0.5 solfa_noteheight#);
1726         save p_in, p_out, p_top, p_top_in;
1727         path p_in, p_out, p_top, p_top_in;
1728         save cone_height;
1729         cone_height = 0.64;
1730
1731         save offset;
1732         offset := 2 * thickness_factor - 1;
1733
1734         save pen_radius;
1735         pen_radius := min (solfa_pen_radius,
1736                            .4 * (h + d) / (1 + offset));
1737
1738         pickup pencircle scaled (2 * pen_radius);
1739
1740         x1 = .5 [x2, x4];
1741         bot y1 = -d;
1742         lft x2 = 0;
1743         y2 = cone_height [y1, y3];
1744         rt x4 = w;
1745         y4 = y2;
1746         x3 = x1;
1747         top y3 = h;
1748         x5 = x1;
1749         y5 = y1 + offset * pen_radius;
1750
1751         labels (range 1 thru 4);
1752
1753         save nw_dist, sw_dist, nw, sw;
1754         pair nw_dist, sw_dist, nw, sw;
1755
1756         nw = unitvector (z2 - z1);
1757         sw = unitvector (z1 - z4);
1758
1759         nw_dist = (nw rotated 90) * pen_radius;
1760         sw_dist = (sw rotated 90) * pen_radius;
1761
1762         p_top := (z2 + nw * pen_radius)
1763                  .. (top z3){right}
1764                  .. (z4 - sw * pen_radius);
1765
1766         p_top_in := (z2 - nw * offset * pen_radius)
1767                     .. (z3 - (0,1) * pen_radius) {right}
1768                     .. (z4 + sw * offset * pen_radius);
1769
1770         save path_a, path_b;
1771         path path_a, path_b;
1772         path_a := z2
1773                   -- z5;
1774         path_b := z5
1775                   -- z4;
1776
1777         z6 = path_a intersectionpoint p_top_in;
1778         z7 = path_b intersectionpoint p_top_in;
1779
1780         p_in := z5
1781                 -- z6
1782                 .. bot z3
1783                 .. z7
1784                 -- cycle;
1785
1786         p_out := bot z1
1787                  .. (z1 + nw_dist)
1788                  -- (z2 + nw_dist)
1789                  .. lft z2
1790                  .. (z2 + nw * pen_radius){direction 0 of p_top}
1791                  & p_top
1792                  & {direction infinity of p_top}(z4 - sw * pen_radius)
1793                  .. rt z4
1794                  .. (z4 + sw_dist)
1795                  -- (z1 + sw_dist)
1796                  .. cycle;
1797
1798         charwx := charwd;
1799         charwy := cone_height [-chardp, charht];
1800         if dir = -1:
1801                 charwy := -charwy;
1802         fi;
1803 enddef;
1804
1805
1806 save ti_weight;
1807 ti_weight := 2;
1808
1809 fet_beginchar ("Whole up tihead", "s0ti");
1810         draw_ti_head (solfa_whole_width, 1, ti_weight);
1811         fill p_out;
1812         unfill p_in;
1813 fet_endchar;
1814
1815
1816 fet_beginchar ("Half up tihead", "u1ti");
1817         draw_ti_head (solfa_half_width, 1, ti_weight);
1818         fill p_out;
1819         unfill p_in;
1820 fet_endchar;
1821
1822
1823 fet_beginchar ("Half down tihead", "d1ti");
1824         draw_ti_head (solfa_half_width, -1, ti_weight);
1825         fill p_out;
1826         unfill p_in;
1827 fet_endchar;
1828
1829
1830 fet_beginchar ("Quarter up tihead", "u2ti");
1831         draw_ti_head (solfa_quarter_width, 1, ti_weight);
1832         fill p_out;
1833 fet_endchar;
1834
1835
1836 fet_beginchar ("Quarter down tihead", "d2ti");
1837         draw_ti_head (solfa_quarter_width, -1, ti_weight);
1838         fill p_out;
1839 fet_endchar;
1840
1841
1842 fet_beginchar ("Whole thin up tihead", "s0tiThin");
1843         draw_ti_head (solfa_whole_width, 1, 1);
1844         fill p_out;
1845         unfill p_in;
1846 fet_endchar;
1847
1848
1849 fet_beginchar ("Half thin up tihead", "u1tiThin");
1850         draw_ti_head (solfa_half_width, 1, 1);
1851         fill p_out;
1852         unfill p_in;
1853 fet_endchar;
1854
1855
1856 fet_beginchar ("Half thin down tihead", "d1tiThin");
1857         draw_ti_head (solfa_half_width, -1, 1);
1858         fill p_out;
1859         unfill p_in;
1860 fet_endchar;
1861
1862
1863 fet_beginchar ("Quarter thin up tihead", "u2tiThin");
1864         draw_ti_head (solfa_quarter_width, 1, 1);
1865         fill p_out;
1866 fet_endchar;
1867
1868
1869 fet_beginchar ("Quarter thin down tihead", "d2tiThin");
1870         draw_ti_head (solfa_quarter_width, -1, 1);
1871         fill p_out;
1872 fet_endchar;
1873
1874
1875 %%%%%%   Funk shape note heads
1876 %
1877 %  Funk heads are narrower than Aiken and Sacred Harp, so we need a new
1878 %  width.
1879 %
1880 funk_notehead_width := 0.75;
1881
1882
1883 %%%%%%   Funk do head
1884 %          Parabolic on one side, vertical line on other
1885 %          Has up and down shapes for *all* notes
1886 %
1887 def draw_Funk_do_head (expr width_factor, thickness_factor) =
1888         set_char_box (0, width_factor * solfa_base_notewidth#,
1889                       0.5 solfa_noteheight#, 0.5 solfa_noteheight#);
1890
1891         save offset;
1892         offset := 2 * thickness_factor - 1;
1893
1894         save pen_radius;
1895         pen_radius := min (solfa_pen_radius,
1896                            .3 * (h + d) / (1 + offset));
1897
1898         pickup pencircle scaled (2 * pen_radius);
1899
1900         rt x1 = w;
1901         bot y1 = -d;
1902
1903         lft x2 = 0;
1904         y2 = 0.5 [y1, y3];
1905
1906         x3 = x1;
1907         top y3 = h;
1908
1909         x4 = x1 - pen_radius;
1910         y4 = y1 + offset * pen_radius;
1911
1912         y5 = y2;
1913         x5 = x2 + pen_radius;
1914
1915         x6 = x4;
1916         y6 = y3 - offset * pen_radius;
1917
1918         save p_up_in, p_up_out, p_down_in, p_down_out;
1919         path p_up_in, p_up_out, p_down_in, p_down_out;
1920
1921         p_down_in := z4{left}
1922                      ... z5{up}
1923                      ... z6{right}
1924                      -- cycle;
1925
1926         p_down_out := bot z1{left}
1927                       .. lft z2{up}
1928                       .. top z3{right}
1929                       .. rt z3{down}
1930                       -- rt z1{down}
1931                       .. cycle;
1932
1933         p_up_in := p_down_in rotated 180 shifted (w,0);
1934         p_up_out := p_down_out rotated 180 shifted (w,0);
1935
1936 enddef;
1937
1938
1939 save funk_do_weight;
1940 funk_do_weight := 1.7;
1941
1942 fet_beginchar ("Whole up Funk dohead", "u0doFunk");
1943         draw_Funk_do_head (funk_notehead_width, funk_do_weight);
1944         fill p_up_out;
1945         unfill p_up_in;
1946 fet_endchar;
1947
1948
1949 fet_beginchar ("Whole down Funk dohead", "d0doFunk");
1950         draw_Funk_do_head (funk_notehead_width, funk_do_weight);
1951         fill p_down_out;
1952         unfill p_down_in;
1953 fet_endchar;
1954
1955
1956 fet_beginchar ("Half up Funk dohead", "u1doFunk");
1957         draw_Funk_do_head (funk_notehead_width, funk_do_weight);
1958         fill p_up_out;
1959         unfill p_up_in;
1960 fet_endchar;
1961
1962
1963 fet_beginchar ("Half down Funk dohead", "d1doFunk");
1964         draw_Funk_do_head (funk_notehead_width, funk_do_weight);
1965         fill p_down_out;
1966         unfill p_down_in;
1967 fet_endchar;
1968
1969
1970 fet_beginchar ("Quarter up Funk dohead", "u2doFunk");
1971         draw_Funk_do_head (funk_notehead_width, funk_do_weight);
1972         fill p_up_out;
1973 fet_endchar;
1974
1975
1976 fet_beginchar ("Quarter down Funk dohead", "d2doFunk");
1977         draw_Funk_do_head (funk_notehead_width, funk_do_weight);
1978         fill p_down_out;
1979 fet_endchar;
1980
1981
1982 %%%%%%  Funk re head
1983 %       Arrowhead shape.
1984 %       Has up and down shapes for *all* notes
1985 %
1986 def draw_Funk_re_head (expr width_factor, thickness_factor) =
1987         set_char_box (0, width_factor * solfa_base_notewidth#,
1988                       0.5 solfa_noteheight#, 0.5 solfa_noteheight#);
1989
1990         save offset;
1991         offset := 2 * thickness_factor - 1;
1992
1993         save pen_radius;
1994         pen_radius := min (solfa_pen_radius,
1995                            .3 * (h + d) / (1 + offset));
1996
1997         pickup pencircle scaled (2 * pen_radius);
1998
1999         save curve_in;
2000         curve_in := 0.9;
2001
2002         lft x1 = 0;
2003         y1 := 0.5 [y2, y4];
2004
2005         rt x2 = w;
2006         top y2 = h;
2007
2008         x3 := curve_in [x1, x2];
2009         y3 := y1;
2010
2011         x4 = x2;
2012         bot y4 = -d;
2013
2014         z6 = lft z3;
2015
2016         save ne, se, ne_perp, se_perp;
2017         pair ne, se, ne_perp, se_perp;
2018
2019         ne := unitvector (z2 - z1);
2020         se := unitvector (z4 - z1);
2021         ne_perp := ne rotated 90;
2022         se_perp := se rotated 90;
2023
2024         save path_a, path_b, path_c, path_d;
2025         path path_a, path_b, path_c, path_d;
2026         save arrow_a_perp, arrow_b_perp;
2027         pair arrow_a_perp, arrow_b_perp;
2028
2029
2030         path_d := z2 .. z3{down} .. z4;
2031         arrow_a_perp = unitvector (direction 0 of path_d rotated 90)
2032                        * pen_radius;
2033         arrow_b_perp = unitvector (direction 2 of path_d rotated 90)
2034                        * pen_radius;
2035
2036         path_b := (z1 + se_perp * pen_radius)
2037                   -- z4 + se_perp * offset * pen_radius;
2038         path_a := (z1 - ne_perp * pen_radius)
2039                   -- z2 - ne_perp * offset * pen_radius;
2040         path_c := z2 - arrow_a_perp
2041                   .. z6{down}
2042                   .. z4 - arrow_b_perp;
2043
2044         z5 = path_a intersectionpoint path_b;
2045         z7 = path_a intersectionpoint path_c;
2046         z8 = path_b intersectionpoint path_c;
2047
2048         save p_up_in, p_down_in, p_up_out, p_down_out;
2049         path p_up_in, p_down_in, p_up_out, p_down_out;
2050
2051         p_down_in := z5
2052                      -- z7
2053                      .. z6{down}
2054                      .. z8
2055                      -- cycle;
2056
2057         p_down_out := lft z1{up}
2058                       .. (z1 + ne_perp * pen_radius){ne}
2059                       -- (z2 + ne_perp * pen_radius){ne}
2060                       .. top z2 {right}
2061                       .. rt z2{down}
2062                       .. (z2 + arrow_a_perp)
2063                       .. rt z3{down}
2064                       .. (z4 + arrow_b_perp)
2065                       .. rt z4{down}
2066                       .. bot z4 {left}
2067                       .. z4 - se_perp * pen_radius
2068                       -- z1 - se_perp * pen_radius
2069                       .. cycle;
2070
2071         p_up_in := p_down_in rotated 180 shifted (w, 0);
2072         p_up_out := p_down_out rotated 180 shifted (w, 0);
2073
2074 enddef;
2075
2076
2077 save funk_re_weight;
2078 funk_re_weight = 1.7;
2079
2080 fet_beginchar ("Whole up Funk rehead", "u0reFunk");
2081         draw_Funk_re_head (funk_notehead_width, funk_re_weight);
2082         fill p_up_out;
2083         unfill p_up_in;
2084 fet_endchar;
2085
2086
2087 fet_beginchar ("Whole down Funk rehead", "d0reFunk");
2088         draw_Funk_re_head (funk_notehead_width, funk_re_weight);
2089         fill p_down_out;
2090         unfill p_down_in;
2091 fet_endchar;
2092
2093
2094 fet_beginchar ("Half up Funk rehead", "u1reFunk");
2095         draw_Funk_re_head (funk_notehead_width, funk_re_weight);
2096         fill p_up_out;
2097         unfill p_up_in;
2098 fet_endchar;
2099
2100
2101 fet_beginchar ("Half down Funk rehead", "d1reFunk");
2102         draw_Funk_re_head (funk_notehead_width, funk_re_weight);
2103         fill p_down_out;
2104         unfill p_down_in;
2105 fet_endchar;
2106
2107
2108 fet_beginchar ("Quarter up Funk rehead", "u2reFunk");
2109         draw_Funk_re_head (funk_notehead_width, funk_re_weight);
2110         fill p_up_out;
2111 fet_endchar;
2112
2113
2114 fet_beginchar ("Quarter down Funk rehead", "d2reFunk");
2115         draw_Funk_re_head (funk_notehead_width, funk_re_weight);
2116         fill p_down_out;
2117 fet_endchar;
2118
2119
2120 %%%%%%  Funk mi head
2121 %       Diamond shape
2122 %       Has up and down shapes for all hollow notes
2123 %
2124 save funk_mi_width, funk_mi_weight;
2125 funk_mi_width := 1.2;
2126 funk_mi_weight := 1.9;
2127
2128 fet_beginchar ("Whole up Funk mihead", "u0miFunk");
2129         draw_mi_head (funk_mi_width * funk_notehead_width,
2130                       funk_mi_weight, false);
2131         fill path_out;
2132         unfill path_in;
2133 fet_endchar;
2134
2135
2136 fet_beginchar ("Whole down Funk mihead", "d0miFunk");
2137         draw_mi_head (funk_mi_width * funk_notehead_width,
2138                       funk_mi_weight, true);
2139         fill path_out;
2140         unfill path_in;
2141 fet_endchar;
2142
2143
2144 fet_beginchar ("Half up Funk mihead", "u1miFunk");
2145         draw_mi_head (funk_mi_width * funk_notehead_width,
2146                       funk_mi_weight, false);
2147         fill path_out;
2148         unfill path_in;
2149 fet_endchar;
2150
2151
2152 fet_beginchar ("Half down Funk mihead", "d1miFunk");
2153         draw_mi_head (funk_mi_width * funk_notehead_width,
2154                       funk_mi_weight, true);
2155         fill path_out;
2156         unfill path_in;
2157 fet_endchar;
2158
2159
2160 fet_beginchar ("Quarter Funk mihead", "s2miFunk");
2161         draw_mi_head (funk_mi_width * funk_notehead_width,
2162                       funk_mi_weight, false);
2163         fill path_out;
2164 fet_endchar;
2165
2166
2167 %%%%%%  Funk fa
2168 %       Triangle shape
2169 %       Does it rotate for whole notes?
2170 %       Same as other shape note systems
2171 %       Need special notes because of special width
2172 %
2173 save funk_fa_weight;
2174 funk_fa_weight := 1.9;
2175
2176 fet_beginchar ("Whole up Funk fahead", "u0faFunk");
2177         draw_fa_head (funk_notehead_width, funk_fa_weight);
2178         fill p_up_out;
2179         unfill p_up_in;
2180 fet_endchar;
2181
2182
2183 fet_beginchar ("Whole down Funk fahead", "d0faFunk");
2184         draw_fa_head (funk_notehead_width, funk_fa_weight);
2185         fill p_down_out;
2186         unfill p_down_in;
2187 fet_endchar;
2188
2189
2190 fet_beginchar ("Half up Funk fahead", "u1faFunk");
2191         draw_fa_head (funk_notehead_width, funk_fa_weight);
2192         fill p_up_out;
2193         unfill p_up_in;
2194 fet_endchar;
2195
2196
2197 fet_beginchar ("Half down Funk fahead", "d1faFunk");
2198         draw_fa_head (funk_notehead_width, funk_fa_weight);
2199         fill p_down_out;
2200         unfill p_down_in;
2201 fet_endchar;
2202
2203
2204 fet_beginchar ("Quarter up Funk fahead", "u2faFunk");
2205         draw_fa_head (funk_notehead_width, funk_fa_weight);
2206         fill p_up_out;
2207 fet_endchar;
2208
2209
2210 fet_beginchar ("Quarter down Funk fahead", "d2faFunk");
2211         draw_fa_head (funk_notehead_width, funk_fa_weight);
2212         fill p_down_out;
2213 fet_endchar;
2214
2215
2216 %%%%%%  Funk sol head is the same as the others
2217 %       Need special character because of skinnier head
2218 %
2219 def draw_Funk_sol_head (expr filled) =
2220 begingroup
2221         save noteheight;
2222         noteheight# := solfa_noteheight#;
2223         draw_outside_ellipse (1.2, 34, 0.71, 0.);
2224         if not filled:
2225           undraw_inside_ellipse (1.9, 33, 0.74, 5.5 stafflinethickness#);
2226         fi
2227         draw_staff (-2, 2, 0);
2228 endgroup
2229 enddef;
2230
2231
2232 fet_beginchar ("Whole Funk solhead", "s0solFunk");
2233         draw_Funk_sol_head ( false);
2234 fet_endchar;
2235
2236
2237 fet_beginchar ("Half Funk solhead", "s1solFunk");
2238         draw_Funk_sol_head ( false);
2239 fet_endchar;
2240
2241
2242 fet_beginchar ("Quarter Funk solhead", "s2solFunk");
2243         draw_Funk_sol_head ( true);
2244 fet_endchar;
2245
2246
2247 %%%%%%  Funk la head
2248 %       Rectangle head
2249 %       Same as for other shape notes
2250 %       Smaller width requires special characters
2251 %
2252 save funk_la_weight;
2253 funk_la_weight := 1.9;
2254
2255 fet_beginchar ("Whole Funk lahead", "s0laFunk");
2256         draw_la_head (funk_notehead_width, funk_notehead_width);
2257         fill p_out;
2258         unfill p_in;
2259 fet_endchar;
2260
2261
2262 fet_beginchar ("Half Funk lahead", "s1laFunk");
2263         draw_la_head (funk_notehead_width, funk_notehead_width);
2264         fill p_out;
2265         unfill p_in;
2266 fet_endchar;
2267
2268
2269 fet_beginchar ("Quarter Funk lahead", "s2laFunk");
2270         draw_la_head (funk_notehead_width, funk_notehead_width);
2271         fill p_out;
2272 fet_endchar;
2273
2274
2275 %%%%%%  Funk ti head
2276 %       `Sideways snow cone'.
2277 %       Rotates for all notes.
2278 %
2279 def draw_Funk_ti_head (expr width_factor, thickness_factor) =
2280         set_char_box (0, width_factor * solfa_base_notewidth#,
2281                       0.5 solfa_noteheight#, 0.5 solfa_noteheight#);
2282         save cone_width;
2283         cone_width = 0.8;
2284
2285         save offset;
2286         offset := 2 * thickness_factor - 1;
2287
2288         save pen_radius;
2289         pen_radius := min (solfa_pen_radius,
2290                            .33 * (h + d) / (1 + offset));
2291
2292         pickup pencircle scaled (2 * pen_radius);
2293
2294         lft x1 = 0;
2295         y1 = .5 [y2, y4];
2296
2297         x2 = cone_width [x1, x3];
2298         top y2 = h;
2299
2300         rt x3 = w;
2301         y3 = y1;
2302
2303         x4 = x2;
2304         bot y4 = -d;
2305
2306         save nw_dist, sw_dist, ne, se;
2307         pair nw_dist, sw_dist, ne, se;
2308
2309         ne = unitvector (z2 - z1);
2310         se = unitvector (z4 - z1);
2311
2312         nw_dist = (ne rotated 90) * pen_radius ;
2313         sw_dist = (se rotated -90) * pen_radius;
2314
2315         save path_a, path_b;
2316         path path_a, path_b;
2317         path_a := z1 - nw_dist
2318                   -- z2 - offset * nw_dist;
2319         path_b := z1 - sw_dist
2320                   -- z4 - offset * sw_dist;
2321
2322         save path_right, path_right_in;
2323         path path_right, path_right_in;
2324         path_right := (z2 + ne * pen_radius)
2325                       .. (rt z3){down}
2326                       .. (z4 + se * pen_radius);
2327
2328         path_right_in := (z2 - ne * pen_radius)
2329                          .. lft z3{down}
2330                          .. (z4 - se * pen_radius);
2331
2332         z5 = path_a intersectionpoint path_b;
2333         z6 = path_a intersectionpoint path_right_in;
2334         z7 = path_b intersectionpoint path_right_in;
2335
2336         save p_up_in, p_down_in, p_up_out, p_down_out;
2337         path p_up_in, p_down_in, p_up_out, p_down_out;
2338
2339         p_down_in := z5
2340                      -- z6
2341                      .. lft z3
2342                      .. z7
2343                      -- cycle;
2344
2345         p_down_out := lft z1
2346                       .. (z1 + nw_dist)
2347                       -- (z2 + nw_dist)
2348                       .. top z2
2349                       .. (z2 + ne * pen_radius){direction 0 of path_right}
2350                       & path_right
2351                       & {direction infinity of path_right}(z4 + se * pen_radius)
2352                       .. bot z4
2353                       .. (z4 + sw_dist)
2354                       -- (z1 + sw_dist)
2355                       .. cycle;
2356
2357         p_up_in := p_down_in rotated 180 shifted (w, 0);
2358         p_up_out := p_down_out rotated 180 shifted (w, 0);
2359 enddef;
2360
2361
2362 save funk_ti_weight;
2363 funk_ti_weight := 1.6;
2364
2365 fet_beginchar ("Whole up Funk tihead", "u0tiFunk");
2366         draw_Funk_ti_head (funk_notehead_width, funk_ti_weight);
2367         fill p_up_out;
2368         unfill p_up_in;
2369 fet_endchar;
2370
2371
2372 fet_beginchar ("Whole down Funk tihead", "d0tiFunk");
2373         draw_Funk_ti_head (funk_notehead_width, funk_ti_weight);
2374         fill p_down_out;
2375         unfill p_down_in;
2376 fet_endchar;
2377
2378
2379 fet_beginchar ("Half up Funk tihead", "u1tiFunk");
2380         draw_Funk_ti_head (funk_notehead_width, funk_ti_weight);
2381         fill p_up_out;
2382         unfill p_up_in;
2383 fet_endchar;
2384
2385
2386 fet_beginchar ("Half down Funk tihead", "d1tiFunk");
2387         draw_Funk_ti_head (funk_notehead_width, funk_ti_weight);
2388         fill p_down_out;
2389         unfill p_down_in;
2390 fet_endchar;
2391
2392
2393 fet_beginchar ("Quarter up Funk tihead", "u2tiFunk");
2394         draw_Funk_ti_head (funk_notehead_width, funk_ti_weight);
2395         fill p_up_out;
2396 fet_endchar;
2397
2398
2399 fet_beginchar ("Quarter down Funk tihead", "d2tiFunk");
2400         draw_Funk_ti_head (funk_notehead_width, funk_ti_weight);
2401         fill p_down_out;
2402 fet_endchar;
2403
2404
2405 %%%%%%   Walker shape note heads
2406 %
2407 % Walker heads are narrow like Funk heads, so use funk_notehead_width.
2408 %
2409
2410 %%%%%%   Walker do head
2411 %
2412 % Trapezoid, with largest side on stem side
2413 %
2414 def draw_Walker_do_head (expr width_factor, dir, thickness_factor) =
2415         set_char_box (0, width_factor * solfa_base_notewidth#,
2416                       0.5 solfa_noteheight#, 0.5 solfa_noteheight#);
2417
2418         pickup pencircle scaled solfa_pen_thick;
2419
2420         save offset;
2421         offset := 2 * thickness_factor - 1;
2422
2423         % adjust width so stem can be centered
2424         if .5w <> good.x .5w: change_width; fi
2425
2426         save scaling;
2427
2428         scaling# = charwd / w;
2429
2430         save inset;
2431         inset := 0.25;
2432
2433         x1 = inset [x4, x3];
2434         top y1 = h;
2435
2436         x2 = inset [x3, x4];
2437         y2 = y1;
2438
2439         bot y3 = -d;
2440         rt x3 = w;
2441
2442         y4 = y3;
2443         lft x4 = 0;
2444
2445         labels (range 1 thru 4);
2446
2447         save left_dir, left_perp, right_dir, right_perp;
2448         pair left_dir, left_perp, right_dir, right_perp;
2449
2450         left_dir = unitvector(z1 - z4);
2451         left_perp = (left_dir rotated 90) * solfa_pen_radius;
2452         right_dir = unitvector(z3 - z2);
2453         right_perp = (right_dir rotated 90) * solfa_pen_radius;
2454
2455         save path_a, path_b, path_c, path_d;
2456         path path_a, path_b, path_c, path_d;
2457
2458         path_a := (z4 - left_perp)
2459                   -- (z1 - left_perp);
2460         path_b := (z1 - (0, offset*solfa_pen_radius))
2461                   -- (z2 - (0, offset*solfa_pen_radius));
2462         path_c := (z2 - right_perp)
2463                   -- (z3 - right_perp);
2464         path_d := (z3 + (0, offset*solfa_pen_radius))
2465                   -- (z4 + (0, offset*solfa_pen_radius));
2466
2467         save p_in, p_out;
2468         path p_in, p_out;
2469
2470         p_in := (path_a intersectionpoint path_b)
2471                 -- (path_b intersectionpoint path_c)
2472                 -- (path_c intersectionpoint path_d)
2473                 -- (path_d intersectionpoint path_a)
2474                 -- cycle;
2475
2476         p_out := top z1{right}
2477                  -- top z2{right}
2478                  .. z2 + right_perp {right_dir}
2479                  -- z3 + right_perp {right_dir}
2480                  .. bot z3{left}
2481                  -- bot z4{left}
2482                  .. z4 + left_perp {left_dir}
2483                  .. z1 + left_perp {left_dir}
2484                  .. cycle;
2485
2486         charwx := scaling# * (w/2 + solfa_pen_radius);
2487         charwy := scaling# * y2 ;
2488
2489         if dir = 1:
2490                 p_in := p_in rotated 180 shifted (w,0);
2491                 p_out := p_out rotated 180 shifted (w,0);
2492         fi;
2493 enddef;
2494
2495
2496 save walker_do_weight;
2497 walker_do_weight := 1.5;
2498
2499 fet_beginchar ("Whole Walker dohead", "s0doWalker");
2500         draw_Walker_do_head (funk_notehead_width, 0, walker_do_weight);
2501         fill p_out;
2502         unfill p_in;
2503 fet_endchar;
2504
2505
2506 fet_beginchar ("Half up Walker dohead", "u1doWalker");
2507         draw_Walker_do_head (funk_notehead_width, 1, walker_do_weight);
2508         fill p_out;
2509         unfill p_in;
2510 fet_endchar;
2511
2512
2513 fet_beginchar ("Half down Walker dohead", "d1doWalker");
2514         draw_Walker_do_head (funk_notehead_width, 0, walker_do_weight);
2515         fill p_out;
2516         unfill p_in;
2517 fet_endchar;
2518
2519
2520 fet_beginchar ("Quarter up Walker dohead", "u2doWalker");
2521         draw_Walker_do_head (funk_notehead_width, 1, walker_do_weight);
2522         fill p_out;
2523 fet_endchar;
2524
2525
2526 fet_beginchar ("Quarter down Walker dohead", "d2doWalker");
2527         draw_Walker_do_head (funk_notehead_width, 0, walker_do_weight);
2528         fill p_out;
2529 fet_endchar;
2530
2531
2532 %%%%%%   Walker re head
2533 %          Parabolic on one side, shallow parabola on other
2534 %          Has up and down shapes for *all* notes
2535 %
2536 def draw_Walker_re_head (expr width_factor, thickness_factor) =
2537         set_char_box (0, width_factor * solfa_base_notewidth#,
2538                       0.5 solfa_noteheight#, 0.5 solfa_noteheight#);
2539
2540         save offset;
2541         offset := 2 * thickness_factor - 1;
2542
2543         save pen_radius;
2544         pen_radius := min (solfa_pen_radius,
2545                            .3 * (h + d) / (1 + offset));
2546
2547         pickup pencircle scaled (2 * pen_radius);
2548
2549         save dish_factor;
2550         dish_factor := 0.20;
2551
2552         rt x1 = w;
2553         bot y1 = -d;
2554
2555         lft x2 = 0;
2556         y2 = 0.5 [y1, y3];
2557
2558         top y3 = h;
2559         x3 = x1;
2560
2561         x4 = dish_factor [x1, x2];
2562         y4 = y2;
2563
2564         x5 = x1;
2565         y5 = y1 + offset * pen_radius;
2566
2567         y6 = y2;
2568         x6 = x2 + pen_radius;
2569
2570         x7 = x3;
2571         y7 = y3 - offset * pen_radius;
2572
2573         y8 = y4;
2574         x8 = x4 - pen_radius;
2575
2576         save path_a, path_d;
2577         path path_a, path_d;
2578
2579         save p_a_start_dir, p_a_end_dir, p_a_start_perp, p_a_end_perp;
2580         pair p_a_start_dir, p_a_end_dir, p_a_start_perp, p_a_end_perp;
2581
2582         path_a := z3 .. z4{down} .. z1;
2583
2584         p_a_start_dir := unitvector(direction 0 of path_a);
2585         p_a_end_dir := unitvector(direction infinity of path_a);
2586         p_a_start_perp := (p_a_start_dir rotated 90) * pen_radius;
2587         p_a_end_perp := (p_a_end_dir rotated 90) * pen_radius;
2588
2589         path_d := (z3 - p_a_start_perp){p_a_start_dir}
2590                   .. z4 {down}
2591                   ..(z1 - p_a_end_perp){p_a_end_dir};
2592
2593         save path_b, path_c;
2594         path path_b, path_c;
2595
2596         path_b := z5 {left} .. z6{up};
2597         path_c := z7 {left} .. z6{down};
2598
2599         z9 = path_d intersectionpoint path_b;
2600         z10 = path_d intersectionpoint path_c;
2601
2602         labels (range 1 thru 4);
2603
2604         save p_up_in, p_up_out, p_down_in, p_down_out;
2605         path p_up_in, p_up_out, p_down_in, p_down_out;
2606
2607         p_down_in := z6{up}
2608                      ... {right} z10 {p_a_start_dir}
2609                      .. z8{down}
2610                      .. {p_a_end_dir} z9 {left}
2611                      ... cycle;
2612
2613         p_down_out := lft z2{up}
2614                       .. top z3{right}
2615                       .. rt z3
2616                       .. (z3 + p_a_start_perp){p_a_start_dir}
2617                       .. rt z4{down}
2618                       .. (z1 + p_a_end_perp) {p_a_end_dir}
2619                       .. rt z1
2620                       .. bot z1 {left}
2621                       .. cycle;
2622
2623         p_up_in := p_down_in rotated 180 shifted (w,0);
2624         p_up_out := p_down_out rotated 180 shifted (w,0);
2625 enddef;
2626
2627
2628 save walker_re_weight;
2629 walker_re_weight := 1.2;
2630
2631 fet_beginchar ("Whole Walker rehead", "s0reWalker");
2632         draw_Walker_re_head (funk_notehead_width, walker_re_weight);
2633         fill p_down_out;
2634         unfill p_down_in;
2635 fet_endchar;
2636
2637
2638 fet_beginchar ("Half up Walker rehead", "u1reWalker");
2639         draw_Walker_re_head (funk_notehead_width, walker_re_weight);
2640         fill p_up_out;
2641         unfill p_up_in;
2642 fet_endchar;
2643
2644
2645 fet_beginchar ("Half down Walker rehead", "d1reWalker");
2646         draw_Walker_re_head (funk_notehead_width, walker_re_weight);
2647         fill p_down_out;
2648         unfill p_down_in;
2649 fet_endchar;
2650
2651
2652 fet_beginchar ("Quarter up Walker rehead", "u2reWalker");
2653         draw_Walker_re_head (funk_notehead_width, walker_re_weight);
2654         fill p_up_out;
2655 fet_endchar;
2656
2657
2658 fet_beginchar ("Quarter down Walker rehead", "d2reWalker");
2659         draw_Walker_re_head (funk_notehead_width, walker_re_weight);
2660         fill p_down_out;
2661 fet_endchar;
2662
2663
2664 %%%%%%  Walker mi head
2665 %       Diamond shape
2666 %       Symmetric for all hollow notes
2667 %
2668 save walker_mi_width, walker_mi_weight;
2669 walker_mi_width := 1.2;
2670 walker_mi_weight := 1.5;
2671
2672 fet_beginchar ("Whole Walker mihead", "s0miWalker");
2673         draw_mi_head (walker_mi_width * funk_notehead_width,
2674                       walker_mi_weight, true);
2675         fill path_out;
2676         unfill path_in;
2677 fet_endchar;
2678
2679
2680 fet_beginchar ("Half Walker mihead", "s1miWalker");
2681         draw_mi_head (walker_mi_width * funk_notehead_width,
2682                       walker_mi_weight, true);
2683         fill path_out;
2684         unfill path_in;
2685 fet_endchar;
2686
2687
2688 fet_beginchar ("Quarter Walker mihead", "s2miWalker");
2689         draw_mi_head (walker_mi_width * funk_notehead_width,
2690                       walker_mi_weight, true);
2691         fill path_out;
2692 fet_endchar;
2693
2694
2695 %%%%%%  Walker fa
2696 %       Triangle shape
2697 %       Does not rotate for whole notes
2698 %       Whole rotation is different from Funk, so special notes
2699
2700 %%%%%%  Funk sol head is the same as the others
2701 %       Need special character because of skinnier head
2702 %
2703 save walker_fa_weight;
2704 walker_fa_weight := 1.5;
2705
2706 fet_beginchar ("Whole Walker fahead", "s0faWalker");
2707         draw_fa_head (funk_notehead_width, walker_fa_weight);
2708         fill p_down_out;
2709         unfill p_down_in;
2710 fet_endchar;
2711
2712
2713 fet_beginchar ("Half up Walker fahead", "u1faWalker");
2714         draw_fa_head (funk_notehead_width, walker_fa_weight);
2715         fill p_up_out;
2716         unfill p_up_in;
2717 fet_endchar;
2718
2719
2720 fet_beginchar ("Half down Walker fahead", "d1faWalker");
2721         draw_fa_head (funk_notehead_width, walker_fa_weight);
2722         fill p_down_out;
2723         unfill p_down_in;
2724 fet_endchar;
2725
2726
2727 fet_beginchar ("Quarter up Walker fahead", "u2faWalker");
2728         draw_fa_head (funk_notehead_width, walker_fa_weight);
2729         fill p_up_out;
2730 fet_endchar;
2731
2732
2733 fet_beginchar ("Quarter down Walker fahead", "d2faWalker");
2734         draw_fa_head (funk_notehead_width, walker_fa_weight);
2735         fill p_down_out;
2736 fet_endchar;
2737
2738
2739 %%%%%%  Walker sol
2740 %       Same as Funk, no special notes
2741 %
2742
2743 %%%%%%  Walker la head
2744 %       Rectcangle head
2745 %       Lighter weight requires separate notes
2746 %
2747 save walker_la_weight;
2748 walker_la_weight := 1.5;
2749
2750 fet_beginchar ("Whole Walker lahead", "s0laWalker");
2751         draw_la_head (funk_notehead_width, walker_la_weight);
2752         fill p_out;
2753         unfill p_in;
2754 fet_endchar;
2755
2756
2757 fet_beginchar ("Half Funk lahead", "s1laWalker");
2758         draw_la_head (funk_notehead_width, walker_la_weight);
2759         fill p_out;
2760         unfill p_in;
2761 fet_endchar;
2762
2763
2764 fet_beginchar ("Quarter Funk lahead", "s2laWalker");
2765         draw_la_head (funk_notehead_width, walker_la_weight);
2766         fill p_out;
2767 fet_endchar;
2768
2769
2770 %%%%%%  Walker ti head
2771 %       Triangular arrowhead
2772 %       Rotates for all but whole notes
2773 %
2774 def draw_Walker_ti_head (expr width_factor, thickness_factor) =
2775         set_char_box (0, width_factor * solfa_base_notewidth#,
2776                       0.5 solfa_noteheight#, 0.5 solfa_noteheight#);
2777
2778         save offset;
2779         offset := 2 * thickness_factor - 1;
2780
2781         save pen_radius;
2782         pen_radius := min (solfa_pen_radius,
2783                            .3 * (h + d) / (1 + offset));
2784
2785         pickup pencircle scaled (2 * pen_radius);
2786
2787         lft x1 = 0;
2788         y1 = .5 [y2, y3];
2789
2790         rt x2 = w;
2791         top y2 = h;
2792
2793         x3 = x2;
2794         bot y3 = -d;
2795
2796
2797         labels (range 1 thru 4);
2798
2799         save nw_dist, sw_dist, ne, se;
2800         pair nw_dist, sw_dist, ne, se;
2801
2802         ne = unitvector (z2 - z1);
2803         se = unitvector (z3 - z1);
2804
2805         nw_dist = (ne rotated 90) * pen_radius ;
2806         sw_dist = (se rotated -90) * pen_radius;
2807
2808
2809         save path_a, path_b, path_c;
2810         path path_a, path_b, path_c;
2811         path_a := z2 - nw_dist * offset
2812                   -- z1 - nw_dist * offset;
2813         path_b := z3 - sw_dist * offset
2814                   -- z1 - sw_dist * offset;
2815         path_c := z2 + left * pen_radius
2816                   -- z3 + left * pen_radius;
2817
2818         z4 = path_a intersectionpoint path_b;
2819         z5 = path_a intersectionpoint path_c;
2820         z6 = path_b intersectionpoint path_c;
2821
2822         save p_up_in, p_down_in, p_up_out, p_down_out;
2823         path p_up_in, p_down_in, p_up_out, p_down_out;
2824
2825         p_down_in := z4
2826                      -- z5
2827                      -- z6
2828                      -- cycle;
2829
2830         p_down_out := lft z1{up}
2831                       .. (z1 + nw_dist){ne}
2832                       -- (z2 + nw_dist){ne}
2833                       .. top z2{right}
2834                       .. rt z2 {down}
2835                       -- rt z3 {down}
2836                       .. bot z3 {left}
2837                       .. (z3 + sw_dist){- se}
2838                       .. (z1 + sw_dist){- se}
2839                       .. cycle;
2840
2841         p_up_in := p_down_in rotated 180 shifted (w, 0);
2842         p_up_out := p_down_out rotated 180 shifted (w, 0);
2843 enddef;
2844
2845
2846 save walker_ti_weight;
2847 walker_ti_weight := 1.4;
2848
2849 fet_beginchar ("Whole Walker tihead", "s0tiWalker");
2850         draw_Walker_ti_head (funk_notehead_width, walker_ti_weight);
2851         fill p_down_out;
2852         unfill p_down_in;
2853 fet_endchar;
2854
2855
2856 fet_beginchar ("Half up Walker tihead", "u1tiWalker");
2857         draw_Walker_ti_head (funk_notehead_width, walker_ti_weight);
2858         fill p_up_out;
2859         unfill p_up_in;
2860 fet_endchar;
2861
2862
2863 fet_beginchar ("Half down Walker tihead", "d1tiWalker");
2864         draw_Walker_ti_head (funk_notehead_width, walker_ti_weight);
2865         fill p_down_out;
2866         unfill p_down_in;
2867 fet_endchar;
2868
2869
2870 fet_beginchar ("Quarter up Walker tihead", "u2tiWalker");
2871         draw_Walker_ti_head (funk_notehead_width, walker_ti_weight);
2872         fill p_up_out;
2873 fet_endchar;
2874
2875
2876 fet_beginchar ("Quarter down Walker tihead", "d2tiWalker");
2877         draw_Walker_ti_head (funk_notehead_width, walker_ti_weight);
2878         fill p_down_out;
2879 fet_endchar;
2880
2881 fet_endgroup ("noteheads");
2882
2883
2884 %
2885 % we derive black_notehead_width# from the quarter head,
2886 % so we have to define black_notehead_width (pixel qty)
2887 % after the black_notehead_width# itself.
2888 %
2889 % Let's keep it outside the group as well.
2890 %
2891
2892 define_pixels (black_notehead_width);