]> git.donarmstrong.com Git - lilypond.git/blob - lily/quote-iterator.cc
* configure.in: Test for and accept lmodern if EC fonts not found.
[lilypond.git] / lily / quote-iterator.cc
1 /*   
2   quote-iterator.cc --  implement Quote_iterator
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2004 Han-Wen Nienhuys <hanwen@xs4all.nl>
7
8 */
9
10 #include "context.hh"
11 #include "event.hh"
12 #include "music-sequence.hh"
13 #include "lily-guile.hh"
14 #include "music-wrapper-iterator.hh"
15 #include "warn.hh"
16
17 class Quote_iterator : public Music_wrapper_iterator
18 {
19 public:
20   Quote_iterator ();
21   Moment vector_moment (int idx) const;
22   Interpretation_context_handle quote_outlet_;
23
24   Moment start_moment_;
25   Moment stop_moment_;
26   SCM event_vector_;
27   int event_idx_;
28   int end_idx_ ;
29
30   SCM transposed_musics_;
31   
32   DECLARE_SCHEME_CALLBACK (constructor, ()); 
33   bool quote_ok () const;
34   bool accept_music_type (Music*) const;
35 protected:
36   virtual void derived_mark () const;
37   virtual void construct_children ();
38   virtual Moment pending_moment () const;
39   virtual void process (Moment);
40   virtual bool ok () const;
41 };
42
43 bool
44 Quote_iterator::accept_music_type (Music *mus) const
45 {
46   SCM accept = get_outlet()->get_property ("quotedEventTypes");
47   for (SCM s =  mus->get_property ("types");
48        scm_is_pair (s);  s = scm_cdr (s))
49     {
50       if (scm_memq (scm_car (s), accept) != SCM_BOOL_F)
51         return true;
52     }
53
54   return false;
55 }
56
57
58 void
59 Quote_iterator::derived_mark () const
60 {
61   scm_gc_mark (transposed_musics_ );
62 }
63
64 Quote_iterator::Quote_iterator ()
65 {
66   transposed_musics_ = SCM_EOL;
67   event_vector_ = SCM_EOL;
68   event_idx_ = 0;
69   end_idx_ = 0;
70 }
71
72
73 int
74 binsearch_scm_vector (SCM vec, SCM key, bool (*is_less)(SCM a,SCM b))
75 {
76   int lo = 0;
77   int hi = SCM_VECTOR_LENGTH (vec);
78
79   /* binary search */
80   do
81   {
82     int cmp = (lo + hi) / 2;
83
84       SCM when = scm_caar (SCM_VECTOR_REF (vec, cmp));
85       bool result =  (*is_less) (key, when);
86       if (result)
87           hi = cmp;
88       else
89           lo = cmp;
90     }
91   while (hi - lo > 1);
92
93   return lo;
94 }
95
96
97 void
98 Quote_iterator::construct_children ()
99 {
100   Music_wrapper_iterator::construct_children ();
101
102   SCM name = get_music ()->get_property ("quoted-context-type");
103   SCM id = get_music ()->get_property ("quoted-context-id");
104
105   if (scm_is_string (id)
106       && scm_is_symbol (name))
107     {
108       Context *cue_context = get_outlet()->find_create_context (name,
109                                                                 ly_scm2string (id), SCM_EOL);
110       quote_outlet_.set_context (cue_context);
111     }
112   else
113     {
114       quote_outlet_.set_context (get_outlet ());
115     }
116   
117
118   event_vector_ = get_music ()->get_property ("quoted-events");
119   
120   /*
121     We have to delay initting event_idx_ , since we have to
122     take starting grace notes into account. Those may offset 
123     event_idx_.
124   */
125   event_idx_ = -1;
126 }
127
128
129 bool
130 Quote_iterator::ok () const
131 {
132   return
133     Music_wrapper_iterator::ok()
134     || quote_ok ();
135 }
136
137 bool
138 Quote_iterator::quote_ok () const
139 {
140   return (event_idx_ >= 0
141           && ly_c_vector_p (event_vector_)
142           && event_idx_ <= end_idx_
143
144           /*
145             Don't quote the grace notes leading to an unquoted note.
146            */
147           && vector_moment (event_idx_).main_part_ < stop_moment_.main_part_
148           );
149 }
150
151 Moment
152 Quote_iterator::pending_moment () const
153 {
154   Rational infty;
155   infty.set_infinite (1);
156   Moment m (infty);
157
158   if (Music_wrapper_iterator::ok())
159     m = m <? Music_wrapper_iterator::pending_moment();
160
161   /*
162     In case event_idx_ < 0, we're not initted yet, and the wrapped
163     music expression determines the starting moment.
164    */
165   if (quote_ok ())
166     m = m <? vector_moment (event_idx_) - start_moment_;
167
168   return m;
169 }
170
171 Moment
172 Quote_iterator::vector_moment (int idx) const
173 {
174   SCM entry = SCM_VECTOR_REF (event_vector_, idx);
175   return *unsmob_moment (scm_caar (entry));
176 }
177
178 void
179 Quote_iterator::process (Moment m)
180 {
181   if (Music_wrapper_iterator::ok())
182     Music_wrapper_iterator::process (m);
183
184   if (!ly_c_vector_p (event_vector_))
185     return ;
186   
187   if (event_idx_ < 0)
188     {
189       event_idx_ = binsearch_scm_vector (event_vector_,
190                                          get_outlet ()->now_mom ().smobbed_copy (),
191                                          &moment_less);
192       start_moment_ = get_outlet ()->now_mom () - music_start_mom();
193       stop_moment_ = start_moment_ + get_music()->get_length ();
194       
195       end_idx_ = binsearch_scm_vector (event_vector_,
196                                        stop_moment_.smobbed_copy (),
197                                        &moment_less);
198     }
199   
200   m += start_moment_;
201   while (event_idx_ <= end_idx_)
202     {
203       Moment em = vector_moment (event_idx_);
204       if (em > m)
205         return ;
206
207       if (em == m)
208         break ;
209
210       event_idx_++;
211     }
212
213   if (quote_ok ())
214     {
215       SCM entry = SCM_VECTOR_REF (event_vector_, event_idx_);
216       Pitch * quote_pitch = unsmob_pitch (scm_cdar (entry));
217
218       /*
219         The pitch that sounds like central C
220        */
221       Pitch * me_pitch = unsmob_pitch (get_outlet ()->get_property ("instrumentTransposition"));
222       
223       for (SCM s = scm_cdr (entry); scm_is_pair (s); s = scm_cdr (s))
224         {
225           SCM ev_acc = scm_car (s);
226
227           Music * mus = unsmob_music (scm_car (ev_acc));
228           if (!mus)
229             programming_error ("need music in quote.");
230           else if (accept_music_type (mus))
231             {
232               if (quote_pitch || me_pitch)
233                 {
234                   Pitch qp, mp;
235                   if (quote_pitch)
236                     qp = *quote_pitch;
237                   if (me_pitch)
238                     mp = *me_pitch;
239
240                   Pitch diff = pitch_interval (qp, mp);
241
242                   SCM copy = ly_music_deep_copy (mus->self_scm ());
243                   mus = unsmob_music (copy);
244                   
245                   transposed_musics_ = scm_cons (copy, transposed_musics_);
246                   mus->transpose (diff);
247                 }
248               
249               bool b = quote_outlet_.get_outlet ()->try_music (mus);
250               if (!b)
251                 mus->origin ()->warning (_f ("In quotation: junking event %s", mus->name ()));
252             }
253         }
254       
255       event_idx_ ++; 
256     }
257 }
258
259 IMPLEMENT_CTOR_CALLBACK (Quote_iterator);