]> 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--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9
10 #include "paper-column.hh"
11 #include "engraver.hh"
12 #include "pqueue.hh"
13 #include "note-spacing.hh"
14 #include "staff-spacing.hh"
15 #include "group-interface.hh"
16 #include "spanner.hh"
17
18 struct Rhythmic_tuple
19 {
20   Grob_info info_;
21   Moment end_;
22   
23   Rhythmic_tuple ()
24     {
25     }
26   Rhythmic_tuple (Grob_info i, Moment m)
27     {
28       info_ = i;
29       end_ = m;
30     }
31   static int time_compare (Rhythmic_tuple const &, Rhythmic_tuple const &);  
32 };
33
34 /**
35    Acknowledge rhythmic elements, for initializing spacing fields in
36    the columns.
37
38    should be the  last one of the toplevel context
39 */
40 class Spacing_engraver : public Engraver
41 {
42   PQueue<Rhythmic_tuple> playing_durations_;
43   Array<Rhythmic_tuple> now_durations_;
44   Array<Rhythmic_tuple> stopped_durations_;
45   Moment now_;
46   Spanner * spacing_;
47   
48   TRANSLATOR_DECLARATIONS (Spacing_engraver);
49 protected:
50   virtual void acknowledge_grob (Grob_info);
51   virtual void start_translation_timestep ();
52   virtual void stop_translation_timestep ();
53   virtual void process_music ();
54   virtual void finalize ();
55 };
56
57 inline int
58 compare (Rhythmic_tuple const &a, Rhythmic_tuple const &b)
59 {
60   return Rhythmic_tuple::time_compare (a,b);
61 }
62
63 int
64 Rhythmic_tuple::time_compare (Rhythmic_tuple const &h1,
65                               Rhythmic_tuple const &h2)
66 {
67   return (h1.end_ - h2.end_).main_part_.sign ();
68 }
69
70 Spacing_engraver::Spacing_engraver ()
71 {
72   spacing_ = 0;
73 }
74
75 void
76 Spacing_engraver::process_music ()
77 {
78   if (!spacing_)
79     {
80       spacing_ = make_spanner ("SpacingSpanner", SCM_EOL);
81       spacing_->set_bound (LEFT, unsmob_grob (get_property ("currentCommandColumn")));  
82       
83     }
84 }
85
86 void
87 Spacing_engraver::finalize ()
88 {
89   if (spacing_)
90     {
91       Grob * p = unsmob_grob (get_property ("currentCommandColumn"));
92   
93       spacing_->set_bound (RIGHT, p);
94       spacing_ = 0;
95     }
96 }
97
98 void
99 Spacing_engraver::acknowledge_grob (Grob_info i)
100 {
101   if (Note_spacing::has_interface (i.grob_) || Staff_spacing::has_interface (i.grob_))
102     {
103       Pointer_group_interface::add_grob (spacing_, ly_symbol2scm  ("wishes"), i.grob_);
104     }
105   
106   if (i.grob_->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface"))
107       || i.grob_->internal_has_interface (ly_symbol2scm ("multi-measure-event")))
108     return;
109
110   /*
111     only pay attention to durations that are not grace notes. 
112    */
113   if (!now_.grace_part_)
114     {
115       Music *r = i.music_cause ();
116       if (r && r->is_mus_type ("rhythmic-event"))
117         {
118           Moment len = r->get_length ();
119           Rhythmic_tuple t (i, now_mom () + len);
120           now_durations_.push (t);
121         }
122     }
123 }
124
125 void
126 Spacing_engraver::stop_translation_timestep ()
127 {
128   Moment shortest_playing;
129   shortest_playing.set_infinite (1);
130   for (int i = 0; i < playing_durations_.size (); i++)
131     {
132       Music * mus = playing_durations_[i].info_.music_cause ();
133       if (mus)
134         {
135           Moment m = mus->get_length ();
136           shortest_playing = shortest_playing <? m;
137         }
138     }
139   Moment starter;
140   starter.set_infinite (1);
141
142   for (int i = 0; i < now_durations_.size (); i++)
143     {
144       Moment m = now_durations_[i].info_.music_cause ()->get_length ();
145       if (m.to_bool ())
146         {
147           starter = starter <? m;
148           playing_durations_.insert (now_durations_[i]);
149
150         }
151     }
152   now_durations_.clear ();
153   
154   shortest_playing = shortest_playing <? starter;
155   
156   Paper_column * sc
157     = dynamic_cast<Paper_column*> (unsmob_grob (get_property ("currentMusicalColumn")));
158
159   assert (starter.to_bool ());
160   SCM sh = shortest_playing.smobbed_copy ();
161   SCM st = starter.smobbed_copy ();
162
163   sc->set_property ("shortest-playing-duration", sh);  
164   sc->set_property ("shortest-starter-duration", st);
165 }
166
167 void
168 Spacing_engraver::start_translation_timestep ()
169 {
170   now_ = now_mom ();
171   stopped_durations_.clear ();
172   while (playing_durations_.size () && playing_durations_.front ().end_ < now_)
173     playing_durations_.delmin ();
174   while (playing_durations_.size () && playing_durations_.front ().end_ == now_)
175     stopped_durations_.push (playing_durations_.get ());
176 }
177
178
179
180
181 ENTER_DESCRIPTION (Spacing_engraver,
182 /* descr */       "make a SpacingSpanner and do bookkeeping of shortest starting and playing notes  ",
183 /* creats*/       "SpacingSpanner",
184 /* accepts */     "",
185 /* acks  */      "grob-interface",
186 /* reads */       "",
187 /* write */       "");