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