]> git.donarmstrong.com Git - lilypond.git/blob - lily/quote-iterator.cc
aca188b52f76ea155fa2cfe364a522aff903f2c7
[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   
25   Moment start_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
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        ly_c_pair_p (s);  s = ly_cdr (s))
49     {
50       if (scm_memq (ly_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 bool
73 moment_less (SCM a, SCM b)
74 {
75   return  *unsmob_moment (a) < *unsmob_moment (b);
76 }
77
78
79 int
80 binsearch_scm_vector (SCM vec, SCM key, bool (*is_less)(SCM a,SCM b))
81 {
82   int lo = 0;
83   int hi = SCM_VECTOR_LENGTH (vec);
84
85   /* binary search */
86   do
87   {
88     int cmp = (lo + hi) / 2;
89
90       SCM when = ly_caar (SCM_VECTOR_REF (vec, cmp));
91       bool result =  (*is_less) (key, when);
92       if (result)
93           hi = cmp;
94       else
95           lo = cmp;
96     }
97   while (hi - lo > 1);
98
99   return lo;
100 }
101
102
103 void
104 Quote_iterator::construct_children ()
105 {
106   SCM dur = get_music ()->get_property ("duration");
107   if (!unsmob_duration (dur))
108     return ;
109
110   set_translator (get_outlet ()->get_default_interpreter ());
111   
112   Moment now = get_outlet ()->now_mom ();
113   Moment stop = now + unsmob_duration (dur)->get_length ();
114
115   start_moment_ = now;
116   event_vector_ = get_music ()->get_property ("quoted-events");
117
118   if (ly_c_vector_p (event_vector_))
119     {
120       event_idx_ = binsearch_scm_vector (event_vector_, now.smobbed_copy (), &moment_less);
121       end_idx_ = binsearch_scm_vector (event_vector_, stop.smobbed_copy (), &moment_less);
122     }
123   else
124     {
125       get_music ()->origin()->warning (_("No events found for \\quote"));
126     }
127 }
128
129
130 bool
131 Quote_iterator::ok () const
132 {
133   return ly_c_vector_p (event_vector_) && (event_idx_ <= end_idx_);
134 }
135
136 Moment
137 Quote_iterator::pending_moment () const
138 {
139   SCM entry = SCM_VECTOR_REF (event_vector_, event_idx_);
140   return *unsmob_moment (ly_caar (entry)) - start_moment_;
141 }
142
143 void
144 Quote_iterator::process (Moment m)
145 {
146   SCM entry = SCM_EOL;
147
148   m += start_moment_;
149   while (event_idx_ < end_idx_)
150     {
151       entry = SCM_VECTOR_REF (event_vector_, event_idx_);
152
153       Moment em = *unsmob_moment (ly_caar (entry));
154
155       if (em > m)
156         return ;
157
158       if (em == m)
159         break ;
160
161       event_idx_++;
162     }
163
164   if (ly_c_pair_p (entry))
165     {
166       Pitch * quote_pitch = unsmob_pitch (ly_cdar (entry));
167       Pitch * me_pitch = unsmob_pitch (get_outlet ()->get_property ("instrumentTransposition"));
168       
169       for (SCM s = ly_cdr (entry); ly_c_pair_p (s); s = ly_cdr (s))
170         {
171           SCM ev_acc = ly_car (s);
172
173           Music * mus = unsmob_music (ly_car (ev_acc));
174           if (!mus)
175             programming_error ("need music in quote.");
176           else if (accept_music_type (mus))
177             {
178               if (quote_pitch || me_pitch)
179                 {
180                   Pitch qp, mp;
181                   if (quote_pitch)
182                     qp = *quote_pitch;
183                   if (me_pitch)
184                     mp = *me_pitch;
185
186                   Pitch diff = interval (mp, qp);
187
188                   SCM copy = ly_deep_mus_copy (mus->self_scm ());
189                   mus = unsmob_music (copy);
190                   transposed_musics_ = scm_cons (copy, transposed_musics_);
191
192                   
193                   mus->transpose (diff);
194                 }
195
196               
197               bool b = get_outlet ()->try_music (mus);
198       
199               if (!b)
200                 mus->origin ()->warning (_f ("In quotation: junking event %s", mus->name ()));
201             }
202         }
203     }
204   event_idx_ ++; 
205 }
206
207 IMPLEMENT_CTOR_CALLBACK (Quote_iterator);