]> git.donarmstrong.com Git - lilypond.git/blob - lily/new-figured-bass-engraver.cc
(process_music): new file.
[lilypond.git] / lily / new-figured-bass-engraver.cc
1 /*
2   new-figured-bass-engraver.cc -- implement New_figured_bass_engraver
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 "engraver.hh"
11
12 #include "context.hh"
13 #include "music.hh"
14 #include "item.hh"
15 #include "spanner.hh"
16 #include "axis-group-interface.hh"
17 #include "align-interface.hh"
18 #include "pointer-group-interface.hh"
19 #include "text-interface.hh"
20
21 #include "translator.icc"
22
23 struct Figure_group
24 {
25   Spanner *group_;
26   Spanner *continuation_line_;
27   
28   SCM number_;
29   SCM alteration_;
30   
31   bool is_continuation_;
32   Item *figure_item_; 
33   Music *current_music_;
34   
35   Figure_group ()
36   {
37     is_continuation_ = false;
38     continuation_line_ = 0;
39     number_ = SCM_EOL;
40     alteration_ = SCM_EOL;
41     group_ = 0;
42     current_music_ = 0;
43   }
44 };
45
46 struct New_figured_bass_engraver : public Engraver
47 {
48   TRANSLATOR_DECLARATIONS(New_figured_bass_engraver);
49   void clear_spanners();
50   void add_brackets ();
51 protected:
52   Array<Figure_group> groups_;
53   Spanner *alignment_;
54   Link_array<Music> new_musics_;
55   bool continuation_;
56   Moment stop_moment_;
57   Music *rest_event_; 
58   
59   virtual bool try_music (Music *);
60   virtual void derived_mark () const; 
61   
62   void start_translation_timestep ();
63   void stop_translation_timestep ();
64   void process_music ();
65 };
66
67 void
68 New_figured_bass_engraver::derived_mark () const
69 {
70   for (int i = 0; i < groups_.size (); i++)
71     {
72       scm_gc_mark (groups_[i].number_);
73       scm_gc_mark (groups_[i].alteration_);
74     }
75 }
76
77 void
78 New_figured_bass_engraver::stop_translation_timestep ()
79 {
80   if (groups_.is_empty ()
81       || now_mom ().main_part_ < stop_moment_.main_part_)
82     return ;
83   
84   bool found = false;
85   for (int i = 0; !found && i < groups_.size (); i++)
86     found  = found  || groups_[i].current_music_;
87
88   if (!found)
89     clear_spanners (); 
90 }
91
92 New_figured_bass_engraver::New_figured_bass_engraver ()
93 {
94   alignment_ = 0;
95   continuation_ = false;
96   rest_event_ = 0;
97 }
98
99 void
100 New_figured_bass_engraver::start_translation_timestep ()
101 {
102   if (now_mom ().main_part_ < stop_moment_.main_part_)
103     return ;
104   
105   rest_event_ = 0;
106   new_musics_.clear ();
107   for (int i = 0; i < groups_.size (); i++)
108     {
109       groups_[i].current_music_ = 0;
110       groups_[i].is_continuation_ = false;
111     }
112   continuation_ = false;
113 }
114
115 bool
116 New_figured_bass_engraver::try_music (Music *m)
117 {
118  if (m->is_mus_type ("rest-event"))
119     {
120       rest_event_ = m;
121       return true;
122     }
123  else
124    {
125      SCM fig = m->get_property ("figure");
126      for (int i = 0; i < groups_.size (); i++)
127        {
128          if (!groups_[i].current_music_
129              && ly_is_equal (groups_[i].number_, fig))
130            {
131              groups_[i].current_music_ = m;
132              groups_[i].is_continuation_ =
133                ly_is_equal (groups_[i].alteration_,
134                             m->get_property ("alteration"));
135              
136              continuation_ = true;
137              return true; 
138            }
139        }
140
141      new_musics_.push (m);
142
143      stop_moment_ = now_mom () + m->get_length ();
144      
145      return true;
146    }
147 }
148
149 void
150 New_figured_bass_engraver::clear_spanners ()
151 {
152   if (!alignment_)
153     return;
154   
155   alignment_ = 0;
156   groups_.clear ();
157 }
158
159 void
160 New_figured_bass_engraver::add_brackets ()
161 {
162   Link_array<Grob> encompass;
163   bool inside = false;
164   for (int i = 0; i < groups_.size (); i ++)
165     {
166       if (!groups_[i].current_music_)
167         continue;
168       
169       if (to_boolean (groups_[i].current_music_->get_property ("bracket-start")))       
170         {
171           inside = true;
172         }
173
174       if (inside && groups_[i].figure_item_)
175         encompass.push (groups_[i].figure_item_);
176
177        if (to_boolean (groups_[i].current_music_->get_property ("bracket-stop")))
178         {
179           inside = false;
180
181           Item * brack = make_item ("BassFigureBracket", groups_[i].current_music_->self_scm ());
182           for (int j = 0; j < encompass.size (); j++)
183             {
184               Pointer_group_interface::add_grob (brack,
185                                                  ly_symbol2scm ("elements"),
186                                                  encompass[j]);
187             }
188           encompass.clear ();
189         }
190     }
191 }
192
193 void
194 New_figured_bass_engraver::process_music ()
195 {
196   if (rest_event_)
197     {
198       clear_spanners ();
199       return;
200     }
201   
202   if (!continuation_
203       && new_musics_.is_empty ())
204     {
205       clear_spanners ();
206       return;
207     }
208   
209   Grob *muscol = dynamic_cast<Item*> (unsmob_grob (get_property ("currentMusicalColumn")));
210   if (!continuation_)
211     {
212       clear_spanners ();
213       alignment_ = make_spanner ("BassFigureAlignment", SCM_EOL);
214       alignment_->set_bound (LEFT, muscol);
215     }
216
217   int k = 0;
218   for (int i = 0; i < new_musics_.size (); i++)
219     {
220       while (k < groups_.size() &&
221              groups_[k].current_music_)
222         k++;
223       
224       if (k >= groups_.size ())
225         {
226           Figure_group group;
227           groups_.push (group);
228         }
229
230       
231       groups_[k].current_music_ = new_musics_[i];
232       groups_[k].figure_item_ = 0;
233       k++;
234     }
235
236   SCM proc = get_property ("newFiguredBassFormatter");
237   
238   alignment_->set_bound (RIGHT, muscol);
239   if (to_boolean (get_property ("useBassFigureExtenders")))
240   for (int i = 0; i < groups_.size(); i++)
241     {
242       if (groups_[i].is_continuation_)
243         {
244           if (!groups_[i].continuation_line_)
245             {
246               Spanner * line = make_spanner ("BassFigureContinuation", SCM_EOL);
247               Item * item = groups_[i].figure_item_;
248               groups_[i].continuation_line_ = line;
249               line->set_bound (LEFT, item);
250
251               /*
252                 Don't add as child. This will cache the wrong
253                 (pre-break) stencil when callbacks are triggered.
254                */
255               line->set_parent (groups_[i].group_, Y_AXIS);
256               Pointer_group_interface::add_grob (line, ly_symbol2scm ("figures"), item);
257               
258               groups_[i].figure_item_ = 0;
259             }
260         }
261       else
262         groups_[i].continuation_line_ = 0;
263     }
264   
265   for (int i = 0; i < groups_.size(); i++)
266     {
267       Figure_group &group = groups_[i];
268       
269       if (group.continuation_line_)
270         {
271           group.continuation_line_->set_bound (RIGHT, muscol);
272         }
273       else if (group.current_music_)
274         {
275           Item *item
276             = make_item ("NewBassFigure",
277                          group.current_music_->self_scm ());
278           SCM fig = group.current_music_->get_property ("figure");
279           if (!group.group_)
280             {
281               group.group_ = make_spanner ("BassFigureLine", SCM_EOL);
282               group.group_->set_bound (LEFT, muscol);
283               Align_interface::add_element (alignment_,
284                                             group.group_,
285                                             Align_interface::alignment_callback_proc);
286             }
287
288           
289           group.number_ = fig;
290           group.alteration_ = group.current_music_->get_property ("alteration");
291
292           SCM text = group.current_music_->get_property ("text");
293           if (!Text_interface::is_markup (text)
294               && ly_is_procedure (proc))
295             {
296               text = scm_call_3 (proc, fig, group.current_music_->self_scm (),
297                                  context ()->self_scm ());
298             }
299
300           item->set_property ("text", text);
301           
302           Axis_group_interface::add_element (group.group_, item);
303           group.figure_item_ = item;
304         }
305
306       groups_[i].group_->set_bound (RIGHT, muscol);
307     }
308
309   add_brackets ();
310 }
311
312
313 ADD_TRANSLATOR (New_figured_bass_engraver,
314                 /* doc */
315
316                 "Make figured bass numbers.",
317                 /* create */
318                 "NewBassFigure "
319                 "BassFigureAlignment "
320                 "BassFigureBracket",
321                 "BassFigureContinuation "
322                 "BassFigureLine "
323
324                 /* accept */
325                 "bass-figure-event rest-event",
326
327                 /* read */
328                 "useBassFigureExtenders",
329
330                 /* write */
331                 "");