2 cluster-engraver.cc -- implement Cluster_engraver
4 (c) 2002 Juergen Reuter <reuter@ipd.uka.de>
10 #include "note-head.hh"
11 #include "protected-scm.hh"
14 class Cluster_engraver : public Engraver
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 ();
26 Drul_array<Music*> reqs_drul_;
27 Pitch pitch_min_, pitch_max_;
32 void reset_min_max (Pitch *pitch_min, Pitch *pitch_max)
35 * (pitch_min > pitch_max) means that pitches are not yet
38 *pitch_min = Pitch (0, 0, +1);
39 *pitch_max = Pitch (0, 0, -1);
42 Cluster_engraver::Cluster_engraver ()
45 columns_scm_ = SCM_EOL;
46 reqs_drul_[LEFT] = reqs_drul_[RIGHT] = 0;
50 Cluster_engraver::try_music (Music *m)
52 if (m->is_mus_type ("abort-event"))
54 reqs_drul_[START] = 0;
60 columns_scm_ = SCM_EOL;
63 else if (m->is_mus_type ("cluster-event"))
65 Direction d = to_dir (m->get_mus_property ("span-direction"));
73 Cluster_engraver::process_music ()
79 reqs_drul_[STOP]->origin ()->warning ("can't find start of cluster");
83 Grob *bound = unsmob_grob (get_property ("currentMusicalColumn"));
84 cluster_->set_bound (RIGHT, bound);
87 if (reqs_drul_[START])
91 reqs_drul_[START]->origin ()->warning ("may not nest clusters");
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 ());
102 reqs_drul_[START] = 0;
107 Cluster_engraver::start_translation_timestep ()
109 reset_min_max (&pitch_min_, &pitch_max_);
113 Cluster_engraver::stop_translation_timestep ()
117 SCM column_scm = get_property ("currentMusicalColumn");
118 if (column_scm == SCM_EOL)
120 programming_error("failed retrieving current column");
124 if (Pitch::compare (pitch_min_, pitch_max_) <= 0)
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);
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),
139 segment = scm_list_n (segment, SCM_UNDEFINED);
140 columns_scm_ = (columns_scm_ != SCM_EOL) ?
141 gh_append2 (columns_scm_, segment) : segment;
142 cluster_->set_grob_property ("segments", columns_scm_); // Urrgh!
146 /* This timestep is caused by a different voice of the
147 same staff and hence should be ignored. */
151 if (reqs_drul_[STOP])
153 reqs_drul_[STOP] = 0;
154 cluster_->set_grob_property ("segments", columns_scm_);
155 typeset_grob (cluster_);
157 columns_scm_ = SCM_EOL;
163 Cluster_engraver::acknowledge_grob (Grob_info info)
165 Item *item = dynamic_cast <Item *>(info.grob_);
168 if (Note_head::has_interface (info.grob_))
170 Music *nr = info.music_cause ();
171 if (nr && nr->is_mus_type ("note-event"))
173 Pitch pitch = *unsmob_pitch (nr->get_mus_property ("pitch"));
174 if (Pitch::compare (pitch_min_, pitch_max_) > 0) // already init'd?
176 // not yet init'd; use current pitch to init min/max
180 else if (Pitch::compare (pitch, pitch_max_) > 0) // new max?
184 else if (Pitch::compare (pitch, pitch_min_) < 0) // new min?
193 ENTER_DESCRIPTION(Cluster_engraver,
194 /* descr */ "engraves a cluster",
195 /* creats*/ "Cluster",
196 /* accepts */ "cluster-event",
197 /* acks */ "note-head-interface",