]> git.donarmstrong.com Git - lilypond.git/blob - lily/spacing-basic.cc
o * lily/spacing-engraver.cc (stop_translation_timestep): directly
[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_spanner::get_duration_space (Grob *me,
28                                      Moment d,
29                                      Rational shortest, bool *expand_only)
30 {
31   Real k = robust_scm2double (me->get_property ("shortest-duration-space"), 1);
32   Real incr = robust_scm2double (me->get_property ("spacing-increment"), 1);
33
34   if (d < shortest)
35     {
36       /*
37         We don't space really short notes using the log of the
38         duration, since it would disproportionally stretches the long
39         notes in a piece. In stead, we use geometric spacing with constant 0.5
40         (i.e. linear.)
41
42         This should probably be tunable, to use other base numbers.
43
44         In Mozart hrn3 by EB., we have 8th note = 3.9 mm (total), 16th note =
45         3.6 mm (total).  head-width = 2.4, so we 1.2mm for 16th, 1.5
46         mm for 8th. (white space), suggesting that we use
47
48         (1.2 / 1.5)^{-log2(duration ratio)}
49
50
51       */
52       Rational ratio = d.main_part_ / shortest;
53
54       return ((k - 1) + double (ratio)) * incr;
55     }
56   else
57     {
58       /*
59         John S. Gourlay. ``Spacing a Line of Music, '' Technical
60         Report OSU-CISRC-10/87-TR35, Department of Computer and
61         Information Science, The Ohio State University, 1987.
62       */
63       Real log = log_2 (shortest);
64       k -= log;
65       Rational compdur = d.main_part_ + d.grace_part_ / Rational (3);
66       *expand_only = false;
67
68       return (log_2 (compdur) + k) * incr;
69     }
70 }
71
72
73 /*
74   The one-size-fits all spacing. It doesn't take into account
75   different spacing wishes from one to the next column.
76 */
77 void
78 Spacing_spanner::standard_breakable_column_spacing (Grob *me, Item *l, Item *r,
79                                                     Real *fixed, Real *space,
80                                                     Spacing_options const *options)
81 {
82   *fixed = 0.0;
83   Direction d = LEFT;
84   Drul_array<Item *> cols (l, r);
85
86   do
87     {
88       if (!Paper_column::is_musical (cols[d]))
89         {
90           /*
91             Tied accidentals over barlines cause problems, so lets see
92             what happens if we do this for non musical columns only.
93           */
94           Interval lext = cols[d]->extent (cols [d], X_AXIS);
95           if (!lext.is_empty ())
96             *fixed += -d * lext[-d];
97         }
98     }
99   while (flip (&d) != LEFT);
100
101   if (l->is_breakable (l) && r->is_breakable (r))
102     {
103       Moment *dt = unsmob_moment (l->get_property ("measure-length"));
104       Moment mlen (1);
105       if (dt)
106         mlen = *dt;
107
108       Real incr = robust_scm2double (me->get_property ("spacing-increment"), 1);
109
110       *space = *fixed + incr * double (mlen.main_part_ / options->global_shortest_) * 0.8;
111     }
112   else
113     {
114       Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
115
116       if (dt == Moment (0, 0))
117         {
118           /*
119             In this case, Staff_spacing should handle the job,
120             using dt when it is 0 is silly.
121           */
122           *space = *fixed + 0.5;
123         }
124       else
125         {
126           bool dummy;
127           *space = *fixed + get_duration_space (me, dt, options->global_shortest_, &dummy);
128         }
129     }
130 }
131
132 Real
133 Spacing_spanner::note_spacing (Grob *me, Grob *lc, Grob *rc,
134                                Spacing_options const *options ,
135                                bool *expand_only)
136 {
137   Moment shortest_playing_len = 0;
138   SCM s = lc->get_property ("shortest-playing-duration");
139
140   if (unsmob_moment (s))
141     shortest_playing_len = *unsmob_moment (s);
142
143   if (! shortest_playing_len.to_bool ())
144     {
145       programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).to_string ());
146       shortest_playing_len = 1;
147     }
148
149   Moment lwhen = Paper_column::when_mom (lc);
150   Moment rwhen = Paper_column::when_mom (rc);
151
152   Moment delta_t = rwhen - lwhen;
153   if (!Paper_column::is_musical (rc))
154     {
155       /*
156         when toying with mmrests, it is possible to have musical
157         column on the left and non-musical on the right, spanning
158         several measures.
159       */
160
161       Moment *dt = unsmob_moment (rc->get_property ("measure-length"));
162       if (dt)
163         {
164           delta_t = min (delta_t, *dt);
165
166           /*
167             The following is an extra safety measure, such that
168             the length of a mmrest event doesn't cause havoc.
169           */
170           shortest_playing_len = min (shortest_playing_len, *dt);
171         }
172     }
173
174   Real dist = 0.0;
175   if (delta_t.main_part_ && !lwhen.grace_part_)
176     {
177       dist = get_duration_space (me, shortest_playing_len,
178                                  options->global_shortest_, expand_only);
179       dist *= double (delta_t.main_part_ / shortest_playing_len.main_part_);
180     }
181   else if (delta_t.grace_part_)
182     {
183       /*
184         Crude hack for spacing graces: we take the shortest space
185         available (namely the space for the global shortest note), and
186         multiply that by grace-space-factor
187       */
188       dist = get_duration_space (me, options->global_shortest_,
189                                  options->global_shortest_, expand_only);
190
191       Real grace_fact
192         = robust_scm2double (me->get_property ("grace-space-factor"), 1);
193
194       dist *= grace_fact;
195     }
196
197   return dist;
198 }