]> git.donarmstrong.com Git - lilypond.git/blob - lily/spacing-basic.cc
* lily/tuplet-bracket.cc (after_line_breaking): don't suicide if
[lilypond.git] / lily / spacing-basic.cc
1 /*
2   spacing-basic.cc -- implement Spacing_spanner, simplistic spacing routines
3   
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
7
8 */
9
10 #include "spacing-spanner.hh"
11 #include "moment.hh"
12 #include "paper-column.hh"
13 #include "misc.hh"
14 #include "warn.hh"
15
16 /*
17    LilyPond spaces by taking a simple-minded spacing algorithm, and
18    adding subtle adjustments to that. This file does the simple-minded
19    spacing routines.
20 */
21
22
23 /*
24    Get the measure wide ant for arithmetic spacing.
25 */
26 Real
27 Spacing_options::get_duration_space (Moment d,
28                                      bool *expand_only) const
29 {
30   Real k = shortest_duration_space_;
31
32   if (d < global_shortest_)
33     {
34       /*
35         We don't space really short notes using the log of the
36         duration, since it would disproportionally stretches the long
37         notes in a piece. In stead, we use geometric spacing with constant 0.5
38         (i.e. linear.)
39
40         This should probably be tunable, to use other base numbers.
41
42         In Mozart hrn3 by EB., we have 8th note = 3.9 mm (total), 16th note =
43         3.6 mm (total).  head-width = 2.4, so we 1.2mm for 16th, 1.5
44         mm for 8th. (white space), suggesting that we use
45
46         (1.2 / 1.5)^{-log2(duration ratio)}
47
48
49       */
50       Rational ratio = d.main_part_ / global_shortest_;
51
52       return ((k - 1) + double (ratio)) * increment_;
53     }
54   else
55     {
56       /*
57         John S. Gourlay. ``Spacing a Line of Music, '' Technical
58         Report OSU-CISRC-10/87-TR35, Department of Computer and
59         Information Science, The Ohio State University, 1987.
60       */
61       Real log = log_2 (global_shortest_);
62       k -= log;
63       Rational compdur = d.main_part_ + d.grace_part_ / Rational (3);
64       *expand_only = false;
65
66       return (log_2 (compdur) + k) * increment_;
67     }
68 }
69
70
71 /*
72   The one-size-fits all spacing. It doesn't take into account
73   different spacing wishes from one to the next column.
74 */
75 void
76 Spacing_spanner::standard_breakable_column_spacing (Grob *me, Item *l, Item *r,
77                                                     Real *fixed, Real *space,
78                                                     Spacing_options const *options)
79 {
80   *fixed = 0.0;
81   Direction d = LEFT;
82   Drul_array<Item *> cols (l, r);
83
84   do
85     {
86       if (!Paper_column::is_musical (cols[d]))
87         {
88           /*
89             Tied accidentals over barlines cause problems, so lets see
90             what happens if we do this for non musical columns only.
91           */
92           Interval lext = cols[d]->extent (cols [d], X_AXIS);
93           if (!lext.is_empty ())
94             *fixed += -d * lext[-d];
95         }
96     }
97   while (flip (&d) != LEFT);
98
99   if (l->is_breakable (l) && r->is_breakable (r))
100     {
101       Moment *dt = unsmob_moment (l->get_property ("measure-length"));
102       Moment mlen (1);
103       if (dt)
104         mlen = *dt;
105
106       Real incr = robust_scm2double (me->get_property ("spacing-increment"), 1);
107
108       *space = *fixed + incr * double (mlen.main_part_ / options->global_shortest_) * 0.8;
109     }
110   else
111     {
112       Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
113
114       if (dt == Moment (0, 0))
115         {
116           /*
117             In this case, Staff_spacing should handle the job,
118             using dt when it is 0 is silly.
119           */
120           *space = *fixed + 0.5;
121         }
122       else
123         {
124           bool dummy;
125           *space = *fixed + options->get_duration_space (dt, &dummy);
126         }
127     }
128 }
129
130 Real
131 Spacing_spanner::note_spacing (Grob *me, Grob *lc, Grob *rc,
132                                Spacing_options const *options ,
133                                bool *expand_only)
134 {
135   Moment shortest_playing_len = 0;
136   SCM s = lc->get_property ("shortest-playing-duration");
137
138   if (unsmob_moment (s))
139     shortest_playing_len = *unsmob_moment (s);
140
141   if (! shortest_playing_len.to_bool ())
142     {
143       programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).to_string ());
144       shortest_playing_len = 1;
145     }
146
147   Moment lwhen = Paper_column::when_mom (lc);
148   Moment rwhen = Paper_column::when_mom (rc);
149
150   Moment delta_t = rwhen - lwhen;
151   if (!Paper_column::is_musical (rc))
152     {
153       /*
154         when toying with mmrests, it is possible to have musical
155         column on the left and non-musical on the right, spanning
156         several measures.
157       */
158
159       Moment *dt = unsmob_moment (rc->get_property ("measure-length"));
160       if (dt)
161         {
162           delta_t = min (delta_t, *dt);
163
164           /*
165             The following is an extra safety measure, such that
166             the length of a mmrest event doesn't cause havoc.
167           */
168           shortest_playing_len = min (shortest_playing_len, *dt);
169         }
170     }
171
172   Real dist = 0.0;
173   if (delta_t.main_part_ && !lwhen.grace_part_)
174     {
175       dist = options->get_duration_space (shortest_playing_len,
176                                   expand_only);
177       dist *= double (delta_t.main_part_ / shortest_playing_len.main_part_);
178     }
179   else if (delta_t.grace_part_)
180     {
181       /*
182         Crude hack for spacing graces: we take the shortest space
183         available (namely the space for the global shortest note), and
184         multiply that by grace-space-factor
185       */
186       dist = options->get_duration_space (options->global_shortest_, expand_only);
187
188       Real grace_fact
189         = robust_scm2double (me->get_property ("grace-space-factor"), 1);
190
191       dist *= grace_fact;
192     }
193
194   return dist;
195 }
196
197
198 /****************************************************************/
199
200 void
201 Spacing_options::init_from_grob (Grob *me)
202 {
203   increment_ = robust_scm2double (me->get_property ("spacing-increment"), 1);
204
205   packed_ = to_boolean (me->get_property ("packed-spacing"));
206   stretch_uniformly_ = to_boolean (me->get_property ("uniform-stretching"));
207   float_nonmusical_columns_
208     = to_boolean (me->get_property ("strict-note-spacing"));
209   shortest_duration_space_ = robust_scm2double (me->get_property ("shortest-duration-space"), 1);
210 }
211
212
213 void
214 Spacing_options::init ()
215 {
216   increment_ = 1.2;
217   packed_ = false;
218   stretch_uniformly_ = false;
219   float_nonmusical_columns_ = false;
220   shortest_duration_space_ = 2.0;
221
222   global_shortest_ = Rational (1,8);
223 }