]> git.donarmstrong.com Git - lilypond.git/blob - lily/quote-iterator.cc
*** empty log message ***
[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-iterator.hh"
15 #include "music.hh"
16 #include "input.hh"
17 #include "warn.hh"
18
19
20 class Quote_iterator : public Music_iterator
21 {
22 public:
23   Quote_iterator ();
24   Moment vector_moment (int idx) const;
25   
26   Moment start_moment_;
27   SCM event_vector_;
28   int event_idx_;
29   int end_idx_ ;
30
31   SCM transposed_musics_;
32   
33   DECLARE_SCHEME_CALLBACK (constructor, ()); 
34
35   bool accept_music_type (Music*) const;
36 protected:
37   virtual void derived_mark () const;
38   virtual void construct_children ();
39   virtual Moment pending_moment () const;
40   virtual void process (Moment);
41   virtual bool ok () const;
42 };
43
44 bool
45 Quote_iterator::accept_music_type (Music *mus) const
46 {
47   SCM accept = get_outlet()->get_property ("quotedEventTypes");
48   for (SCM s =  mus->get_property ("types");
49        scm_is_pair (s);  s = scm_cdr (s))
50     {
51       if (scm_memq (scm_car (s), accept) != SCM_BOOL_F)
52         return true;
53     }
54
55   return false;
56 }
57
58
59 void
60 Quote_iterator::derived_mark () const
61 {
62   scm_gc_mark (transposed_musics_ );
63 }
64
65 Quote_iterator::Quote_iterator ()
66 {
67   transposed_musics_ = SCM_EOL;
68   event_vector_ = SCM_EOL;
69   event_idx_ = 0;
70   end_idx_ = 0;
71 }
72
73 bool
74 moment_less (SCM a, SCM b)
75 {
76   return  *unsmob_moment (a) < *unsmob_moment (b);
77 }
78
79
80 int
81 binsearch_scm_vector (SCM vec, SCM key, bool (*is_less)(SCM a,SCM b))
82 {
83   int lo = 0;
84   int hi = SCM_VECTOR_LENGTH (vec);
85
86   /* binary search */
87   do
88   {
89     int cmp = (lo + hi) / 2;
90
91       SCM when = scm_caar (SCM_VECTOR_REF (vec, cmp));
92       bool result =  (*is_less) (key, when);
93       if (result)
94           hi = cmp;
95       else
96           lo = cmp;
97     }
98   while (hi - lo > 1);
99
100   return lo;
101 }
102
103
104 void
105 Quote_iterator::construct_children ()
106 {
107   SCM dur = get_music ()->get_property ("duration");
108   if (!unsmob_duration (dur))
109     return ;
110
111   set_translator (get_outlet ()->get_default_interpreter ());
112   
113   Moment now = get_outlet ()->now_mom ();
114   Moment stop = now + unsmob_duration (dur)->get_length ();
115
116   start_moment_ = now;
117   event_vector_ = get_music ()->get_property ("quoted-events");
118
119   if (ly_c_vector_p (event_vector_))
120     {
121       event_idx_ = binsearch_scm_vector (event_vector_, now.smobbed_copy (), &moment_less);
122       end_idx_ = binsearch_scm_vector (event_vector_, stop.smobbed_copy (), &moment_less);
123     }
124   else
125     {
126       get_music ()->origin()->warning (_("No events found for \\quote"));
127     }
128 }
129
130
131 bool
132 Quote_iterator::ok () const
133 {
134   return ly_c_vector_p (event_vector_) && (event_idx_ <= end_idx_);
135 }
136
137 Moment
138 Quote_iterator::pending_moment () const
139 {
140   return vector_moment (event_idx_) - start_moment_;
141 }
142
143 Moment
144 Quote_iterator::vector_moment (int idx) const
145 {
146   SCM entry = SCM_VECTOR_REF (event_vector_, idx);
147   return *unsmob_moment (scm_caar (entry));
148 }
149   
150
151 void
152 Quote_iterator::process (Moment m)
153 {
154   m += start_moment_;
155   while (event_idx_ <= end_idx_)
156     {
157       Moment em = vector_moment (event_idx_);
158       if (em > m)
159         return ;
160
161       if (em == m)
162         break ;
163
164       event_idx_++;
165     }
166
167   if (event_idx_ <= end_idx_)
168     {
169       SCM entry = SCM_VECTOR_REF (event_vector_, event_idx_);
170       Pitch * quote_pitch = unsmob_pitch (scm_cdar (entry));
171
172       /*
173         The pitch that sounds like central C
174        */
175       Pitch * me_pitch = unsmob_pitch (get_outlet ()->get_property ("instrumentTransposition"));
176       
177       for (SCM s = scm_cdr (entry); scm_is_pair (s); s = scm_cdr (s))
178         {
179           SCM ev_acc = scm_car (s);
180
181           Music * mus = unsmob_music (scm_car (ev_acc));
182           if (!mus)
183             programming_error ("need music in quote.");
184           else if (accept_music_type (mus))
185             {
186               if (quote_pitch || me_pitch)
187                 {
188                   Pitch qp, mp;
189                   if (quote_pitch)
190                     qp = *quote_pitch;
191                   if (me_pitch)
192                     mp = *me_pitch;
193
194                   Pitch diff = pitch_interval (qp, mp);
195
196                   SCM copy = ly_deep_mus_copy (mus->self_scm ());
197                   mus = unsmob_music (copy);
198                   transposed_musics_ = scm_cons (copy, transposed_musics_);
199
200                   
201                   mus->transpose (diff);
202                 }
203
204               
205               bool b = get_outlet ()->try_music (mus);
206       
207               if (!b)
208                 mus->origin ()->warning (_f ("In quotation: junking event %s", mus->name ()));
209             }
210         }
211     }
212   event_idx_ ++; 
213 }
214
215 IMPLEMENT_CTOR_CALLBACK (Quote_iterator);