]> git.donarmstrong.com Git - lilypond.git/blob - lily/spacing-engraver.cc
Fix some bugs in the dynamic engraver and PostScript backend
[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 /*
36   TODO: allow starting & stopping of spacing regions.
37 */
38 /*
39   Acknowledge rhythmic elements, for initializing spacing fields in
40   the columns.
41 */
42 class Spacing_engraver : public Engraver
43 {
44   PQueue<Rhythmic_tuple> playing_durations_;
45   vector<Rhythmic_tuple> now_durations_;
46   vector<Rhythmic_tuple> stopped_durations_;
47   Moment now_;
48   Spanner *spacing_;
49
50   TRANSLATOR_DECLARATIONS (Spacing_engraver);
51
52 protected:
53   DECLARE_ACKNOWLEDGER (staff_spacing);
54   DECLARE_ACKNOWLEDGER (note_spacing);
55   DECLARE_ACKNOWLEDGER (rhythmic_head);
56
57   void start_translation_timestep ();
58   void stop_translation_timestep ();
59   void process_music ();
60   virtual void finalize ();
61 };
62
63 inline int
64 compare (Rhythmic_tuple const &a, Rhythmic_tuple const &b)
65 {
66   return Rhythmic_tuple::time_compare (a, b);
67 }
68
69 int
70 Rhythmic_tuple::time_compare (Rhythmic_tuple const &h1,
71                               Rhythmic_tuple const &h2)
72 {
73   return (h1.end_ - h2.end_).main_part_.sign ();
74 }
75
76 Spacing_engraver::Spacing_engraver ()
77 {
78   spacing_ = 0;
79 }
80
81 void
82 Spacing_engraver::process_music ()
83 {
84   if (!spacing_)
85     {
86       spacing_ = make_spanner ("SpacingSpanner", SCM_EOL);
87       spacing_->set_bound (LEFT, unsmob_grob (get_property ("currentCommandColumn")));
88     }
89 }
90
91 void
92 Spacing_engraver::finalize ()
93 {
94   if (spacing_)
95     {
96       Grob *p = unsmob_grob (get_property ("currentCommandColumn"));
97
98       spacing_->set_bound (RIGHT, p);
99       spacing_ = 0;
100     }
101 }
102
103 void
104 Spacing_engraver::acknowledge_note_spacing (Grob_info i)
105 {
106   Pointer_group_interface::add_grob (spacing_, ly_symbol2scm ("wishes"), i.grob ());
107 }
108
109 void
110 Spacing_engraver::acknowledge_staff_spacing (Grob_info i)
111 {
112   Pointer_group_interface::add_grob (spacing_, ly_symbol2scm ("wishes"), i.grob ());
113 }
114
115 void
116 Spacing_engraver::acknowledge_rhythmic_head (Grob_info i)
117 {
118   if (i.grob ()->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface"))
119       || i.grob ()->internal_has_interface (ly_symbol2scm ("multi-measure-interface")))
120     return;
121
122   /*
123     only pay attention to durations that are not grace notes.
124   */
125   if (!now_.grace_part_)
126     {
127       Music *r = i.music_cause ();
128       if (r && r->is_mus_type ("rhythmic-event"))
129         {
130           Moment len = r->get_length ();
131           Rhythmic_tuple t (i, now_mom () + len);
132           now_durations_.push_back (t);
133         }
134     }
135 }
136
137 void
138 Spacing_engraver::stop_translation_timestep ()
139 {
140   Paper_column *musical_column
141     = dynamic_cast<Paper_column *> (unsmob_grob (get_property ("currentMusicalColumn")));
142
143   SCM proportional = get_property ("proportionalNotationDuration");
144   if (unsmob_moment (proportional))
145     {
146       musical_column->set_property ("shortest-playing-duration", proportional);
147       musical_column->set_property ("shortest-starter-duration", proportional);
148       return;
149     }
150
151   Moment shortest_playing;
152   shortest_playing.set_infinite (1);
153   for (vsize i = 0; i < playing_durations_.size (); i++)
154     {
155       Music *mus = playing_durations_[i].info_.music_cause ();
156       if (mus)
157         {
158           Moment m = mus->get_length ();
159           shortest_playing = min (shortest_playing, m);
160         }
161     }
162   Moment starter;
163   starter.set_infinite (1);
164
165   for (vsize i = 0; i < now_durations_.size (); i++)
166     {
167       Moment m = now_durations_[i].info_.music_cause ()->get_length ();
168       if (m.to_bool ())
169         {
170           starter = min (starter, m);
171           playing_durations_.insert (now_durations_[i]);
172         }
173     }
174   now_durations_.clear ();
175
176   shortest_playing = min (shortest_playing, starter);
177
178   assert (starter.to_bool ());
179   SCM sh = shortest_playing.smobbed_copy ();
180   SCM st = starter.smobbed_copy ();
181
182   musical_column->set_property ("shortest-playing-duration", sh);
183   musical_column->set_property ("shortest-starter-duration", st);
184 }
185
186 void
187 Spacing_engraver::start_translation_timestep ()
188 {
189   now_ = now_mom ();
190   stopped_durations_.clear ();
191   while (playing_durations_.size () && playing_durations_.front ().end_ < now_)
192     playing_durations_.delmin ();
193   while (playing_durations_.size () && playing_durations_.front ().end_ == now_)
194     stopped_durations_.push_back (playing_durations_.get ());
195 }
196
197 ADD_ACKNOWLEDGER (Spacing_engraver, staff_spacing);
198 ADD_ACKNOWLEDGER (Spacing_engraver, note_spacing);
199 ADD_ACKNOWLEDGER (Spacing_engraver, rhythmic_head);
200
201 ADD_TRANSLATOR (Spacing_engraver,
202                 "make a SpacingSpanner and do "
203                 "bookkeeping of shortest starting and playing notes  ",
204
205                 /* create */ "SpacingSpanner",
206                 /* accept */ "",
207                 /* read */
208                 "currentMusicalColumn "
209                 "currentCommandColumn "
210                 "proportionalNotationDuration",
211                 
212                 /* write */ "");