]> git.donarmstrong.com Git - lilypond.git/blob - lily/part-combine-music-iterator.cc
patch::: 1.3.78.jcn1
[lilypond.git] / lily / part-combine-music-iterator.cc
1 /*   
2   part-combine-music-iterator.cc -- implement  Part_combine_music_iterator
3
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 2000 Jan Nieuwenhuizen <janneke@gnu.org>
7  */
8
9 #include "part-combine-music.hh"
10 #include "part-combine-music-iterator.hh"
11 #include "translator-group.hh"
12 #include "musical-request.hh"
13 #include "warn.hh"
14
15 Part_combine_music_iterator::Part_combine_music_iterator ()
16 {
17   unirhythm_b_ = false;
18
19   first_iter_p_ = 0;
20   second_iter_p_ = 0;
21 }
22
23 Part_combine_music_iterator::~Part_combine_music_iterator ()
24 {
25   delete second_iter_p_;
26   delete first_iter_p_;
27 }
28
29 Moment
30 Part_combine_music_iterator::next_moment () const
31 {
32   Moment first_next = first_iter_p_->next_moment ();
33   Moment second_next = second_iter_p_->next_moment ();
34   return first_next <? second_next;
35 }
36
37 bool
38 Part_combine_music_iterator::ok () const
39 {
40   //hmm
41   return first_iter_p_->ok ();
42 }
43
44 void
45 Part_combine_music_iterator::do_print () const
46 {
47   first_iter_p_->print ();
48   second_iter_p_->print ();
49 }
50
51 void
52 Part_combine_music_iterator::construct_children ()
53 {
54   Part_combine_music const * m = dynamic_cast<Part_combine_music const*> (music_l_);
55   
56   first_iter_p_ = get_iterator_p (m->first_l ());
57   second_iter_p_ = get_iterator_p (m->second_l ());
58 }
59
60 void
61 Part_combine_music_iterator::change_to (Music_iterator *it, String to_type,
62                                         String to_id)
63 {
64   Translator_group * current = it->report_to_l ();
65   Translator_group * last = 0;
66
67   /*
68     Cut & Paste from from Auto_change_iterator from Change_iterator (ugh).
69
70     TODO: abstract this function 
71    */
72   
73   /* find the type  of translator that we're changing.
74      
75      If \translator Staff = bass, then look for Staff = *
76    */
77   while  (current && current->type_str_ != to_type)
78     {
79       last = current;
80       current = current->daddy_trans_l_;
81     }
82
83   if (current && current->id_str_ == to_id)
84     {
85       String msg;
86       msg += _ ("Can't switch translators, I'm there already");
87     }
88   
89   if (current) 
90     if (last)
91       {
92         Translator_group * dest = 
93           it->report_to_l ()->find_create_translator_l (to_type, to_id);
94         current->remove_translator_p (last);
95         dest->add_translator (last);
96       }
97     else
98       {
99         /*
100           We could change the current translator's id, but that would make 
101           errors hard to catch
102           
103            last->translator_id_str_  = change_l ()->change_to_id_str_;
104         */
105         error (_f ("I'm one myself: `%s'", to_type.ch_C ()));
106       }
107   else
108     error (_f ("none of these in my family: `%s'", to_id.ch_C ()));
109 }
110
111 Pitch_interrogate_req* first_spanish_inquisition; // nobody expects it
112 Pitch_interrogate_req* second_spanish_inquisition; // won't strike twice
113
114 void
115 Part_combine_music_iterator::do_process_and_next (Moment m)
116 {
117   Moment first_next = first_iter_p_->next_moment ();
118   Moment second_next = second_iter_p_->next_moment ();
119
120   Part_combine_music const * p = dynamic_cast<Part_combine_music const* > (music_l_);
121
122   String to_id =  unirhythm_b_ ? "one" : "two";
123   /*
124     different rhythm for combined voices: separate 
125     same rhythm for separated voices: combine
126
127     Arg.  Voices should be separated for small intervals, eg < 3.
128     This should be \property settable, and, we need the outcome
129     of the spanish_inquisition's...
130
131     Can't we first do a process_and_next go into a fake/tmp tree,
132     use + junk the result, and then do the real process_and_next...?
133     
134   */
135   if ((first_next != second_next && unirhythm_b_)
136       || (first_next == second_next && !unirhythm_b_))
137     {
138       unirhythm_b_ = !unirhythm_b_;
139       to_id =  unirhythm_b_ ? "one" : "two";
140       change_to (second_iter_p_, p->what_str_, to_id);
141     }
142
143   Translator_group * fd = 
144     first_iter_p_->report_to_l ()->find_create_translator_l (p->what_str_,
145                                                              "one");
146   Translator_group * sd = 
147     second_iter_p_->report_to_l ()->find_create_translator_l (p->what_str_,
148                                                               to_id);
149
150   fd->set_property ("unirhythm", unirhythm_b_ ? SCM_BOOL_T : SCM_BOOL_F);
151   sd->set_property ("unirhythm", unirhythm_b_ ? SCM_BOOL_T : SCM_BOOL_F);
152   first_iter_p_->report_to_l ()->set_property ("unirhythm", unirhythm_b_ ? SCM_BOOL_T : SCM_BOOL_F);
153   second_iter_p_->report_to_l ()->set_property ("unirhythm", unirhythm_b_ ? SCM_BOOL_T : SCM_BOOL_F);
154
155   if (first_next <= m)
156     first_iter_p_->process_and_next (m);
157
158   if (second_next <= m)
159     second_iter_p_->process_and_next (m);
160
161   Music_iterator::do_process_and_next (m);
162
163   /*
164     TODO:
165     
166     * "a2" string is fine, but "Soli" strings are one request late??
167     
168       The problem seems to be: we need to do_try_music for the
169       spanish_inquisition to work; but the properties that we set
170       need to be set *before* we do_try_music?
171       
172     * setting of stem directions by a2-engraver don't work
173
174     * separate for small ( <3 ?) intervals too
175       
176     Later (because currently, we only handle thread switching, really):
177
178     Maybe different modes exist?
179
180     * Wind instruments (Flute I/II)
181     * Hymnals:  
182
183
184       Rules for Hymnals/SATB (John Henckel <henckel@iname.com>):
185
186       1. if S and A differ by less than a third, the stems should be up/down.
187       2. else if S and A have different values, the stems should be up/down.
188       3. else if A sings "la" or higher, both S and A stems should be down.
189       4. else both stems should be up
190
191     * This may get really tricky: combining voices/staffs: string instruments
192
193    */
194   
195   if (!first_spanish_inquisition)
196     first_spanish_inquisition = new Pitch_interrogate_req;
197   Music_iterator* fit = first_iter_p_->try_music (first_spanish_inquisition);
198
199   if (!second_spanish_inquisition)
200     second_spanish_inquisition = new Pitch_interrogate_req;
201   Music_iterator* sit = second_iter_p_->try_music (second_spanish_inquisition);
202
203   if ((first_next == second_next)
204       && !compare (&first_spanish_inquisition->pitch_arr_,
205                    &second_spanish_inquisition->pitch_arr_))
206     {
207       fd->set_property ("unison", SCM_BOOL_T);
208       sd->set_property ("unison", SCM_BOOL_T);
209       first_iter_p_->report_to_l ()->set_property ("unison", SCM_BOOL_T);
210       second_iter_p_->report_to_l ()->set_property ("unison", SCM_BOOL_T);
211     }
212   else
213     {
214       fd->set_property ("unison", SCM_BOOL_F);
215       sd->set_property ("unison", SCM_BOOL_F);
216       first_iter_p_->report_to_l ()->set_property ("unison", SCM_BOOL_F);
217       second_iter_p_->report_to_l ()->set_property ("unison", SCM_BOOL_F);
218     }
219
220   if (first_spanish_inquisition->pitch_arr_.size () &&
221       second_spanish_inquisition->pitch_arr_.size ())
222     {
223       first_spanish_inquisition->pitch_arr_.sort (Musical_pitch::compare);
224       second_spanish_inquisition->pitch_arr_.sort (Musical_pitch::compare);
225       SCM interval = gh_int2scm (first_spanish_inquisition->pitch_arr_.top ().semitone_pitch ()
226                                  - second_spanish_inquisition->pitch_arr_[0].semitone_pitch ());
227       fd->set_property ("interval", interval);
228       sd->set_property ("interval", interval);
229       first_iter_p_->report_to_l ()->set_property ("interval", interval);
230       second_iter_p_->report_to_l ()->set_property ("interval", interval);
231     }
232       
233   if (first_spanish_inquisition->pitch_arr_.size ()
234       && !second_spanish_inquisition->pitch_arr_.size ())
235     {
236       fd->set_property ("solo", SCM_BOOL_T);
237       first_iter_p_->report_to_l ()->set_property ("solo", SCM_BOOL_T);
238     }
239   else
240     {
241       fd->set_property ("solo", SCM_BOOL_F);
242       first_iter_p_->report_to_l ()->set_property ("solo", SCM_BOOL_F);
243     }
244
245
246   if (!first_spanish_inquisition->pitch_arr_.size ()
247       && second_spanish_inquisition->pitch_arr_.size ())
248     {
249       sd->set_property ("solo", SCM_BOOL_T);
250       second_iter_p_->report_to_l ()->set_property ("solo", SCM_BOOL_T);
251     }
252   else
253     {
254       sd->set_property ("solo", SCM_BOOL_F);
255       second_iter_p_->report_to_l ()->set_property ("solo", SCM_BOOL_F);
256     }
257
258   first_spanish_inquisition->pitch_arr_.clear ();
259   second_spanish_inquisition->pitch_arr_.clear ();
260 }
261
262 Music_iterator*
263 Part_combine_music_iterator::try_music_in_children (Music *m) const
264 {
265   Music_iterator * i =  first_iter_p_->try_music (m);
266   if (i)
267     return i;
268   else
269     return second_iter_p_->try_music (m);
270 }
271