2 % feta-bolletjes.mf -- implement noteheads
4 % source file of LilyPond's pretty-but-neat music font
6 % (c) 1997--2004 Jan Nieuwenhuizen <janneke@gnu.org>
7 % & Han-Wen Nienhuys <hanwen@cs.uu.nl>
8 % & Juergen Reuter <reuter@ipd.uka.de>
14 % most beautiful noteheads are pronounced, not circular,
15 % and not even symmetric.
16 % These examples are inspired by [Wanske], see literature list
20 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
22 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
23 save black_notehead_width, noteheight,
24 slash_thick, slash_slope, overdone_heads;
25 numeric black_notehead_width, noteheight, slash_thick;
28 fet_begingroup("noteheads");
32 % slope of slash. From scm/grob-description.scm. How to auto-copy?
35 % thickness of slash lines. quarter notes get 1.5slt width.
36 slash_thick# := 2/3*0.48staff_space#;
40 % Hand-engraved music often has balls extending above and below
41 % the lines. If you like that, modify overdone heads (unit:
45 noteheight#:=staff_space#+ (1 + overdone_heads) *stafflinethickness#;
47 define_pixels(slash_thick, noteheight);
50 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
52 % SLANT moves both extremes on the long axis (by SLANT * ELLIPTICITY,
53 % so SLANT = -1, puts the extreme on the long axis next to the short axis one.)
56 def draw_outside_ellipse (expr ellipticity, tilt, superness,
62 p := superellipse ((ellipticity, 0), (-slant * ellipticity, 1.0),
63 (- ellipticity, 0), (slant * ellipticity, -1.0), superness);
67 save top_point, right_point;
68 pair top_point, right_point;
70 top_point := directionpoint left of p;
71 right_point := directionpoint up of p;
73 save scaling, width, height;
75 scaling# = noteheight# /(2 ypart (top_point));
76 width# := 2 xpart (right_point) * scaling#;
78 define_pixels (width, scaling);
80 set_char_box (0, width#, noteheight#/2, noteheight#/2);
83 charwy := ypart (right_point) * scaling#;
86 p := p scaled scaling shifted (width/2, 0) ;
88 pickup pencircle scaled 1 ; draw p;
95 def undraw_inside_ellipse (expr ellipticity, tilt, superness, clearance,
101 p := superellipse ((ellipticity, 0), (0, 1.0),
102 (- ellipticity, 0), (0, -1.0), superness);
106 save top_point, right_point;
107 pair top_point, right_point;
109 top_point := directionpoint left of p;
110 right_point := directionpoint up of p;
112 save height, scaling;
114 height# = staff_space# + stafflinethickness# - clearance;
115 scaling# = height# /(2 ypart (top_point));
117 define_pixels (scaling);
118 p := (p scaled scaling) shifted center;
120 if test_outlines = 1:
121 pickup pencircle scaled 1; draw p;
133 % dimensions aren't entirely right.
135 fet_beginchar ("Brevis notehead", "s-1", "brevishead");
136 save stemthick, fudge;
137 define_pixels (stemthick);
138 fudge = blot_diameter / 2;
139 stemthick# = 2 stafflinethickness#;
141 draw_outside_ellipse (1.80, 0, 0.707, 0);
142 undraw_inside_ellipse (1.30, 125, 0.68, 2 stafflinethickness#,
145 pickup pencircle scaled stemthick;
157 draw_gridline(z1,z2,stemthick);
158 draw_gridline(z3,z4,stemthick);
164 fet_beginchar("Whole notehead", "s0", "wholehead")
165 draw_outside_ellipse (1.80 - puff_up_factor / 3.0, 0, 0.707, 0);
166 undraw_inside_ellipse (1.30, 125 - puff_up_factor *10,
167 0.68, 2 stafflinethickness#,
170 % draw_staff_outline (-2, 2, 0.5);
175 fet_beginchar("Half notehead", "s1", "halfhead")
176 draw_outside_ellipse (1.53 - puff_up_factor / 3.0, 34, 0.66, 0.17);
177 undraw_inside_ellipse (3.25, 33, 0.81,
178 2.5 stafflinethickness#, (w/2, 0));
182 fet_beginchar("Quart notehead", "s2", "quarthead")
184 % used to have 32. With 31, they are slightly bolder.
185 draw_outside_ellipse (1.49 - puff_up_factor / 3.0, 31, 0.707, 0);
186 black_notehead_width# := charwd;
189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
192 fet_beginchar("Whole diamondhead", "s0diamond", "wholediamondhead")
193 draw_outside_ellipse (1.80, 0, 0.495, 0);
194 undraw_inside_ellipse (1.30, 125, 0.6,
195 .4 staff_space# + stafflinethickness#,
200 fet_beginchar("Half diamondhead", "s1diamond",
203 draw_outside_ellipse (1.50, 34, 0.49, 0.17);
204 undraw_inside_ellipse (3.5, 33, 0.80,
205 .3 staff_space# + 1.5 stafflinethickness#, (w/2, 0));
209 fet_beginchar("Quart diamondhead", "s2diamond", "diamondhead")
210 draw_outside_ellipse (1.80, 35, 0.495, -0.25);
213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219 def define_triangle_shape(expr stemdir) =
220 save triangle,kern; path triangle;
221 save width, depth, height;
222 save left_point, height, width, origin;
223 save left_up_dir, exact_right_point, exact_down_point;
224 pair exact_down_point, exact_left_point, origin, left_up_dir, exact_right_point;
227 pen_thick# = stafflinethickness# + .1 staff_space#;
228 define_pixels(pen_thick, llap);
230 left_up_dir = llap# * dir (90 + tilt);
232 xpart (left_up_dir) * xs - (pen_thick# * xs)/2 + xpart origin = 0;
235 exact_left_point := origin + (left_up_dir xscaled xs);
236 exact_down_point := origin + (left_up_dir rotated 120 xscaled xs);
237 exact_right_point := origin + (left_up_dir rotated 240 xscaled xs);
239 height# = ypart (exact_left_point + origin) + pen_thick#/2;
240 depth# = -ypart (exact_down_point + origin) + pen_thick#/2;
241 width# = xpart (exact_right_point - exact_left_point) + pen_thick# * xs;
243 set_char_box(0, width#, depth#, height#);
245 z0 = (hround_pixels (xpart origin), 0);
246 z1 = z0 + llap * dir(90+tilt) xscaled xs;
247 z2 = z0 + (llap * dir(90+tilt + 120) xscaled xs);
248 z3 = z0 + (llap * dir(90+tilt + 240) xscaled xs);
250 z12 = caveness[.5[z1,z2],z3];
251 z23 = caveness[.5[z2,z3],z1];
252 z31 = caveness[.5[z3,z1],z2];
254 triangle = z1 .. z12 .. z2 ..
258 pickup pencircle scaled pen_thick xscaled xs;
259 labels(1,2,12,23,31,3);
264 charwy := ypart exact_right_point;
265 charwx := xpart exact_right_point;
267 charwy := - ypart exact_down_point;
268 charwx := (width# - xpart exact_down_point);
272 fet_beginchar("Whole trianglehead", "0triangle", "wholetrianglehead")
278 llap# = 3/4noteheight#;
282 define_triangle_shape(1);
287 def draw_closed_triangle_head(expr dir) =
293 llap# = 2/3noteheight#;
296 define_triangle_shape(dir);
300 fet_beginchar("Half trianglehead", "d1triangle", "dhalftrianglehead")
301 draw_closed_triangle_head(-1);
304 fet_beginchar("Half trianglehead", "u1triangle", "uhalftrianglehead")
305 draw_closed_triangle_head(1);
308 def draw_closed_triangle_head(expr dir) =
313 llap# = 2/3noteheight#;
316 define_triangle_shape(dir);
320 fet_beginchar("Quart trianglehead", "u2triangle", "utrianglehead")
321 draw_closed_triangle_head(1);
324 fet_beginchar("Quart trianglehead", "d2triangle", "dtrianglehead")
325 draw_closed_triangle_head(-1);
328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330 % slash heads are for indicating improvisation. They are
331 % twice as high as normal heads.
333 def draw_slash(expr hwid_hash) =
337 exact_height = staff_space# + stafflinethickness#/2;
339 set_char_box (0, 2 exact_height / slash_slope + hwid_hash,
340 exact_height, exact_height);
346 pickup pencircle scaled blot_diameter;
351 lft x2 = 2 h / slash_slope;
358 ne_dir := unitvector( z3 - z4);
359 filldraw z1 --- z2 --- z3 --- z4 --- cycle;
361 if hwid_hash > 2 slash_thick#:
364 th = slash_thick - blot_diameter;
369 z6 - z5 = whatever * ne_dir;
370 z8 - z7 = whatever * ne_dir;
372 z5 = z1 + whatever * ne_dir + th * (ne_dir rotated -90);
373 z8 = z4 + whatever * ne_dir + th * (ne_dir rotated 90);
376 z5 -- z6 -- z7 -- z8 -- cycle;
378 labels (range 1 thru 10);
381 fet_beginchar("Whole slashhead","s0slash","wholeslashhead")
382 draw_slash(4 slash_thick# + 0.5 staff_space#);
385 fet_beginchar("Half slashhead","s1slash","halfslashhead")
386 draw_slash(3.0 slash_thick# + 0.15 staff_space#);
389 fet_beginchar("Quart slashhead","s2slash","quartslashhead")
390 draw_slash(1.5 slash_thick#);
393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
394 % thick is the distance between the NE/SW parallel lines in the cross
395 % (distance between centres of lines)
396 % in stafflinethickness def
398 def draw_cross(expr thick) =
399 save pent, slant, ne_dir;
403 pen_thick# := 1.2 stafflinethickness#;
404 define_pixels (pen_thick);
405 pickup pencircle scaled pen_thick;
408 ne_dir := unitvector ((1, (2 h -pen_thick)/(w - pen_thick)));
411 z4 - z5 = whatever * ne_dir;
413 z6 - z3 = whatever * ne_dir;
414 z3 - z4 = whatever * (ne_dir yscaled -1);
416 z4 - z3 = whatever * (ne_dir) + (ne_dir rotated -90) * thick * stafflinethickness;
418 x1 = charwd/2 - .5 pen_thick#;
419 z1 = whatever * ne_dir + thick/2 * stafflinethickness# * (ne_dir rotated -90);
422 labels (1,2,3,4,5,6);
424 crz = (z6 -- z3 -- z4 -- z5) ;
426 draw crz shifted(w/2,0);
427 draw crz xscaled -1 shifted(w/2,0);
428 draw crz yscaled -1 shifted(w/2,0);
429 draw crz scaled -1 shifted(w/2,0);
433 z12 = (charwx * hppp, y1 * vppp);
437 fet_beginchar("Whole Crossed notehead", "s0cross", "wholecrossedhead")
438 wid# := black_notehead_width#+4stafflinethickness#;
439 hei# := noteheight#+stafflinethickness#;
440 set_char_box(0, wid#,hei#/2,hei#/2);
445 fet_beginchar("Half Crossed notehead", "s1cross", "halfcrossedhead")
446 wid# := black_notehead_width#+2 stafflinethickness#;
447 hei# := noteheight#+stafflinethickness#/2;
448 set_char_box(0, wid#,hei#/2,hei#/2);
452 fet_beginchar("Crossed notehead", "s2cross", "crossedhead")
453 wid# := black_notehead_width#;
455 set_char_box(0, wid#,hei#/2,hei#/2);
459 fet_beginchar("X-Circled notehead", "s2xcircle", "xcircledhead")
460 wid# := black_notehead_width#*sqrt(sqrt2);
461 hei# := noteheight#*sqrt(sqrt2);
462 set_char_box(0, wid#,hei#/2,hei#/2);
463 cthick := (1.2+1/4)*stafflinethickness;
466 pickup pencircle scaled cthick;
467 draw fullcircle xscaled 2cxr yscaled 2cyr shifted (w/2,0);
470 draw (-xpos+w/2,-ypos) -- (xpos+w/2,ypos);
471 draw (-xpos+w/2,ypos) -- (xpos+w/2,-ypos);
476 z12 = (charwx * hppp , charwy * vppp );
491 def generic_draw_solfa_note_shape =
492 save a,beta,black,white;
495 pickup pencircle scaled stafflinethickness;
496 2 beta# = noteheight#;
498 wid# := 2a#+stafflinethickness#;
499 hei# := noteheight#+stafflinethickness#;
500 set_char_box(0, wid#,0.5 hei#, 0.5 hei#);
502 define_pixels(a,beta);
504 black = noteshape xscaled a yscaled beta shifted (a+stafflinethickness/2,0);
508 white = noteishape xscaled (a*ai_a) yscaled (beta*bi_b)
509 shifted ((dx+1)*(a+stafflinethickness/2),
510 dy*(beta+stafflinethickness/2));
515 def draw_solfa_note_shape =
516 save solid; boolean solid;
518 generic_draw_solfa_note_shape;
520 def draw_solfa_quarter_note_shape =
521 save solid; boolean solid;
523 generic_draw_solfa_note_shape;
526 % do - equilateral triangle: (0,-h/2) -- (w/2,h/2) -- (w,-h/2) -- cycle;
527 % stem attachment: -h/2
529 save triangle; path triangle;
530 triangle := (-1,-1) -- (0,1) -- (1,-1) -- cycle;
535 save solfa_pen_thick;
536 solfa_pen_thick# = 2 stafflinethickness#;
537 define_pixels (solfa_pen_thick);
539 def draw_do_head (expr width_factor, dir) =
542 set_char_box(0, width_factor * noteheight#, 0.5 noteheight#, 0.5 noteheight#);
544 pickup pencircle scaled solfa_pen_thick;
553 p := z1 -- z2 -- z3 -- cycle;
556 charwy := - chardp + 0.5 stafflinethickness#;
562 fet_beginchar("Whole dohead", "s0do", "wholedohead")
563 draw_do_head (1.8, 1);
568 fet_beginchar("Half dohead", "d1do", "downhalfdohead")
569 draw_do_head (1.5, -1);
573 fet_beginchar("Half dohead", "s1do", "halfdohead")
574 draw_do_head (1.5, 1);
578 fet_beginchar("Quart dohead", "d2do", "downdohead")
579 draw_do_head (1.55, -1);
584 fet_beginchar("Quart dohead", "s2do", "dohead")
585 draw_do_head (1.55, 1);
590 % re - flat top, curved bottom:
591 % (0,h/2) {dir -90} .. (w/2,-h/2) .. {dir 90} (w,h/2) -- cycle;
592 % (broader along the base and with more vertical sides for half and
594 % stem attachment: h/2
598 def draw_re_head (expr width_factor, dir) =
601 set_char_box(0, width_factor * noteheight#, 0.5 noteheight#, 0.5 noteheight#);
603 pickup pencircle scaled solfa_pen_thick;
610 y2 = curve_start [y3,y1];
617 labels (range 1 thru 5);
618 p := z1 --- z2 .. z3{right} .. z4 --- z5 --- cycle;
621 charwy := curve_start [-chardp, charht];
627 fet_beginchar("Whole rehead", "s0re", "wholerehead")
628 draw_re_head (1.8,1);
633 fet_beginchar("Half up rehead", "u1re", "uphalfrehead")
634 draw_re_head (1.5, 1);
638 fet_beginchar("Half down rehead", "d1re", "downhalfrehead")
639 draw_re_head (1.5, -1);
644 fet_beginchar("Quart rehead", "u2re", "uprehead")
645 draw_re_head (1.55, 1);
649 fet_beginchar("Quart rehead", "d2re", "downrehead")
650 draw_re_head (1.55, -1);
657 def draw_mi_head (expr width_factor) =
658 save path_out, path_in;
659 path path_out, path_in;
660 set_char_box(0, width_factor * noteheight#, 0.5 noteheight#, 0.5 noteheight#);
662 pickup pencircle scaled solfa_pen_thick;
674 z6 - z5 = whatever * (z2 - z1);
675 z8 - z7 = whatever * (z2 - z1);
676 z8 - z5 = whatever * (z4 - z1);
677 z6 - z7 = whatever * (z4 - z1);
679 z5 = whatever [z1, z4] + (unitvector (z4 - z1) rotated -90 scaled 0.5 solfa_pen_thick);
680 z5 = whatever [z1, z2] + (unitvector (z2 - z1) rotated 90 scaled 0.75 solfa_pen_thick);
682 z5 - z1 = -(z7 - z3);
684 labels (range 1 thru 8);
685 path_out := z1 -- z2 -- z3 -- z4 -- cycle;
686 path_in := z5 -- z6 -- z7 -- z8 -- cycle;
687 % path_in := z5 -- z1 --cycle;
690 fet_beginchar("Whole mihead", "s0mi", "wholemihead")
697 fet_beginchar("Half mihead", "s1mi", "halfmihead")
704 fet_beginchar("Quart mihead", "s2mi", "mihead")
712 def draw_fa_head (expr width_factor) =
713 set_char_box(0, width_factor * noteheight#, 0.5 noteheight#, 0.5 noteheight#);
717 pickup pencircle scaled solfa_pen_thick;
730 labels(range 1 thru 4);
732 p_up := z1 -- z2 -- z3 --cycle;
733 p_down := z1 -- z4 -- z3 --cycle;
740 fet_beginchar("Whole fa up head", "d0fa", "wholefadownhead")
745 fet_beginchar("Whole fa down head", "u0fa", "wholefauphead")
750 fet_beginchar("half fa up head", "d1fa", "halffadownhead")
755 fet_beginchar("Half fa down head", "u1fa", "halffauphead")
760 fet_beginchar("Quarter fa up head", "u2fa", "quarterfadownhead")
765 fet_beginchar("Quarter fa down head", "d2fa", "quarterfauphead")
771 def draw_la_head (expr width_factor) =
772 set_char_box(0, width_factor * noteheight#, 0.5 noteheight#, 0.5 noteheight#);
776 pickup pencircle scaled solfa_pen_thick;
789 labels(range 1 thru 4);
791 p := z1 -- z2 -- z3 -- z4 -- cycle;
794 fet_beginchar("Whole lahead", "s0la", "wholelahead")
800 fet_beginchar("Half lahead", "s1la", "halflahead")
806 fet_beginchar("Quart lahead", "s2la", "lahead")
813 def draw_ti_head (expr width_factor, dir) =
814 set_char_box(0, width_factor * noteheight#, 0.5 noteheight#, 0.5 noteheight#);
820 pickup pencircle scaled solfa_pen_thick;
825 y2 = cone_height [y1,y3];
831 labels(range 1 thru 4);
833 p := z1 -- z2 .. z3{right} .. z4 -- cycle;
835 charwy := cone_height [-chardp, charht];
841 fet_beginchar("Whole up tihead", "s0ti", "wholetihead")
842 draw_ti_head (1.8, 1);
847 fet_beginchar("Half up tihead", "u1ti", "uphalftihead")
848 draw_ti_head (1.5, 1);
852 fet_beginchar("Half down tihead", "d1ti", "dnhalftihead")
853 draw_ti_head (1.5, -1);
859 fet_beginchar("Quart up tihead", "u2ti", "utihead")
860 draw_ti_head (1.55, 1);
865 fet_beginchar("Quart down tihead", "d2ti", "dtihead")
866 draw_ti_head (1.55, -1);
872 fet_endgroup("noteheads");
876 % we derive black_notehead_width# from the quarter head,
877 % so we have to define black_notehead_width (pixel qty)
878 % after the black_notehead_width# itself. Let's keep it outside the group as well.
880 define_pixels(black_notehead_width);