]> git.donarmstrong.com Git - lilypond.git/blob - lily/rest.cc
Web-ja: update introduction
[lilypond.git] / lily / rest.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "rest.hh"
21
22 #include "directional-element-interface.hh"
23 #include "dots.hh"
24 #include "font-interface.hh"
25 #include "international.hh"
26 #include "output-def.hh"
27 #include "paper-score.hh"
28 #include "staff-symbol-referencer.hh"
29 #include "staff-symbol.hh"
30 #include "stencil.hh"
31 #include "grob.hh"
32
33 // -> offset callback
34 MAKE_SCHEME_CALLBACK (Rest, y_offset_callback, 1);
35 SCM
36 Rest::y_offset_callback (SCM smob)
37 {
38   Grob *me = unsmob<Grob> (smob);
39   int duration_log = scm_to_int (me->get_property ("duration-log"));
40   Real ss = Staff_symbol_referencer::staff_space (me);
41
42   return scm_from_double (ss * 0.5 * Rest::staff_position_internal (me, duration_log, get_grob_direction (me)));
43 }
44
45 Real
46 Rest::staff_position_internal (Grob *me, int duration_log, int dir)
47 {
48   if (!me)
49     return 0;
50
51   bool position_override = scm_is_number (me->get_property ("staff-position"));
52   Real pos;
53
54   if (position_override)
55     {
56       pos
57         = robust_scm2double (me->get_property ("staff-position"), 0);
58
59       /*
60         semibreve rests are positioned one staff line off
61       */
62       if (duration_log == 0)
63         return pos + 2;
64
65       /*
66         trust the client on good positioning;
67         would be tempting to adjust position of rests longer than a quarter
68         to be properly aligned to staff lines,
69         but custom rest shapes may not need that sort of care.
70       */
71
72       return pos;
73     }
74
75   Real vpos = dir * robust_scm2int (me->get_property ("voiced-position"), 0);
76   pos = vpos;
77
78   if (duration_log > 1)
79     /* Only half notes or longer want alignment with staff lines */
80     return pos;
81
82   /*
83     We need a staff symbol for actually aligning anything
84   */
85   Grob *staff = Staff_symbol_referencer::get_staff_symbol (me);
86   if (!staff)
87     return pos;
88
89   std::vector<Real> linepos = Staff_symbol::line_positions (staff);
90
91   if (linepos.empty ())
92     return pos;
93
94   std::sort (linepos.begin (), linepos.end ());
95
96   if (duration_log == 0)
97     {
98       /*
99         lower voice semibreve rests generally hang a line lower
100       */
101
102       if (dir < 0)
103         pos -= 2;
104
105       /*
106         make a semibreve rest hang from the next available line,
107         except when there is none.
108       */
109
110       std::vector<Real>::const_iterator it
111         = std::upper_bound (linepos.begin (), linepos.end (), pos);
112       if (it != linepos.end ())
113         pos = *it;
114       else
115         pos = linepos.back ();
116     }
117   else
118     {
119       std::vector<Real>::const_iterator it
120         = std::upper_bound (linepos.begin (), linepos.end (), pos);
121       if (it != linepos.begin ())
122         --it;
123       pos = *it;
124     }
125
126   /* Finished for neutral position */
127   if (!dir)
128     return pos;
129
130   /* If we have a voiced position, make sure that it's on the
131      proper side of neutral before using it.
132   */
133
134   Real neutral = staff_position_internal (me, duration_log, 0);
135
136   if (dir * (pos - neutral) > 0)
137     return pos;
138   else
139     return neutral + vpos;
140 }
141
142 /* A rest might lie under a beam, in which case it should be cross-staff if
143    the beam is cross-staff because the rest's position depends on the
144    formatting of the beam. */
145 MAKE_SCHEME_CALLBACK (Rest, calc_cross_staff, 1);
146 SCM
147 Rest::calc_cross_staff (SCM smob)
148 {
149   Grob *me = unsmob<Grob> (smob);
150   Grob *stem = unsmob<Grob> (me->get_object ("stem"));
151
152   if (!stem)
153     return SCM_BOOL_F;
154
155   return stem->get_property ("cross-staff");
156 }
157
158 /*
159   make this function easily usable in C++
160 */
161 string
162 Rest::glyph_name (Grob *me, int durlog, const string &style, bool try_ledgers,
163                   Real offset)
164 {
165   bool is_ledgered = false;
166   if (try_ledgers && (durlog == -1 || durlog == 0 || durlog == 1))
167     {
168       int const pos = int (Staff_symbol_referencer::get_position (me)
169                            + offset);
170       /*
171         half rests need ledger if not lying on a staff line,
172         whole rests need ledger if not hanging from a staff line,
173         breve rests need ledger if neither lying on nor hanging from a staff line
174       */
175       if (-1 <= durlog && durlog <= 1)
176         is_ledgered = !Staff_symbol_referencer::on_staff_line (me, pos)
177                       && !(durlog == -1
178                            && Staff_symbol_referencer::on_staff_line (me, pos + 2));
179     }
180
181   string actual_style (style.c_str ());
182
183   if ((style == "mensural") || (style == "neomensural"))
184     {
185
186       /*
187         FIXME: Currently, ancient font does not provide ledgered rests;
188         hence the "o" suffix in the glyph name is bogus.  But do we need
189         ledgered rests at all now that we can draw ledger lines with
190         variable width, length and blotdiameter? -- jr
191       */
192       is_ledgered = 0;
193
194       /*
195         There are no 32th/64th/128th mensural/neomensural rests.  In
196         these cases, revert back to default style.
197       */
198       if (durlog > 4)
199         actual_style = "";
200     }
201
202   if (((style == "classical") || (style == "z")) && (durlog != 2))
203     {
204       /*
205         these styles differ from the default in quarter rests only
206       */
207       actual_style = "";
208     }
209
210   if (style == "default")
211     {
212       /*
213         Some parts of lily still prefer style "default" over "".
214         Correct this here. -- jr
215       */
216       actual_style = "";
217     }
218
219   return ("rests." + ::to_string (durlog) + (is_ledgered ? "o" : "")
220           + actual_style);
221 }
222
223 MAKE_SCHEME_CALLBACK (Rest, print, 1);
224 SCM
225 Rest::brew_internal_stencil (Grob *me, bool ledgered)
226 {
227   SCM durlog_scm = me->get_property ("duration-log");
228   if (!scm_is_number (durlog_scm))
229     return Stencil ().smobbed_copy ();
230
231   int durlog = scm_to_int (durlog_scm);
232
233   string style = robust_symbol2string (me->get_property ("style"), "default");
234
235   Font_metric *fm = Font_interface::get_default_font (me);
236   string font_char = glyph_name (me, durlog, style, ledgered, 0.0);
237   Stencil out = fm->find_by_name (font_char);
238   if (out.is_empty ())
239     me->warning (_f ("rest `%s' not found", font_char.c_str ()));
240
241   return out.smobbed_copy ();
242 }
243
244 /**
245    translate the rest vertically by amount DY, but only if
246    it doesn't have staff-position set.
247 */
248 void
249 Rest::translate (Grob *me, int dy)
250 {
251   if (!scm_is_number (me->get_property ("staff-position")))
252     {
253       me->translate_axis (dy * Staff_symbol_referencer::staff_space (me) / 2.0, Y_AXIS);
254       Grob *p = me->get_parent (Y_AXIS);
255       p->flush_extent_cache (Y_AXIS);
256     }
257 }
258
259 SCM
260 Rest::print (SCM smob)
261 {
262   return brew_internal_stencil (unsmob<Grob> (smob), true);
263 }
264
265 MAKE_SCHEME_CALLBACK (Rest, width, 1);
266 /*
267   We need the callback. The real stencil has ledgers depending on
268   Y-position. The Y-position is known only after line breaking.  */
269 SCM
270 Rest::width (SCM smob)
271 {
272   return generic_extent_callback (unsmob<Grob> (smob), X_AXIS);
273 }
274
275 MAKE_SCHEME_CALLBACK (Rest, height, 1);
276 SCM
277 Rest::height (SCM smob)
278 {
279   return generic_extent_callback (unsmob<Grob> (smob), Y_AXIS);
280 }
281
282 /*
283   We need the callback. The real stencil has ledgers depending on
284   Y-position. The Y-position is known only after line breaking.  */
285 SCM
286 Rest::generic_extent_callback (Grob *me, Axis a)
287 {
288   /*
289     Don't want ledgers: ledgers depend on Y position, which depends on
290     rest collision, which depends on stem size which depends on beam
291     slop of opposite note column.
292
293     consequence: we get too small extents and potential collisions
294     with ledgered rests.
295   */
296   SCM m = brew_internal_stencil (me, a != X_AXIS);
297   return ly_interval2scm (unsmob<Stencil> (m)->extent (a));
298 }
299
300 MAKE_SCHEME_CALLBACK (Rest, pure_height, 3);
301 SCM
302 Rest::pure_height (SCM smob,
303                    SCM /* start */,
304                    SCM /* end */)
305 {
306   Grob *me = unsmob<Grob> (smob);
307   SCM m = brew_internal_stencil (me, false);
308   return ly_interval2scm (unsmob<Stencil> (m)->extent (Y_AXIS));
309 }
310
311 ADD_INTERFACE (Rest,
312                "A rest symbol.  The property @code{style} can be"
313                " @code{default}, @code{mensural}, @code{neomensural} or"
314                " @code{classical}.",
315
316                /* properties */
317                "direction "
318                "minimum-distance "
319                "style "
320                "voiced-position "
321               );