]> git.donarmstrong.com Git - lilypond.git/blobdiff - mf/parmesan-custodes.mf
Release: bump Welcome versions.
[lilypond.git] / mf / parmesan-custodes.mf
index f61f2449f6c5cc83daf047d5f9d2025fcda2a916..144d84392df397d6b45fc6df5301ec68fd67a89b 100644 (file)
-% -*-Fundamental-*-
-% feta-custodes.mf --  implement custos symbols
-% 
-% source file of LilyPond's pretty-but-neat music font
-% 
-% (C) 2000, 2002 Juergen Reuter <reuter@ipd.uka.de>
+% Feta (not the Font-En-Tja) music font --  ancient custodes
+% This file is part of LilyPond, the GNU music typesetter.
+%
+% Copyright (C) 2000--2015 Juergen Reuter <reuter@ipd.uka.de>
 % 
+% The LilyPond font is free software: you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation, either version 3 of the License, or
+% (at your option) any later version, or under the SIL Open Font License.
+%
+% LilyPond is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
 
 save black_notehead_width;
 numeric black_notehead_width;
 
-fet_begingroup("custodes");
+fet_begingroup ("custodes");
 
-noteheight#:=staff_space#+ (1 + overdone_heads) *stafflinethickness#;
-define_pixels(noteheight);
+%
+% character aligment:
+%
+%   The custos is assumed to be vertically centered around (0, 0).
+%   The left-most edge of the custos should touch the vertical line
+%   that goes though the point (0, 0).
+%
+% set_char_box() conventions:
+%
+% * breapth: Ignored (as far as I know).  Should be set to 0.
+%
+% * width: Should cover the horizontal range of the custos that is to
+%   be printed in the staff.  If the custos has an appendage that is
+%   supposed to reach beyond the right end of the staff, the width
+%   should be set such that the appendage is outside of the char box.
+%
+% * depth: Should match the bottom edge of the custos.  Affects
+%   vertical collision handling.
+%
+% * height: Should match the top edge of the custos.  Affects vertical
+%   collision handling.
+%
+
+save between_staff_lines, on_staff_line, anywhere;
+
+between_staff_lines := 0;
+on_staff_line := 1;
+anywhere := 2;
+
+save dir_up, dir_down;
+
+dir_up := 1;
+dir_down := -1;
 
 
 %%%%%%%%
 %
+%
 % Hufnagel style
 %
+%
+
+% parameterized hufnagel custos
+def custos_hufnagel (expr verbose_name, internal_name, 
+                         direction, staffline_adjustment) =
+
+       fet_beginchar (verbose_name, internal_name);
+               save alpha, dalpha, ht, wd, stem_ht, pen_size;
+
+               ht# = noteheight#;
+               wd# / ht# = 0.6;
+               alpha = 35;
+               dalpha = direction * alpha;
+
+               if staffline_adjustment = between_staff_lines:
+                       stem_ht# = 1.00 staff_space#;
+               elseif staffline_adjustment = on_staff_line:
+                       stem_ht# = 1.50 staff_space#;
+               else: % staffline_adjustment = anywhere
+                       stem_ht# = 1.25 staff_space#;
+               fi;
+
+               pen_size# = 0.5 (wd# ++ ht#);
+
+               define_pixels (ht, wd, pen_size, stem_ht);
 
