]> git.donarmstrong.com Git - lilypond.git/blob - lily/cluster-engraver.cc
2002-12-30 Juergen Reuter <reuter@ipd.uka.de>
[lilypond.git] / lily / cluster-engraver.cc
1 /*
2   cluster-engraver.cc -- implement Cluster_engraver
3
4   (c) 2002 Juergen Reuter <reuter@ipd.uka.de>
5 */
6
7 #include "engraver.hh"
8 #include "item.hh"
9 #include "spanner.hh"
10 #include "note-head.hh"
11 #include "protected-scm.hh"
12 #include "warn.hh"
13
14 class Cluster_engraver : public Engraver
15 {
16
17 protected:
18 TRANSLATOR_DECLARATIONS(Cluster_engraver);
19   virtual void start_translation_timestep ();
20   virtual bool try_music (Music *);
21   virtual void process_music ();  
22   virtual void acknowledge_grob (Grob_info);
23   virtual void stop_translation_timestep ();
24
25 private:
26   Drul_array<Music*> reqs_drul_;
27   Pitch pitch_min_, pitch_max_;
28   Spanner *cluster_;
29   Protected_scm columns_scm_;
30 };
31
32 void reset_min_max (Pitch *pitch_min, Pitch *pitch_max)
33 {
34   /*
35    * (pitch_min > pitch_max) means that pitches are not yet
36    * initialized
37    */
38   *pitch_min = Pitch (0, 0, +1);
39   *pitch_max = Pitch (0, 0, -1);
40 }
41
42 Cluster_engraver::Cluster_engraver ()
43 {
44   cluster_ = 0;
45   columns_scm_ = SCM_EOL;
46   reqs_drul_[LEFT] = reqs_drul_[RIGHT] = 0;
47 }
48
49 bool
50 Cluster_engraver::try_music (Music *m)
51 {
52   if (m->is_mus_type ("abort-event"))
53     {
54       reqs_drul_[START] = 0;
55       reqs_drul_[STOP] = 0;
56       if (cluster_)
57         {
58           cluster_->suicide ();
59           cluster_ = 0;
60           columns_scm_ = SCM_EOL;
61         }
62     }
63   else if (m->is_mus_type ("cluster-event"))
64     {
65       Direction d = to_dir (m->get_mus_property ("span-direction"));
66       reqs_drul_[d] = m;
67       return true;
68     }
69   return false;
70 }
71
72 void
73 Cluster_engraver::process_music ()
74 {
75   if (reqs_drul_[STOP])
76     {
77       if (!cluster_)
78         {
79           reqs_drul_[STOP]->origin ()->warning ("can't find start of cluster");
80         }
81       else
82         {
83           Grob *bound = unsmob_grob (get_property ("currentMusicalColumn"));
84           cluster_->set_bound (RIGHT, bound);
85         }
86     }
87   if (reqs_drul_[START])
88     {
89       if (cluster_)
90         {
91           reqs_drul_[START]->origin ()->warning ("may not nest clusters");
92         }
93       else
94         {
95           SCM basicProperties = get_property ("Cluster");
96           cluster_ = new Spanner (basicProperties);
97           columns_scm_ = SCM_EOL;
98           Grob *bound = unsmob_grob (get_property ("currentMusicalColumn"));
99           cluster_->set_bound (LEFT, bound);
100           announce_grob (cluster_, bound->self_scm ());
101         }
102       reqs_drul_[START] = 0;
103     }
104 }
105
106 void
107 Cluster_engraver::start_translation_timestep ()
108 {
109   reset_min_max (&pitch_min_, &pitch_max_);
110 }
111
112 void
113 Cluster_engraver::stop_translation_timestep ()
114 {
115   if (cluster_)
116     {
117       SCM column_scm = get_property ("currentMusicalColumn");
118       if (column_scm == SCM_EOL)
119         {
120           programming_error("failed retrieving current column");
121         }
122       else
123         {
124           if (Pitch::compare (pitch_min_, pitch_max_) <= 0)
125             {
126               Real y_bottom = 0.5 * pitch_min_.steps ();
127               SCM c0 = get_property ("centralCPosition");
128               if (gh_number_p (c0))
129                 y_bottom += 0.5 * gh_scm2int (c0);
130               else
131                 programming_error ("Cluster_engraver: failed evaluating c0");
132               Real y_top = y_bottom +
133                 0.5 * (pitch_max_.steps () - pitch_min_.steps ());
134               column_scm = Protected_scm (column_scm);
135               SCM segment = scm_list_n (column_scm,
136                                         gh_double2scm (y_bottom),
137                                         gh_double2scm (y_top),
138                                         SCM_UNDEFINED);
139               segment = scm_list_n (segment, SCM_UNDEFINED);
140               columns_scm_ = (columns_scm_ != SCM_EOL) ?
141                 gh_append2 (columns_scm_, segment) : segment;
142             }
143           else
144             {
145               /* This timestep is caused by a different voice of the
146                  same staff and hence should be ignored. */
147             }
148         }
149
150       if (reqs_drul_[STOP])
151         {
152           reqs_drul_[STOP] = 0;
153           cluster_->set_grob_property ("segments", columns_scm_);
154           typeset_grob (cluster_);
155           cluster_ = 0;
156           columns_scm_ = SCM_EOL;
157         }
158     }
159 }
160
161 void
162 Cluster_engraver::acknowledge_grob (Grob_info info)
163 {
164   Item *item = dynamic_cast <Item *>(info.grob_);
165   if (item)
166     {
167       if (Note_head::has_interface (info.grob_))
168         {
169           Music *nr = info.music_cause ();
170           if (nr && nr->is_mus_type ("note-event"))
171             {
172               Pitch pitch = *unsmob_pitch (nr->get_mus_property ("pitch"));
173               if (Pitch::compare (pitch_min_, pitch_max_) > 0) // already init'd?
174                 {
175                   // not yet init'd; use current pitch to init min/max
176                   pitch_min_ = pitch;
177                   pitch_max_ = pitch;
178                 }
179               else if (Pitch::compare (pitch, pitch_max_) > 0) // new max?
180                 {
181                   pitch_max_ = pitch;
182                 }
183               else if (Pitch::compare (pitch, pitch_min_) < 0) // new min?
184                 {
185                   pitch_min_ = pitch;
186                 }
187             }
188         }
189     }
190 }
191
192 ENTER_DESCRIPTION(Cluster_engraver,
193 /* descr */     "engraves a cluster",
194 /* creats*/     "Cluster",
195 /* accepts */   "cluster-event",
196 /* acks  */     "note-head-interface",
197 /* reads */     "",
198 /* write */     "");