]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
Issue 2491: Macro for(UP_and_DOWN) and 3 similar.
[lilypond.git] / lily / spanner.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1996--2012 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 "libc-extension.hh"
21 #include "moment.hh"
22 #include "paper-column.hh"
23 #include "paper-score.hh"
24 #include "pointer-group-interface.hh"
25 #include "stencil.hh"
26 #include "system.hh"
27 #include "warn.hh"
28
29 Grob *
30 Spanner::clone () const
31 {
32   return new Spanner (*this);
33 }
34
35 void
36 Spanner::do_break_processing ()
37 {
38   //break_into_pieces
39   Item *left = spanned_drul_[LEFT];
40   Item *right = spanned_drul_[RIGHT];
41
42   if (!left || !right)
43     return;
44
45   if (get_system () || is_broken ())
46     return;
47
48   if (left == right)
49     {
50       /*
51         If we have a spanner spanning one column, we must break it
52         anyway because it might provide a parent for another item.  */
53       for (LEFT_and_RIGHT (d))
54         {
55           Item *bound = left->find_prebroken_piece (d);
56           if (!bound)
57             programming_error ("no broken bound");
58           else if (bound->get_system ())
59             {
60               Spanner *span = dynamic_cast<Spanner *> (clone ());
61               span->set_bound (LEFT, bound);
62               span->set_bound (RIGHT, bound);
63
64               assert (span->get_system ());
65               span->get_system ()->typeset_grob (span);
66               broken_intos_.push_back (span);
67             }
68         }
69     }
70   else
71     {
72       System *root = get_root_system (this);
73       vector<Item *> break_points = root->broken_col_range (left, right);
74
75       break_points.insert (break_points.begin () + 0, left);
76       break_points.push_back (right);
77
78       Slice parent_rank_slice;
79       parent_rank_slice.set_full ();
80
81       /*
82         Check if our parent in X-direction spans equally wide
83         or wider than we do.
84       */
85       for (int a = X_AXIS; a < NO_AXES; a++)
86         {
87           if (Spanner *parent = dynamic_cast<Spanner *> (get_parent ((Axis)a)))
88             parent_rank_slice.intersect (parent->spanned_rank_interval ());
89         }
90
91       for (vsize i = 1; i < break_points.size (); i++)
92         {
93           Drul_array<Item *> bounds;
94           bounds[LEFT] = break_points[i - 1];
95           bounds[RIGHT] = break_points[i];
96           for (LEFT_and_RIGHT (d))
97             {
98               if (!bounds[d]->get_system ())
99                 bounds[d] = bounds[d]->find_prebroken_piece (- d);
100             }
101
102           if (!bounds[LEFT] || ! bounds[RIGHT])
103             {
104               programming_error ("bounds of this piece aren't breakable. ");
105               continue;
106             }
107
108           bool ok = parent_rank_slice.contains (bounds[LEFT]->get_column ()->get_rank ());
109           ok = ok && parent_rank_slice.contains (bounds[RIGHT]->get_column ()->get_rank ());
110
111           if (!ok)
112             {
113               programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner. Ignoring orphaned part",
114                                             name ().c_str ()));
115               continue;
116             }
117
118           Spanner *span = dynamic_cast<Spanner *> (clone ());
119           span->set_bound (LEFT, bounds[LEFT]);
120           span->set_bound (RIGHT, bounds[RIGHT]);
121
122           if (!bounds[LEFT]->get_system ()
123               || !bounds[RIGHT]->get_system ()
124               || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
125             {
126               programming_error ("bounds of spanner are invalid");
127               span->suicide ();
128             }
129           else
130             {
131               bounds[LEFT]->get_system ()->typeset_grob (span);
132               broken_intos_.push_back (span);
133             }
134         }
135     }
136   vector_sort (broken_intos_, Spanner::less);
137   for (vsize i = broken_intos_.size (); i--;)
138     broken_intos_[i]->break_index_ = i;
139 }
140
141 vsize
142 Spanner::get_break_index () const
143 {
144   return break_index_;
145 }
146
147 void
148 Spanner::set_my_columns ()
149 {
150   for (LEFT_and_RIGHT (d))
151     {
152       if (!spanned_drul_[d]->get_system ())
153         set_bound (d, spanned_drul_[d]->find_prebroken_piece ((Direction) - d));
154     }
155 }
156
157 Interval_t<int>
158 Spanner::spanned_rank_interval () const
159 {
160   Interval_t<int> iv (0, 0);
161
162   if (spanned_drul_[LEFT] && spanned_drul_[LEFT]->get_column ())
163     iv[LEFT] = spanned_drul_[LEFT]->get_column ()->get_rank ();
164   if (spanned_drul_[RIGHT] && spanned_drul_[RIGHT]->get_column ())
165     iv[RIGHT] = spanned_drul_[RIGHT]->get_column ()->get_rank ();
166   return iv;
167 }
168
169 Interval_t<Moment>
170 Spanner::spanned_time () const
171 {
172   return spanned_time_interval (spanned_drul_[LEFT],
173                                 spanned_drul_[RIGHT]);
174 }
175
176 Item *
177 Spanner::get_bound (Direction d) const
178 {
179   return spanned_drul_[d];
180 }
181
182 /*
183   Set the items that this spanner spans. If D == LEFT, we also set the
184   X-axis parent of THIS to S.
185 */
186 void
187 Spanner::set_bound (Direction d, Grob *s)
188 {
189   Item *i = dynamic_cast<Item *> (s);
190   if (!i)
191     {
192       programming_error ("must have Item for spanner bound of " + name ());
193       return;
194     }
195
196   spanned_drul_[d] = i;
197
198   /**
199      We check for System to prevent the column -> line_of_score
200      -> column -> line_of_score -> etc situation */
201   if (d == LEFT && !dynamic_cast<System *> (this))
202     set_parent (i, X_AXIS);
203
204   /*
205     Signal that this column needs to be kept alive. They need to be
206     kept alive to have meaningful position and linebreaking.
207
208     [maybe we should try keeping all columns alive?, and perhaps
209     inherit position from their (non-)musical brother]
210   */
211   if (dynamic_cast<Paper_column *> (i))
212     Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
213 }
214
215 Spanner::Spanner (SCM s)
216   : Grob (s)
217 {
218   break_index_ = 0;
219   spanned_drul_.set (0, 0);
220   pure_property_cache_ = SCM_UNDEFINED;
221 }
222
223 Spanner::Spanner (Spanner const &s)
224   : Grob (s)
225 {
226   spanned_drul_.set (0, 0);
227   pure_property_cache_ = SCM_UNDEFINED;
228 }
229
230 /*
231   Certain spanners have pre-computed X values that lie either in
232   X-positions or the X key of the alists returned for left-bound-info
233   and right-bound-info.  These are calculated to give the real length
234   of a spanner (which, because of various padding or overhang properties,
235   can extend pass or arrive short of a given bound).  If possible, we
236   use these to calculate the spanner's length, and otherwise, we use
237   the bound.
238
239   For those writing a new spanner, DO NOT use both X-positions and
240   left-bound-info/right-bound-info.
241 */
242 Real
243 Spanner::spanner_length () const
244 {
245   Interval lr = robust_scm2interval (get_property ("X-positions"),
246                                      Interval (1, -1));
247
248   if (lr.is_empty ())
249     {
250       Drul_array<SCM> bounds (get_property ("left-bound-info"),
251                               get_property ("right-bound-info"));
252
253       for (LEFT_and_RIGHT (d))
254         lr[d] = robust_scm2double (ly_assoc_get (ly_symbol2scm ("X"),
255                                                  bounds[d], SCM_BOOL_F), -d);
256     }
257
258   if (lr.is_empty ())
259     {
260       for (LEFT_and_RIGHT (d))
261         lr[d] = spanned_drul_[d]->relative_coordinate (0, X_AXIS);
262     }
263
264   if (lr.is_empty ())
265     programming_error ("spanner with negative length");
266
267   return lr.length ();
268 }
269
270 System *
271 Spanner::get_system () const
272 {
273   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
274     return 0;
275   if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
276     return 0;
277   return spanned_drul_[LEFT]->get_system ();
278 }
279
280 Grob *
281 Spanner::find_broken_piece (System *l) const
282 {
283   vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
284   if (idx != VPOS)
285     return broken_intos_ [idx];
286   return 0;
287 }
288
289 Spanner *
290 Spanner::broken_neighbor (Direction d) const
291 {
292   if (!original_)
293     return 0;
294
295   vsize k = get_break_index ();
296   Spanner *orig = dynamic_cast<Spanner *> (original_);
297   int j = int (k) + d;
298   if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
299     return 0;
300
301   return orig->broken_intos_[j];
302 }
303
304 int
305 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
306 {
307   return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
308 }
309
310 bool
311 Spanner::less (Spanner *const &a, Spanner *const &b)
312 {
313   return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
314 }
315
316 bool
317 Spanner::is_broken () const
318 {
319   return broken_intos_.size ();
320 }
321
322 /*
323   If this is a broken spanner, return the amount the left end is to be
324   shifted horizontally so that the spanner starts after the initial
325   clef and key on the staves. This is necessary for ties, slurs,
326   crescendo and decrescendo signs, for example.
327 */
328 Real
329 Spanner::get_broken_left_end_align () const
330 {
331   Paper_column *sc = dynamic_cast<Paper_column *> (spanned_drul_[LEFT]->get_column ());
332
333   // Relevant only if left span point is first column in line
334   if (sc != NULL
335       && sc->break_status_dir () == RIGHT)
336     {
337       /*
338         We used to do a full search for the Break_align_item.
339         But that doesn't make a difference, since the Paper_column
340         is likely to contain only a Break_align_item.
341       */
342       return sc->extent (sc, X_AXIS)[RIGHT];
343     }
344
345   return 0.0;
346 }
347
348 void
349 Spanner::derived_mark () const
350 {
351   scm_gc_mark (pure_property_cache_);
352
353   for (LEFT_and_RIGHT (d))
354     if (spanned_drul_[d])
355       scm_gc_mark (spanned_drul_[d]->self_scm ());
356     ;
357
358   for (vsize i = broken_intos_.size (); i--;)
359     scm_gc_mark (broken_intos_[i]->self_scm ());
360 }
361
362 /*
363   Set left or right bound to IT.
364
365   Warning: caller should ensure that subsequent calls put in ITems
366   that are left-to-right ordered.
367 */
368 void
369 add_bound_item (Spanner *sp, Grob *it)
370 {
371   if (!sp->get_bound (LEFT))
372     sp->set_bound (LEFT, it);
373   else
374     sp->set_bound (RIGHT, it);
375 }
376
377 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
378 SCM
379 Spanner::set_spacing_rods (SCM smob)
380 {
381   Grob *me = unsmob_grob (smob);
382   SCM num_length = me->get_property ("minimum-length");
383   if (scm_is_number (num_length))
384     {
385       Rod r;
386       Spanner *sp = dynamic_cast<Spanner *> (me);
387       System *root = get_root_system (me);
388       Drul_array<Item *> bounds (sp->get_bound (LEFT),
389                                  sp->get_bound (RIGHT));
390       if (!bounds[LEFT] || !bounds[RIGHT])
391         return SCM_UNSPECIFIED;
392
393       vector<Item *> cols (root->broken_col_range (bounds[LEFT]->get_column (),
394                                                    bounds[RIGHT]->get_column ()));
395
396       if (cols.size ())
397         {
398           Rod r;
399           r.item_drul_[LEFT] = sp->get_bound (LEFT);
400           r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
401           r.distance_ = robust_scm2double (num_length, 0);
402           r.add_to_cols ();
403
404           r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
405           r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
406           r.add_to_cols ();
407         }
408
409       r.distance_ = robust_scm2double (num_length, 0);
410       r.item_drul_[LEFT] = sp->get_bound (LEFT);
411       r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
412       r.add_to_cols ();
413     }
414
415   return SCM_UNSPECIFIED;
416 }
417
418 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
419 SCM
420 Spanner::calc_normalized_endpoints (SCM smob)
421 {
422   Spanner *me = unsmob_spanner (smob);
423   SCM result = SCM_EOL;
424
425   Spanner *orig = dynamic_cast<Spanner *> (me->original ());
426
427   orig = orig ? orig : me;
428
429   if (orig->is_broken ())
430     {
431       Real total_width = 0.0;
432       vector<Real> span_data;
433
434       if (!orig->is_broken ())
435         span_data.push_back (orig->spanner_length ());
436       else
437         for (vsize i = 0; i < orig->broken_intos_.size (); i++)
438           span_data.push_back (orig->broken_intos_[i]->spanner_length ());
439
440       vector<Interval> unnormalized_endpoints;
441
442       for (vsize i = 0; i < span_data.size (); i++)
443         {
444           unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
445           total_width += span_data[i];
446         }
447
448       for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
449         {
450           SCM t = ly_interval2scm (1 / total_width * unnormalized_endpoints[i]);
451           orig->broken_intos_[i]->set_property ("normalized-endpoints", t);
452           if (me->get_break_index () == i)
453             result = t;
454         }
455     }
456   else
457     {
458       result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
459       orig->set_property ("normalized-endpoints", result);
460     }
461
462   return result;
463 }
464
465 Spanner *
466 unsmob_spanner (SCM s)
467 {
468   return dynamic_cast<Spanner *> (unsmob_grob (s));
469 }
470
471 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
472 SCM
473 Spanner::bounds_width (SCM grob)
474 {
475   Spanner *me = unsmob_spanner (grob);
476
477   Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
478
479   Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
480               me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
481
482   w -= me->relative_coordinate (common, X_AXIS);
483
484   return ly_interval2scm (w);
485 }
486
487 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
488 SCM
489 Spanner::kill_zero_spanned_time (SCM grob)
490 {
491   Spanner *me = unsmob_spanner (grob);
492   /*
493     Remove the line or hairpin at the start of the line.  For
494     piano voice indicators, it makes no sense to have them at
495     the start of the line.
496
497     I'm not sure what the official rules for glissandi are, but
498     usually the 2nd note of the glissando is "exact", so when playing
499     from the start of the line, there is no need to glide.
500
501     From a typographical p.o.v. this makes sense, since the amount of
502     space left of a note at the start of a line is very small.
503
504     --hwn.
505
506   */
507   if (me->get_bound (LEFT)->break_status_dir ())
508     {
509       Interval_t<Moment> moments = me->spanned_time ();
510       moments [LEFT].grace_part_ = 0;
511       if (moments.length () == Moment (0, 0))
512         me->suicide ();
513     }
514
515   return SCM_UNSPECIFIED;
516 }
517
518 SCM
519 Spanner::get_cached_pure_property (SCM sym, int start, int end)
520 {
521   // The pure property cache is indexed by (name start . end), where name is
522   // a symbol, and start and end are numbers referring to the starting and
523   // ending column ranks of the current line.
524   if (scm_hash_table_p (pure_property_cache_) == SCM_BOOL_F)
525     return SCM_UNDEFINED;
526
527   SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
528   return scm_hash_ref (pure_property_cache_, key, SCM_UNDEFINED);
529 }
530
531 void
532 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
533 {
534   if (scm_hash_table_p (pure_property_cache_) == SCM_BOOL_F)
535     pure_property_cache_ = scm_c_make_hash_table (17);
536
537   SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
538   scm_hash_set_x (pure_property_cache_, key, val);
539 }
540
541 ADD_INTERFACE (Spanner,
542                "Some objects are horizontally spanned between objects.  For"
543                " example, slurs, beams, ties, etc.  These grobs form a subtype"
544                " called @code{Spanner}.  All spanners have two span points"
545                " (these must be @code{Item} objects), one on the left and one"
546                " on the right.  The left bound is also the X@tie{}reference"
547                " point of the spanner.",
548
549                /* properties */
550                "normalized-endpoints "
551                "minimum-length "
552                "spanner-broken "
553                "spanner-id "
554                "to-barline "
555               );