]> git.donarmstrong.com Git - lilypond.git/blob - lily/spacing-engraver.cc
*** empty log message ***
[lilypond.git] / lily / spacing-engraver.cc
1 /*
2   spacing-engraver.cc -- implement Spacing_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1999--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "paper-column.hh"
10 #include "engraver.hh"
11 #include "pqueue.hh"
12 #include "note-spacing.hh"
13 #include "staff-spacing.hh"
14 #include "pointer-group-interface.hh"
15 #include "spanner.hh"
16
17 #include "translator.icc"
18
19 struct Rhythmic_tuple
20 {
21   Grob_info info_;
22   Moment end_;
23
24   Rhythmic_tuple ()
25   {
26   }
27   Rhythmic_tuple (Grob_info i, Moment m)
28   {
29     info_ = i;
30     end_ = m;
31   }
32   static int time_compare (Rhythmic_tuple const &, Rhythmic_tuple const &);
33 };
34
35 inline int
36 compare (Rhythmic_tuple const &a, Rhythmic_tuple const &b)
37 {
38   return Rhythmic_tuple::time_compare (a, b);
39 }
40
41 int
42 Rhythmic_tuple::time_compare (Rhythmic_tuple const &h1,
43                               Rhythmic_tuple const &h2)
44 {
45   return (h1.end_ - h2.end_).main_part_.sign ();
46 }
47
48 /****************************************************************/
49
50 /*
51   Acknowledge rhythmic elements, for initializing spacing fields in
52   the columns.
53 */
54 class Spacing_engraver : public Engraver
55 {
56   PQueue<Rhythmic_tuple> playing_durations_;
57   vector<Rhythmic_tuple> now_durations_;
58   vector<Rhythmic_tuple> stopped_durations_;
59   Moment now_;
60   Spanner *spacing_;
61   Music *start_section_;
62   
63   TRANSLATOR_DECLARATIONS (Spacing_engraver);
64
65 protected:
66   DECLARE_ACKNOWLEDGER (staff_spacing);
67   DECLARE_ACKNOWLEDGER (note_spacing);
68   DECLARE_ACKNOWLEDGER (rhythmic_head);
69
70   void start_translation_timestep ();
71   void stop_translation_timestep ();
72   void process_music ();
73   
74   virtual void finalize ();
75   virtual bool try_music (Music *m);
76
77   void start_spanner ();
78   void stop_spanner ();
79 };
80
81 Spacing_engraver::Spacing_engraver ()
82 {
83   spacing_ = 0;
84   start_section_ = 0;
85 }
86
87 bool
88 Spacing_engraver::try_music (Music *m)
89 {
90   start_section_ = m;
91   return true;  
92 }
93
94 void
95 Spacing_engraver::process_music ()
96 {
97   if (start_section_ && spacing_)
98     stop_spanner ();
99   
100   if (!spacing_)
101     start_spanner ();
102 }
103
104 void
105 Spacing_engraver::start_spanner ()
106 {
107   assert (!spacing_);
108
109   spacing_ = make_spanner ("SpacingSpanner", SCM_EOL);
110   spacing_->set_bound (LEFT,
111                        unsmob_grob (get_property ("currentCommandColumn")));
112 }
113
114 void
115 Spacing_engraver::finalize ()
116 {
117   stop_spanner ();
118 }
119
120 void
121 Spacing_engraver::stop_spanner ()
122 {
123   if (spacing_)
124     {
125       Grob *p = unsmob_grob (get_property ("currentCommandColumn"));
126
127       spacing_->set_bound (RIGHT, p);
128       spacing_ = 0;
129     }
130 }
131
132 void
133 Spacing_engraver::acknowledge_note_spacing (Grob_info i)
134 {
135   Pointer_group_interface::add_grob (spacing_, ly_symbol2scm ("wishes"), i.grob ());
136 }
137
138 void
139 Spacing_engraver::acknowledge_staff_spacing (Grob_info i)
140 {
141   Pointer_group_interface::add_grob (spacing_, ly_symbol2scm ("wishes"), i.grob ());
142 }
143
144 void
145 Spacing_engraver::acknowledge_rhythmic_head (Grob_info i)
146 {
147   if (i.grob ()->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface"))
148       || i.grob ()->internal_has_interface (ly_symbol2scm ("multi-measure-interface")))
149     return;
150
151   /*
152     only pay attention to durations that are not grace notes.
153   */
154   if (!now_.grace_part_)
155     {
156       Music *r = i.music_cause ();
157       if (r && r->is_mus_type ("rhythmic-event"))
158         {
159           Moment len = r->get_length ();
160           Rhythmic_tuple t (i, now_mom () + len);
161           now_durations_.push_back (t);
162         }
163     }
164 }
165
166 void
167 Spacing_engraver::stop_translation_timestep ()
168 {
169   Paper_column *musical_column
170     = dynamic_cast<Paper_column *> (unsmob_grob (get_property ("currentMusicalColumn")));
171
172   SCM proportional = get_property ("proportionalNotationDuration");
173   if (unsmob_moment (proportional))
174     {
175       musical_column->set_property ("shortest-playing-duration", proportional);
176       musical_column->set_property ("shortest-starter-duration", proportional);
177       return;
178     }
179
180   Moment shortest_playing;
181   shortest_playing.set_infinite (1);
182   for (vsize i = 0; i < playing_durations_.size (); i++)
183     {
184       Music *mus = playing_durations_[i].info_.music_cause ();
185       if (mus)
186         {
187           Moment m = mus->get_length ();
188           shortest_playing = min (shortest_playing, m);
189         }
190     }
191   Moment starter;
192   starter.set_infinite (1);
193
194   for (vsize i = 0; i < now_durations_.size (); i++)
195     {
196       Moment m = now_durations_[i].info_.music_cause ()->get_length ();
197       if (m.to_bool ())
198         {
199           starter = min (starter, m);
200           playing_durations_.insert (now_durations_[i]);
201         }
202     }
203   now_durations_.clear ();
204
205   shortest_playing = min (shortest_playing, starter);
206
207   assert (starter.to_bool ());
208   SCM sh = shortest_playing.smobbed_copy ();
209   SCM st = starter.smobbed_copy ();
210
211   musical_column->set_property ("shortest-playing-duration", sh);
212   musical_column->set_property ("shortest-starter-duration", st);
213 }
214
215 void
216 Spacing_engraver::start_translation_timestep ()
217 {
218   start_section_ = 0;
219
220   now_ = now_mom ();
221   stopped_durations_.clear ();
222   
223   while (playing_durations_.size () && playing_durations_.front ().end_ < now_)
224     playing_durations_.delmin ();
225   while (playing_durations_.size () && playing_durations_.front ().end_ == now_)
226     stopped_durations_.push_back (playing_durations_.get ());
227 }
228
229 ADD_ACKNOWLEDGER (Spacing_engraver, staff_spacing);
230 ADD_ACKNOWLEDGER (Spacing_engraver, note_spacing);
231 ADD_ACKNOWLEDGER (Spacing_engraver, rhythmic_head);
232
233 ADD_TRANSLATOR (Spacing_engraver,
234                 "make a SpacingSpanner and do "
235                 "bookkeeping of shortest starting and playing notes  ",
236
237                 /* create */ "SpacingSpanner",
238                 /* accept */
239                 "spacing-section-event ",
240                 /* read */
241                 "currentMusicalColumn "
242                 "currentCommandColumn "
243                 "proportionalNotationDuration",
244                 
245                 /* write */ "");