]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
e0e1c18e1d09f6a9ae59afffc78646fa571ea906
[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."
114                                             "  Ignoring orphaned part",
115                                             name ().c_str ()));
116               continue;
117             }
118
119           Spanner *span = dynamic_cast<Spanner *> (clone ());
120           span->set_bound (LEFT, bounds[LEFT]);
121           span->set_bound (RIGHT, bounds[RIGHT]);
122
123           if (!bounds[LEFT]->get_system ()
124               || !bounds[RIGHT]->get_system ()
125               || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
126             {
127               programming_error ("bounds of spanner are invalid");
128               span->suicide ();
129             }
130           else
131             {
132               bounds[LEFT]->get_system ()->typeset_grob (span);
133               broken_intos_.push_back (span);
134             }
135         }
136     }
137   vector_sort (broken_intos_, Spanner::less);
138   for (vsize i = broken_intos_.size (); i--;)
139     broken_intos_[i]->break_index_ = i;
140 }
141
142 vsize
143 Spanner::get_break_index () const
144 {
145   return break_index_;
146 }
147
148 void
149 Spanner::set_my_columns ()
150 {
151   for (LEFT_and_RIGHT (d))
152     {
153       if (!spanned_drul_[d]->get_system ())
154         set_bound (d, spanned_drul_[d]->find_prebroken_piece ((Direction) - d));
155     }
156 }
157
158 Interval_t<int>
159 Spanner::spanned_rank_interval () const
160 {
161   Interval_t<int> iv (0, 0);
162
163   if (spanned_drul_[LEFT] && spanned_drul_[LEFT]->get_column ())
164     iv[LEFT] = spanned_drul_[LEFT]->get_column ()->get_rank ();
165   if (spanned_drul_[RIGHT] && spanned_drul_[RIGHT]->get_column ())
166     iv[RIGHT] = spanned_drul_[RIGHT]->get_column ()->get_rank ();
167   return iv;
168 }
169
170 Interval_t<Moment>
171 Spanner::spanned_time () const
172 {
173   return spanned_time_interval (spanned_drul_[LEFT],
174                                 spanned_drul_[RIGHT]);
175 }
176
177 Item *
178 Spanner::get_bound (Direction d) const
179 {
180   return spanned_drul_[d];
181 }
182
183 /*
184   Set the items that this spanner spans. If D == LEFT, we also set the
185   X-axis parent of THIS to S.
186 */
187 void
188 Spanner::set_bound (Direction d, Grob *s)
189 {
190   Item *i = dynamic_cast<Item *> (s);
191   if (!i)
192     {
193       programming_error ("must have Item for spanner bound of " + name ());
194       return;
195     }
196
197   spanned_drul_[d] = i;
198
199   /**
200      We check for System to prevent the column -> line_of_score
201      -> column -> line_of_score -> etc situation */
202   if (d == LEFT && !dynamic_cast<System *> (this))
203     set_parent (i, X_AXIS);
204
205   /*
206     Signal that this column needs to be kept alive. They need to be
207     kept alive to have meaningful position and linebreaking.
208
209     [maybe we should try keeping all columns alive?, and perhaps
210     inherit position from their (non-)musical brother]
211   */
212   if (dynamic_cast<Paper_column *> (i))
213     Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
214 }
215
216 Spanner::Spanner (SCM s)
217   : Grob (s)
218 {
219   break_index_ = 0;
220   spanned_drul_.set (0, 0);
221   pure_property_cache_ = SCM_UNDEFINED;
222 }
223
224 Spanner::Spanner (Spanner const &s)
225   : Grob (s)
226 {
227   spanned_drul_.set (0, 0);
228   pure_property_cache_ = SCM_UNDEFINED;
229 }
230
231 /*
232   Certain spanners have pre-computed X values that lie either in
233   X-positions or the X key of the alists returned for left-bound-info
234   and right-bound-info.  These are calculated to give the real length
235   of a spanner (which, because of various padding or overhang properties,
236   can extend pass or arrive short of a given bound).  If possible, we
237   use these to calculate the spanner's length, and otherwise, we use
238   the bound.
239
240   For those writing a new spanner, DO NOT use both X-positions and
241   left-bound-info/right-bound-info.
242 */
243 Real
244 Spanner::spanner_length () const
245 {
246   Interval lr = robust_scm2interval (get_property ("X-positions"),
247                                      Interval (1, -1));
248
249   if (lr.is_empty ())
250     {
251       Drul_array<SCM> bounds (get_property ("left-bound-info"),
252                               get_property ("right-bound-info"));
253
254       for (LEFT_and_RIGHT (d))
255         lr[d] = robust_scm2double (ly_assoc_get (ly_symbol2scm ("X"),
256                                                  bounds[d], SCM_BOOL_F), -d);
257     }
258
259   if (lr.is_empty ())
260     {
261       for (LEFT_and_RIGHT (d))
262         lr[d] = spanned_drul_[d]->relative_coordinate (0, X_AXIS);
263     }
264
265   if (lr.is_empty ())
266     programming_error ("spanner with negative length");
267
268   return lr.length ();
269 }
270
271 System *
272 Spanner::get_system () const
273 {
274   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
275     return 0;
276   if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
277     return 0;
278   return spanned_drul_[LEFT]->get_system ();
279 }
280
281 Grob *
282 Spanner::find_broken_piece (System *l) const
283 {
284   vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
285   if (idx != VPOS)
286     return broken_intos_ [idx];
287   return 0;
288 }
289
290 Spanner *
291 Spanner::broken_neighbor (Direction d) const
292 {
293   if (!original_)
294     return 0;
295
296   vsize k = get_break_index ();
297   Spanner *orig = dynamic_cast<Spanner *> (original_);
298   int j = int (k) + d;
299   if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
300     return 0;
301
302   return orig->broken_intos_[j];
303 }
304
305 int
306 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
307 {
308   return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
309 }
310
311 bool
312 Spanner::less (Spanner *const &a, Spanner *const &b)
313 {
314   return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
315 }
316
317 bool
318 Spanner::is_broken () const
319 {
320   return broken_intos_.size ();
321 }
322
323 void
324 Spanner::derived_mark () const
325 {
326   scm_gc_mark (pure_property_cache_);
327
328   for (LEFT_and_RIGHT (d))
329     if (spanned_drul_[d])
330       scm_gc_mark (spanned_drul_[d]->self_scm ());
331   ;
332
333   for (vsize i = broken_intos_.size (); i--;)
334     scm_gc_mark (broken_intos_[i]->self_scm ());
335 }
336
337 /*
338   Set left or right bound to IT.
339
340   Warning: caller should ensure that subsequent calls put in ITems
341   that are left-to-right ordered.
342 */
343 void
344 add_bound_item (Spanner *sp, Grob *it)
345 {
346   if (!sp->get_bound (LEFT))
347     sp->set_bound (LEFT, it);
348   else
349     sp->set_bound (RIGHT, it);
350 }
351
352 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
353 SCM
354 Spanner::set_spacing_rods (SCM smob)
355 {
356   Grob *me = unsmob_grob (smob);
357   SCM num_length = me->get_property ("minimum-length");
358   if (scm_is_number (num_length))
359     {
360       Rod r;
361       Spanner *sp = dynamic_cast<Spanner *> (me);
362       System *root = get_root_system (me);
363       Drul_array<Item *> bounds (sp->get_bound (LEFT),
364                                  sp->get_bound (RIGHT));
365       if (!bounds[LEFT] || !bounds[RIGHT])
366         return SCM_UNSPECIFIED;
367
368       vector<Item *> cols (root->broken_col_range (bounds[LEFT]->get_column (),
369                                                    bounds[RIGHT]->get_column ()));
370
371       if (cols.size ())
372         {
373           Rod r;
374           r.item_drul_[LEFT] = sp->get_bound (LEFT);
375           r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
376           r.distance_ = robust_scm2double (num_length, 0);
377           r.add_to_cols ();
378
379           r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
380           r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
381           r.add_to_cols ();
382         }
383
384       r.distance_ = robust_scm2double (num_length, 0);
385       r.item_drul_[LEFT] = sp->get_bound (LEFT);
386       r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
387       r.add_to_cols ();
388
389       /*
390         We do not know yet if the spanner is going to have a bound that is
391         broken. To account for this uncertainty, we add the rod twice:
392         once for the central column (see above) and once for the left column
393         (see below). As end_rods_ are never used when rods_ are used and vice
394         versa, this rod will only be accessed once for each spacing
395         configuraiton before line breaking. Then, as a grob never exists in
396         both unbroken and broken forms after line breaking, only one of these
397         two rods will be in the column vector used for spacing in
398         simple-spacer.cc get_line_confugration.
399       */
400       if (Item *left_pbp = sp->get_bound (RIGHT)->find_prebroken_piece (LEFT))
401         {
402           r.item_drul_[RIGHT] = left_pbp;
403           r.add_to_cols ();
404         }
405     }
406
407   return SCM_UNSPECIFIED;
408 }
409
410 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
411 SCM
412 Spanner::calc_normalized_endpoints (SCM smob)
413 {
414   Spanner *me = unsmob_spanner (smob);
415   SCM result = SCM_EOL;
416
417   Spanner *orig = dynamic_cast<Spanner *> (me->original ());
418
419   orig = orig ? orig : me;
420
421   if (orig->is_broken ())
422     {
423       Real total_width = 0.0;
424       vector<Real> span_data;
425
426       if (!orig->is_broken ())
427         span_data.push_back (orig->spanner_length ());
428       else
429         for (vsize i = 0; i < orig->broken_intos_.size (); i++)
430           span_data.push_back (orig->broken_intos_[i]->spanner_length ());
431
432       vector<Interval> unnormalized_endpoints;
433
434       for (vsize i = 0; i < span_data.size (); i++)
435         {
436           unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
437           total_width += span_data[i];
438         }
439
440       for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
441         {
442           SCM t = ly_interval2scm (1 / total_width * unnormalized_endpoints[i]);
443           orig->broken_intos_[i]->set_property ("normalized-endpoints", t);
444           if (me->get_break_index () == i)
445             result = t;
446         }
447     }
448   else
449     {
450       result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
451       orig->set_property ("normalized-endpoints", result);
452     }
453
454   return result;
455 }
456
457 Spanner *
458 unsmob_spanner (SCM s)
459 {
460   return dynamic_cast<Spanner *> (unsmob_grob (s));
461 }
462
463 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
464 SCM
465 Spanner::bounds_width (SCM grob)
466 {
467   Spanner *me = unsmob_spanner (grob);
468
469   Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
470
471   Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
472               me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
473
474   w -= me->relative_coordinate (common, X_AXIS);
475
476   return ly_interval2scm (w);
477 }
478
479 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
480 SCM
481 Spanner::kill_zero_spanned_time (SCM grob)
482 {
483   Spanner *me = unsmob_spanner (grob);
484   /*
485     Remove the line or hairpin at the start of the line.  For
486     piano voice indicators, it makes no sense to have them at
487     the start of the line.
488
489     I'm not sure what the official rules for glissandi are, but
490     usually the 2nd note of the glissando is "exact", so when playing
491     from the start of the line, there is no need to glide.
492
493     From a typographical p.o.v. this makes sense, since the amount of
494     space left of a note at the start of a line is very small.
495
496     --hwn.
497
498   */
499   if (me->get_bound (LEFT)->break_status_dir ())
500     {
501       Interval_t<Moment> moments = me->spanned_time ();
502       moments [LEFT].grace_part_ = 0;
503       if (moments.length () == Moment (0, 0))
504         me->suicide ();
505     }
506
507   return SCM_UNSPECIFIED;
508 }
509
510 SCM
511 Spanner::get_cached_pure_property (SCM sym, int start, int end)
512 {
513   // The pure property cache is indexed by (name start . end), where name is
514   // a symbol, and start and end are numbers referring to the starting and
515   // ending column ranks of the current line.
516   if (scm_hash_table_p (pure_property_cache_) == SCM_BOOL_F)
517     return SCM_UNDEFINED;
518
519   SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
520   return scm_hash_ref (pure_property_cache_, key, SCM_UNDEFINED);
521 }
522
523 void
524 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
525 {
526   if (scm_hash_table_p (pure_property_cache_) == SCM_BOOL_F)
527     pure_property_cache_ = scm_c_make_hash_table (17);
528
529   SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
530   scm_hash_set_x (pure_property_cache_, key, val);
531 }
532
533 ADD_INTERFACE (Spanner,
534                "Some objects are horizontally spanned between objects.  For"
535                " example, slurs, beams, ties, etc.  These grobs form a subtype"
536                " called @code{Spanner}.  All spanners have two span points"
537                " (these must be @code{Item} objects), one on the left and one"
538                " on the right.  The left bound is also the X@tie{}reference"
539                " point of the spanner.",
540
541                /* properties */
542                "normalized-endpoints "
543                "minimum-length "
544                "spanner-broken "
545                "spanner-id "
546                "to-barline "
547               );