-% stem up
-fet_beginchar("Custos Hufnagel", "hufnagel", "hufnagel")
-       save b_h,a_w;
-       a_b:=1.54; % b_h*a_b/a_w = wd/ht
-       b_h:=0.85;
-       a_w:=1.09;
-
-       save a, beta, ht, wd;
-       ht# =noteheight#;
-       2beta#=ht#*b_h;
-       a# = beta#*a_b;
-       wd# = 2a# / a_w;
-       set_char_box(0, wd#, ht#/2, ht#/2);
-       black_notehead_width# := wd#;
-
-       save rh_width, rh_height, rh_edge; % rhombus dimensions
-       rh_width#=0.7ht#; % ht*tan(35)
-       rh_height#=1.0ht#;
-       rh_edge#=0.61ht#; % (ht/2)/cos(35)
-
-       define_pixels(rh_width, rh_height, rh_edge);
-       pickup pencircle
-         xscaled stafflinethickness
-         yscaled rh_edge rotated -35;
-       z1=(0.5rh_width,+0.25rh_height);
-       z2=(1.0rh_width,-0.25rh_height);
-       z3=(2.0rh_width,+0.50rh_height);
-       draw z1 -- z2 -- z3;
-fet_endchar;
-
-% stem down
-fet_beginchar("Reverse Custos Hufnagel", "rhufnagel", "rhufnagel")
-       save b_h,a_w;
-       a_b:=1.54; % b_h*a_b/a_w = wd/ht
-       b_h:=0.85;
-       a_w:=1.09;
-
-       save a, beta, ht, wd;
-       ht# =noteheight#;
-       2beta#=ht#*b_h;
-       a# = beta#*a_b;
-       wd# = 2a# / a_w;
-       set_char_box(0, wd#, ht#/2, ht#/2);
-       black_notehead_width# := wd#;
-
-       save rh_width, rh_height, rh_edge; % rhombus dimensions
-       rh_width#=0.7ht#; % ht*tan(35)
-       rh_height#=1.0ht#;
-       rh_edge#=0.61ht#; % (ht/2)/cos(35)
-
-       define_pixels(rh_width, rh_height, rh_edge);
-       pickup pencircle
-         xscaled stafflinethickness
-         yscaled rh_edge rotated +35;
-       z1=(0.5rh_width,-0.25rh_height);
-       z2=(1.0rh_width,+0.25rh_height);
-       z3=(2.0rh_width,-0.50rh_height);
-       draw z1 -- z2 -- z3;
-fet_endchar;
+               save ellipse, pat, T;
+               path ellipse, pat;
+               transform T;
+
+               T := identity xscaled linethickness
+                             yscaled pen_size
+                             rotated -dalpha;
+               pickup pencircle transformed T;
+               ellipse := fullcircle transformed T;
+
+               if direction = dir_up:
+                       top y1 = ht / 2;
+                       bot y2 = -ht / 2;
+               else:
+                       bot y1 = -ht / 2;
+                       top y2 = ht / 2;
+               fi;
+
+               lft x1 = 0;
+               rt  x2 = wd;
+               y3 - y2 = direction * stem_ht;
+               (y3 - y2) = (x3 - x2) * tand (90 - dalpha);
+
+               fill get_subpath (ellipse, z1 - z2, z2 - z1, z1)
+                    if direction > 0:
+                            -- get_subpath (ellipse, z2 - z1, z3 - z2, z2)
+                    else:
+                            -- get_subpoint (ellipse, z2 - z1, z2)
+                            -- get_subpoint (ellipse, z3 - z2, z2)
+                    fi
+                    -- get_subpath (ellipse, z3 - z2, z2 - z3, z3)
+                    if direction > 0:
+                            -- get_subpoint (ellipse, z2 - z3, z2)
+                            -- get_subpoint (ellipse, z1 - z2, z2)
+                    else:
+                            -- get_subpath (ellipse, z2 - z3, z1 - z2, z2)
+                    fi
+                    -- cycle;
+
+               % The stem is intentionally outside of the char box.
+               if direction > 0:
+                       set_char_box (0, wd#, ht# / 2, stem_ht#);
+               else:
+                       set_char_box (0, wd#, stem_ht#, ht# / 2);
+               fi;
+
+               labels (1, 2, 3);
+       fet_endchar;
+enddef;
+
+
+% custos hufnagel, stem up, between staff lines
+custos_hufnagel ("Custos Hufnagel", "hufnagel.u0", 
+                dir_up, between_staff_lines);
+
+
+% custos hufnagel, stem up, on staff line
+custos_hufnagel ("Custos Hufnagel", "hufnagel.u1", 
+                dir_up, on_staff_line);
+
+
+% custos hufnagel, stem up, anywhere
+custos_hufnagel ("Custos Hufnagel", "hufnagel.u2", 
+                dir_up, anywhere);
+
+
+% custos hufnagel, stem down, between staff lines
+custos_hufnagel ("Reverse Custos Hufnagel", "hufnagel.d0",
+                dir_down, between_staff_lines);
+
+
+% custos hufnagel, stem down, on staff line
+custos_hufnagel ("Reverse Custos Hufnagel", "hufnagel.d1",
+                dir_down, on_staff_line);
+
+
+% custos hufnagel, stem down, anywhere
+custos_hufnagel ("Reverse Custos Hufnagel", "hufnagel.d2",
+                dir_down, anywhere);
 
 
 %%%%%%%%
 %
+%
 % Medicaea style
 %
+%
+
+def custos_medicaea (expr verbose_name, internal_name, 
+                         direction, staffline_adjustment) =
+       fet_beginchar (verbose_name, internal_name);
+               save ht, wd, stem_ht;
+
+               ht# = noteheight#;
+               wd# / ht# = 0.25;
+
+               if staffline_adjustment = between_staff_lines:
+                       stem_ht# = 1.00 staff_space#;
+               elseif staffline_adjustment = on_staff_line:
+                       stem_ht# = 1.50 staff_space#;
+               else: % staffline_adjustment = anywhere
+                       stem_ht# = 1.25 staff_space#;
+               fi;
+
+               define_pixels (ht, wd, stem_ht);
 
-% stem up
-fet_beginchar("Custos Med.", "medicaea", "medicaea")
-       save b_h, a_w;
-       a_b := 1.54; % b_h*a_b/a_w = wd/ht
-       b_h := 0.85;
-       a_w := 1.09;
-
-       save a, beta, ht, wd;
-       ht# = noteheight# * mag;
-       2beta# = ht# * b_h;
-       a# = beta# * a_b;
-       wd# = 0.4a# / a_w;
-       set_char_box(0, wd#, ht#/2, ht#/2); % width intentionally too small
-       black_notehead_width# := wd#;
-
-       define_pixels(ht, wd);
-
-       % head
-       pickup pencircle xscaled blot_diameter yscaled 1.0ht;
-       z1 = (0.0wd, 0.0ht);
-       z2 = z1 + (1.0wd - blot_diameter/2, 0);
-       draw z1 .. z2;
-
-       % stem
-       pickup pencircle scaled stafflinethickness;
-       z3 = (1.0wd - stafflinethickness/2, 0.0ht);
-       z4 = z3 + (0, +1.0ht);
-       draw z3 .. z4;
-fet_endchar;
-
-
-% stem down
-fet_beginchar("Reverse Custos Med.", "rmedicaea", "rmedicaea")
-       save b_h, a_w;
-       a_b := 1.54; % b_h*a_b/a_w = wd/ht
-       b_h := 0.85;
-       a_w := 1.09;
-
-       save a, beta, ht, wd;
-       ht# = noteheight# * mag;
-       2beta# = ht# * b_h;
-       a# = beta# * a_b;
-       wd# = 0.4a# / a_w;
-       set_char_box(0, wd#, ht#/2, ht#/2); % width intentionally too small
-       black_notehead_width# := wd#;
-
-       define_pixels(ht, wd);
-
-       % head
-       pickup pencircle xscaled blot_diameter yscaled 1.0ht;
-       z1 = (0.0wd, 0.0ht);
-       z2 = z1 + (1.0wd - blot_diameter/2, 0);
-       draw z1 .. z2;
-
-       % stem
-       pickup pencircle scaled stafflinethickness;
-       z3 = (1.0wd - stafflinethickness/2, 0.0ht);
-       z4 = z3 + (0, -1.0ht);
-       draw z3 .. z4;
-fet_endchar;
+               save ellipse, T;
+               path ellipse;
+               transform T;
+
+               T := identity xscaled 0.6 linethickness
+                             yscaled ht;
+               pickup pencircle transformed T;
+               ellipse := fullcircle transformed T;
+
+               lft x1 = 0;
+               y1 = 0;
+               rt x2 = wd;
+               y2 = y1;
+
+               fill get_subpath (ellipse, left, right, z1)
+                    -- get_subpath (ellipse, right, left, z2)
+                    -- cycle;
+
+               pickup pencircle scaled 0.6 linethickness;
+
+               rt x3 = wd;
+               y3 = 0;
+               x4 = x3;
+               if direction > 0:
+                       top y4 = stem_ht;
+                       draw_rounded_block (bot lft z3, top rt z4,
+                                           0.6 linethickness);
+               else:
+                       bot y4 = -stem_ht;
+                       draw_rounded_block (bot lft z4, top rt z3,
+                                           0.6 linethickness);
+               fi;
+
+
+               if direction > 0:
+                       set_char_box (0, wd#, ht# / 2, stem_ht#);
+               else:
+                       set_char_box (0, wd#, stem_ht#, ht# / 2);
+               fi;
+
+               labels (1, 2, 3, 4);
+       fet_endchar;
+enddef;
+
+
+% custos medicaea, stem up, between staff lines
+custos_medicaea ("Custos Med.", "medicaea.u0", 
+                dir_up, between_staff_lines);
+
+
+% custos medicaea, stem up, on staff line
+custos_medicaea ("Custos Med.", "medicaea.u1", 
+                dir_up, on_staff_line);
+
+
+% custos medicaea, stem up, anywhere
+custos_medicaea ("Custos Med.", "medicaea.u2", 
+                dir_up, anywhere);
+
+
+% custos medicaea, stem down, between staff lines
+custos_medicaea ("Reverse Custos Med.", "medicaea.d0", 
+               dir_down, between_staff_lines);
+
+
+% custos medicaea, stem down, on staff line
+custos_medicaea ("Reverse Custos Med.", "medicaea.d1", 
+                dir_down, on_staff_line);
+
+
+% custos medicaea, stem down, anywhere
+custos_medicaea ("Reverse Custos Med.", "medicaea.d2", 
+                dir_down, anywhere);
 
 
 %%%%%%%%
 %
+%
 % Editio Vaticana style
 %
+%
+
+def custos_vaticana (expr verbose_name, internal_name, 
+                         direction, staffline_adjustment) =
+       fet_beginchar (verbose_name, internal_name);
+               save ht, wd, u_offs, l_offs, stem_size, stem_end;
+               save pen_ht, l_shift, curve_ht, bend_ht;
+
+               ht# = noteheight#;
+               wd# = 0.24 ht#;
+
+               if staffline_adjustment = between_staff_lines:
+                       stem_size# = 1.00;
+               elseif staffline_adjustment = on_staff_line:
+                       stem_size# = 1.50;
+               else: % staffline_adjustment = anywhere
+                       stem_size# = 1.25;
+               fi;
 
-% stem up
-fet_beginchar("Custos Ed. Vat.", "vaticana", "vaticana")
-       save b_h, a_w;
-       a_b := 1.54; % b_h*a_b/a_w = wd/ht
-       b_h := 0.85;
-       a_w := 1.09;
-
-       save a, beta, ht, wd;
-       ht# = noteheight# * mag;
-       2beta# = ht# * b_h;
-       a# = beta# * a_b;
-       wd# = 0.4a# / a_w;
-       set_char_box(0, wd#, ht#/2, ht#/2);
-       black_notehead_width# := wd#;
-
-       define_pixels(ht, wd);
-       pickup pencircle scaled stafflinethickness;
-
-       z1 = (0.0wd, +0.05ht);
-       z2 = (1.0wd + 0.5stafflinethickness, 0.0ht);
-       penpos1(0.5ht, 90);
-       penpos2(0.5ht, 90);
-       penstroke z1e{z2 - z1} .. {right}z2e;
-
-       z3=(1.0wd, +0.0ht);
-       z4=(1.0wd, +1.0ht);
-       draw z3 -- z4;
-fet_endchar;
-
-
-% stem down
-fet_beginchar("Reverse Custos Ed. Vat.", "rvaticana", "rvaticana")
-       save b_h, a_w;
-       a_b := 1.54; % b_h*a_b/a_w = wd/ht
-       b_h := 0.85;
-       a_w := 1.09;
-
-       save a, beta, ht, wd;
-       ht# = noteheight# * mag;
-       2beta# = ht# * b_h;
-       a# = beta# * a_b;
-       wd# = 0.4a# / a_w;
-       set_char_box(0, wd#, ht#/2, ht#/2);
-       black_notehead_width# := wd#;
-
-       define_pixels(ht, wd);
-       pickup pencircle scaled stafflinethickness;
-
-       z1 = (0.0wd, -0.05ht);
-       z2 = (1.0wd + 0.5stafflinethickness, -0.0ht);
-       penpos1(0.5ht, 90);
-       penpos2(0.5ht, 90);
-       penstroke z1e{z2 - z1} .. {right}z2e;
-
-       z3=(1.0wd, -0.0ht);
-       z4=(1.0wd, -1.0ht);
-       draw z3 -- z4;
-fet_endchar;
+               curve_ht# = 0.6 ht#;
+               bend_ht# = 0.10 ht#;
+               l_shift# = 0.04 ht#;
+               u_offs# = +direction * 0.5 * (bend_ht# + l_shift#);
+               l_offs# = -direction * 0.5 * (bend_ht# - l_shift#);
+               stem_end# = direction * stem_size# * staff_space#;
+               pen_ht# = curve_ht# - l_shift#;
+
+               define_pixels (u_offs, l_offs, stem_end, ht, wd, pen_ht);
+
+               pickup pencircle scaled 0.6 linethickness;
+
+               z1 = (0, u_offs);
+               z2 = (0.7 wd, l_offs);
+               z3 = (wd, l_offs);
+
+               penpos1 (pen_ht, 90);
+               penpos2 (pen_ht, 90);
+               penpos3 (pen_ht, 90);
+
+               penstroke z1e{z2 - z1}
+                         .. {right}z2e
+                         .. z3e;
+
+               rt x4 = wd;
+               x5 = x4;
+
+               if direction > 0:
+                       y4 = y3r;
+                       top y5 = stem_end;
+                       draw_rounded_block (bot lft z4, top rt z5,
+                                           0.6 linethickness);
+               else:
+                       y4 = y3l;
+                       bot y5 = stem_end;
+                       draw_rounded_block (bot lft z5, top rt z4,
+                                           0.6 linethickness);
+               fi;
+
+               if direction > 0:
+                       set_char_box (0, wd#,
+                                     -l_offs# + 0.5 pen_ht#, stem_end#);
+               else:
+                       set_char_box (0, wd#,
+                                     -stem_end#, +l_offs# + 0.5 pen_ht#);
+               fi;
+
+               penlabels (1, 2, 3);
+               labels (4, 5);
+       fet_endchar;
+enddef;
+
+
+% custos vaticana, stem up, between staff lines
+custos_vaticana ("Custos Ed. Vat.", "vaticana.u0", 
+                dir_up, between_staff_lines);
+
+
+% custos vaticana, stem up, on staff line
+custos_vaticana ("Custos Ed. Vat.", "vaticana.u1", 
+                dir_up, on_staff_line);
+
+
+% custos vaticana, stem up, anywhere
+custos_vaticana ("Custos Ed. Vat.", "vaticana.u2", 
+                dir_up, anywhere);
+
+
+% custos vaticana, stem down, between staff lines
+custos_vaticana ("Reverse Custos Ed. Vat.", "vaticana.d0", 
+                dir_down, between_staff_lines);
+
+
+% custos vaticana, stem down, on_staff_line
+custos_vaticana ("Reverse Custos Ed. Vat.", "vaticana.d1", 
+                dir_down, on_staff_line);
+
+
+% custos vaticana, stem down, anywhere
+custos_vaticana ("Reverse Custos Ed. Vat.", "vaticana.d2", 
+                dir_down, anywhere);
 
 
 %%%%%%%%
 %
+%
 % Mensural style
 %
+%
 
-% stem up
-fet_beginchar("Custos Mensural", "mensural", "mensural")
-       save b_h,a_w;
-       a_b:=1.54; % b_h*a_b/a_w = wd/ht
-       b_h:=0.85;
-       a_w:=1.09;
-
-       save a, beta, ht, wd;
-       ht# =noteheight#;
-       2beta#=ht#*b_h;
-       a# = beta#*a_b;
-       wd# = 2a# / a_w;
-       set_char_box(0, wd#, ht#/2, ht#/2); % width intentionally too small
-       black_notehead_width# := wd#;
-
-       define_pixels(ht, wd);
-       pickup pencircle xscaled stafflinethickness yscaled 0.4ht rotated -35;
-       z1=(0.0wd,-0.2ht);
-       z2=(0.2wd,+0.2ht);
-       z3=(0.4wd,-0.2ht);
-       z4=(0.6wd,+0.2ht);
-       z5=(0.8wd,-0.2ht);
-       z6=(1.6wd,+1.4ht);
-       draw z1 -- z2 -- z3 -- z4 -- z5 -- z6;
-fet_endchar;
-
-% stem down
-fet_beginchar("Reverse Custos Mensural", "rmensural", "rmensural")
-       save b_h,a_w;
-       a_b:=1.54; % b_h*a_b/a_w = wd/ht
-       b_h:=0.85;
-       a_w:=1.09;
-
-       save a, beta, ht, wd;
-       ht# =noteheight#;
-       2beta#=ht#*b_h;
-       a# = beta#*a_b;
-       wd# = 2a# / a_w;
-       set_char_box(0, wd#, ht#/2, ht#/2); % width intentionally too small
-       black_notehead_width# := wd#;
-
-       define_pixels(ht, wd);
-       pickup pencircle xscaled stafflinethickness yscaled 0.4ht rotated +35;
-       z1=(0.0wd,+0.2ht);
-       z2=(0.2wd,-0.2ht);
-       z3=(0.4wd,+0.2ht);
-       z4=(0.6wd,-0.2ht);
-       z5=(0.8wd,+0.2ht);
-       z6=(1.6wd,-1.4ht);
-       draw z1 -- z2 -- z3 -- z4 -- z5 -- z6;
-fet_endchar;
-
-fet_endgroup("custodes");
-define_pixels(black_notehead_width);
-
+def custos_mensural (expr verbose_name, internal_name, 
+                         direction, staffline_adjustment) =
+       fet_beginchar (verbose_name, internal_name);
+               save alpha, dalpha, ht, wd, stem_ht;
+
+               ht# = noteheight#;
+               wd# / ht# = 1.2;
+               alpha = 35;
+               dalpha = direction * alpha;
+
+               if staffline_adjustment = between_staff_lines:
+                       stem_ht# = 2.00 staff_space#;
+               elseif staffline_adjustment = on_staff_line:
+                       stem_ht# = 2.50 staff_space#;
+               else: % staffline_adjustment = anywhere
+                       stem_ht# = 2.25 staff_space#;
+               fi;
+
+               define_pixels (ht, wd, stem_ht);
+
+               save ellipse, T;
+               path ellipse;
+               transform T;
+
+               T := identity xscaled linethickness
+                             yscaled 0.4 ht
+                             rotated -dalpha;
+               pickup pencircle transformed T;
+               ellipse := fullcircle transformed T;
+
+               if direction > 0:
+                       bot y1 = bot y3 = bot y5 = -direction * 0.33 ht;
+                       top y2 = top y4 = +direction * 0.33 ht;
+               else:
+                       top y1 = top y3 = top y5 = -direction * 0.33 ht;
+                       bot y2 = bot y4 = +direction * 0.33 ht;
+               fi;
+
+               lft x1 = 0.0 wd;
+               lft x2 = 0.2 wd;
+               lft x3 = 0.4 wd;
+               lft x4 = 0.6 wd;
+               lft x5 = 0.8 wd;
+
+               y6 - y5 = direction * stem_ht;
+               y6 - y5 = (x6 - x5) * tand (90 - dalpha);
+
+               if direction > 0:
+                       fill get_subpath (ellipse, z1 - z2, z2 - z1, z1)
+                            -- get_subpoint (ellipse, z2 - z1, z2)
+                            -- get_subpoint (ellipse, z3 - z2, z2)
+                            -- get_subpath (ellipse, z3 - z2, z4 - z3, z3)
+                            -- get_subpoint (ellipse, z4 - z3, z4)
+                            -- get_subpoint (ellipse, z5 - z4, z4)
+                            -- get_subpath (ellipse, z5 - z4, z6 - z5, z5)
+                            -- get_subpath (ellipse, z6 - z5, z5 - z6, z6)
+                            -- get_subpoint (ellipse, z5 - z6, z5)
+                            -- get_subpoint (ellipse, z4 - z5, z5)
+                            -- get_subpath (ellipse, z4 - z5, z3 - z4, z4)
+                            -- get_subpoint (ellipse, z3 - z4, z3)
+                            -- get_subpoint (ellipse, z2 - z3, z3)
+                            -- get_subpath (ellipse, z2 - z3, z1 - z2, z2)
+                            -- cycle;
+               else:
+                       fill get_subpath (ellipse, z1 - z2, z2 - z1, z1)
+                            -- get_subpath (ellipse, z2 -z1, z3 - z2, z2)
+                            -- get_subpoint (ellipse, z3 - z2, z3)
+                            -- get_subpoint (ellipse, z4 - z3, z3)
+                            -- get_subpath (ellipse, z4 -z3, z5 - z4, z4)
+                            -- get_subpoint (ellipse, z5 - z4, z5)
+                            -- get_subpoint (ellipse, z6 - z5, z5)
+                            -- get_subpath (ellipse, z6 - z5, z5 - z6, z6)
+                            -- get_subpath (ellipse, z5 - z6, z4 - z5, z5)
+                            -- get_subpoint (ellipse, z4 - z5, z4)
+                            -- get_subpoint (ellipse, z3 - z4, z4)
+                            -- get_subpath (ellipse, z3 - z4, z2 - z3, z3)
+                            -- get_subpoint (ellipse, z2 - z3, z2)
+                            -- get_subpoint (ellipse, z1 - z2, z2)
+                            -- cycle;
+               fi;
+
+               % The stem is intentionally outside of the char box.
+               if direction > 0:
+                       set_char_box (0, wd#,
+                                     +direction * 0.33 ht#, stem_ht#);
+               else:
+                       set_char_box (0, wd#,
+                                     stem_ht#, -direction * 0.33 ht#);
+               fi;
+
+               labels (1, 2, 3, 4, 5, 6);
+       fet_endchar;
+enddef;
+
+
+% custos mensural, stem up, between staff lines
+custos_mensural ("Custos Mensural", "mensural.u0", 
+                dir_up, between_staff_lines);
+
+
+% custos mensural, stem up, on staff line
+custos_mensural ("Custos Mensural", "mensural.u1", 
+                dir_up, on_staff_line);
+
+
+% custos mensural, stem up, anywhere
+custos_mensural ("Custos Mensural", "mensural.u2", 
+                dir_up, anywhere);
+
+
+% custos mensural, stem down, between staff lines
+custos_mensural ("Reverse Custos Mensural", "mensural.d0", 
+                dir_down, between_staff_lines);
+
+
+% custos mensural, stem down, on staff line
+custos_mensural ("Reverse Custos Mensural", "mensural.d1", 
+                dir_down, on_staff_line);
+
+
+% custos mensural, stem down, anywhere
+custos_mensural ("Reverse Custos Mensural", "mensural.d2", 
+                dir_down, anywhere);
+
+
+fet_endgroup ("custodes");