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