]> git.donarmstrong.com Git - lilypond.git/blob - lily/custos.cc
release: 1.5.47
[lilypond.git] / lily / custos.cc
1 /*
2   custos.cc -- implement Custos
3
4   source file of the GNU LilyPond music typesetter
5
6  (C) 2000, 2002 Juergen Reuter <reuter@ipd.uka.de>
7 */
8
9 /* TODO:
10
11  - merge create_ledger_line () and Note_head::create_ledger_line ()
12
13  - rewrite create_ledger_line () to support short and thin ledger lines
14
15  - do not show if a clef change immediately follows in the next line
16
17  - decide: do or do not print custos if the next line starts with a rest
18
19 */
20
21
22 #include <stdio.h>
23 #include "direction.hh"
24 #include "staff-symbol-referencer.hh"
25 #include "custos.hh"
26 #include "molecule.hh"
27 #include "debug.hh"
28 #include "note-head.hh"
29 #include "item.hh"
30 #include "font-interface.hh"
31 #include "math.h" // rint
32
33 /*
34    This function is a patched and hopefully much more understandable
35    rewrite of Note_head::ledger_line ().  It still has some
36    bugs/limitations:
37  *
38  (1) The term thick/2 probably should be thick*2 (probably a bug,
39    see the code below).
40  *
41  (2) The minimal width of the resulting ledger line equals the width
42    of the noteheads-ledgerending symbol (a limitation):
43  *
44  (---- left ledger ending
45      ----) right ledger ending
46  (---) resulting ledger line (just ok)
47  *
48    If x_extent ("xwid" in Note_head) is less than the width of the
49    ledger ending, the width of the total ledger line is even *greater*
50    than the width of a ledger ending (I would call this a bug).  In
51    the below code, the condition "if (x_extent.length () >
52    slice_x_extent.length ())" avoids outputting the left ending in such
53    cases (rather a silly workaround, but better than nothing).
54  *
55  (---- left ledger ending
56      ----)   right ledger ending
57  (-)   desired ledger line
58      ------- resulting ledger line (too long)
59      ----)   resulting ledger line with additional "if" (still too long)
60  *
61    The algorithm works properly only for a desired ledger line width
62    greater than the width of the ledger ending:
63  *
64  (----    left ledger ending
65         ----) right ledger ending
66  (------) desired ledger line
67  (------) resulting ledger line (ok)
68  *
69  * (3) The thickness of the ledger line is fixed (limitation).
70  */
71 Molecule
72 Custos::create_ledger_line (Interval x_extent, Grob *me) 
73 {
74   Molecule line;
75   Molecule slice = Font_interface::get_default_font (me)->find_by_name ("noteheads-ledgerending");
76   Interval slice_x_extent = slice.extent (X_AXIS);
77   Interval slice_y_extent = slice.extent (Y_AXIS);
78
79   // Create left ending of ledger line.
80   Molecule left_ending = slice;
81   left_ending.translate_axis (x_extent[LEFT] - slice_x_extent[LEFT], X_AXIS);
82   if (x_extent.length () > slice_x_extent.length ())
83     line.add_molecule (left_ending);
84
85   // Create right ending of ledger line.
86   Molecule right_ending = slice;
87   right_ending.translate_axis (x_extent[RIGHT] - slice_x_extent[RIGHT],
88                                X_AXIS);
89   line.add_molecule (right_ending);
90
91   // Fill out space between left and right ending of ledger line by
92   // lining up a series of slices in a row between them.
93   Molecule fill_out_slice = left_ending;
94   Real thick = slice_y_extent.length ();
95   Real delta_x = slice_x_extent.length () - thick;
96   Real xpos = x_extent [LEFT] + 2*delta_x + thick/2; // TODO: check: thick*2?
97   while (xpos <= x_extent[RIGHT])
98     {
99       fill_out_slice.translate_axis (delta_x, X_AXIS);
100       line.add_molecule (fill_out_slice);
101       xpos += delta_x;
102     }
103
104   return line;
105 }
106
107 void
108 Custos::add_streepjes (Grob* me,
109                    int pos,
110                    int interspaces,
111                    Molecule* custos_p_)
112 {
113   // TODO: This is (almost) duplicated code (see
114   // Note_head::brew_molecule).  Junk me.
115   Real inter_f = Staff_symbol_referencer::staff_space (me)/2;
116   int streepjes_i = abs (pos) < interspaces
117     ? 0
118     : (abs (pos) - interspaces) /2;
119   if (streepjes_i) 
120     {
121       Direction dir = (Direction)sign (pos);
122       Molecule ledger_line (create_ledger_line (custos_p_->extent (X_AXIS),
123                                                 me));
124       ledger_line.set_empty (true);
125       Real offs = (Staff_symbol_referencer::on_staffline (me))
126         ? 0.0
127         : -dir * inter_f;
128       for (int i = 0; i < streepjes_i; i++)
129         {
130           Molecule streep (ledger_line);
131           streep.translate_axis (-dir * inter_f * i * 2 + offs,
132                                  Y_AXIS);
133           custos_p_->add_molecule (streep);
134         }
135     }
136 }
137
138 MAKE_SCHEME_CALLBACK (Custos,brew_molecule,1);
139 SCM
140 Custos::brew_molecule (SCM smob)
141 {
142   Item *me = (Item *)unsmob_grob (smob);
143   SCM scm_style = me->get_grob_property ("style");
144
145   if (gh_symbol_p (scm_style))
146     {
147       String style = ly_scm2string (scm_symbol_to_string (scm_style));
148
149       /*
150         DOCME:
151         
152         Why would we want it differently? What's the meaning of adjust ?
153        */
154       bool adjust =
155         to_boolean (me->get_grob_property ("adjust-if-on-staffline"));
156
157       String idx = "custodes-" + style + "-";
158
159       int neutral_pos;
160       SCM ntr_pos = me->get_grob_property ("neutral-position");
161       if (gh_number_p (ntr_pos))
162         neutral_pos = gh_scm2int (ntr_pos);
163       else
164         neutral_pos = 0;
165
166       Direction neutral_direction =
167         to_dir (me->get_grob_property ("neutral-direction"));
168
169       int pos = (int)rint (Staff_symbol_referencer::position_f (me));
170       int sz = Staff_symbol_referencer::line_count (me)-1;
171
172       if (pos < neutral_pos)
173         idx += "u";
174       else if (pos > neutral_pos)
175         idx += "d";
176       else if (neutral_direction == UP)
177         idx += "u";
178       else if (neutral_direction == DOWN)
179         idx += "d";
180       else // auto direction; not yet supported -> use "d"
181         idx += "d";
182
183       if (adjust)
184         {
185           idx += (((pos ^ sz) & 0x1) == 0) ? "1" : "0";
186         }
187       else
188         {
189           idx += "2";
190         }
191
192       Molecule molecule
193         = Font_interface::get_default_font (me)->find_by_name (idx);
194       if (molecule.empty_b ())
195         {
196           String message = "no such custos: `" + idx + "'";
197           warning (_ (message.ch_C ()));
198           return SCM_EOL;
199         }
200       else
201         {
202           add_streepjes (me, (int)pos, sz, &molecule);
203           return  molecule.smobbed_copy ();
204         }
205     }
206   else
207     return SCM_EOL;
208 }
209
210 bool
211 Custos::has_interface (Grob*m)
212 {
213   return m && m->has_interface (ly_symbol2scm ("custos-interface"));
214 }
215
216
217 ADD_INTERFACE (Custos, "custos-interface",
218   "A custos is a staff context symbol that appears at the end of a
219   staff line with monophonic musical contents (i.e. with a single
220   voice).  It anticipates the pitch of the first note of the following
221   line and thus helps the player or singer to manage line breaks
222   during performance, thus enhancing readability of a score.
223
224   Custodes were frequently used in music notation until the 16th
225   century.  There were different appearences for different notation
226   styles.  Nowadays, they have survived only in special forms of
227   musical notation such as via the editio vaticana dating back to the
228   beginning of the 20th century.
229
230 [TODO: add to glossary]",
231   "style adjust-if-on-staffline neutral-position");