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