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