]> git.donarmstrong.com Git - lilypond.git/blob - lily/tie-performer.cc
release: 1.3.118
[lilypond.git] / lily / tie-performer.cc
1 /*   
2   tie-performer.cc --  implement Tie_performer
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 1999--2000 Jan Nieuwenhuizen <janneke@gnu.org>
7   
8  */
9
10 #include "command-request.hh"
11 #include "audio-item.hh"
12 #include "musical-request.hh"
13 #include "pqueue.hh"
14 #include "performer.hh"
15
16 struct CNote_melodic_tuple {
17   Melodic_req *req_l_ ;
18   Audio_note *note_l_;
19   Moment end_;
20   CNote_melodic_tuple ();
21   CNote_melodic_tuple (Audio_note*, Melodic_req*, Moment);
22   static int pitch_compare (CNote_melodic_tuple const &, CNote_melodic_tuple const &);
23   static int time_compare (CNote_melodic_tuple const &, CNote_melodic_tuple const &);  
24 };
25
26 inline int compare (CNote_melodic_tuple const &a, CNote_melodic_tuple const &b)
27 {
28   return CNote_melodic_tuple::time_compare (a,b);
29 }
30
31
32 /**
33    Manufacture ties.  Acknowledge notes, and put them into a
34    priority queue. If we have a Tie_req, connect the notes that finish
35    just at this time, and note that start at this time.
36
37    TODO: should share code with Tie_engraver ?
38  */
39 class Tie_performer : public Performer
40 {
41 public:
42   VIRTUAL_COPY_CONS(Translator);
43   Tie_performer ();
44 private:
45   bool done_;
46   PQueue<CNote_melodic_tuple> past_notes_pq_;
47   Tie_req *req_l_;
48   Array<CNote_melodic_tuple> now_notes_;
49   Array<CNote_melodic_tuple> stopped_notes_;
50   Link_array<Audio_tie> tie_p_arr_;
51   
52 protected:
53   virtual void initialize ();
54   virtual void start_translation_timestep ();
55   virtual void stop_translation_timestep ();
56   virtual void acknowledge_audio_element (Audio_element_info);
57   virtual bool try_music (Music*);
58   virtual void create_audio_elements ();
59 };
60
61
62 Tie_performer::Tie_performer ()
63 {
64   req_l_ = 0;
65   done_ = false;
66 }
67
68 ADD_THIS_TRANSLATOR (Tie_performer);
69
70
71 #if 0
72 Tie_performer::Tie_performer ()
73 {
74   // URG
75   // if we don't do this, lily dumps core
76   // which means that ``initialize'' and
77   // ``start_translation_timestep'' did not happen?!
78   initialize ();
79 }
80 #endif
81
82 void
83 Tie_performer::initialize ()
84 {
85   req_l_ = 0;
86 }
87
88
89 bool
90 Tie_performer::try_music (Music *m)
91 {
92   if (!req_l_)
93     {
94       if (Tie_req * c = dynamic_cast<Tie_req*> (m))
95         {
96           req_l_ = c;
97           return true;
98         }
99     }
100   return false;
101 }
102
103 void
104 Tie_performer::acknowledge_audio_element (Audio_element_info i)
105 {
106   if (Audio_note *nh = dynamic_cast<Audio_note *> (i.elem_l_))
107     {
108       Note_req * m = dynamic_cast<Note_req* > (i.req_l_);
109       if (!m)
110         return;
111       now_notes_.push (CNote_melodic_tuple (nh, m, now_mom()+ m->length_mom ()));
112     }
113 }
114
115 void
116 Tie_performer::create_audio_elements ()
117 {
118   if (req_l_ && ! done_)
119     {
120       Moment now = now_mom ();
121       Link_array<Audio_note> nharr;
122       
123       stopped_notes_.clear ();
124       while (past_notes_pq_.size ()
125              && past_notes_pq_.front ().end_ == now)
126         stopped_notes_.push (past_notes_pq_.get ());
127       done_ = true;
128       return;
129     }
130
131   if (req_l_)
132     {
133       now_notes_.sort (CNote_melodic_tuple::pitch_compare);
134       stopped_notes_.sort(CNote_melodic_tuple::pitch_compare);
135       int i=0;
136       int j=0;
137       int tie_count=0;
138       while  ( i < now_notes_.size () && j < stopped_notes_.size ())
139         {
140           int comp
141             = Pitch::compare (*unsmob_pitch (now_notes_[i].req_l_->get_mus_property ("pitch") ),
142                                       *unsmob_pitch (stopped_notes_[j].req_l_->get_mus_property ("pitch")));
143
144           if (comp)
145             {
146               (comp < 0) ? i ++ : j++;
147               continue;
148             }
149           else
150             {
151               tie_count ++;
152
153               /* don't go around recreating ties that were already
154                  made. Not infallible. Due to reordering in sort (),
155                  we will make the wrong ties when notenotes are
156                  added.  */
157               if (tie_count > tie_p_arr_.size ())
158                 {
159                   Audio_tie * p = new Audio_tie;
160                   p->set_note (LEFT, stopped_notes_[j].note_l_);
161                   p->set_note (RIGHT, now_notes_[i].note_l_);
162                   tie_p_arr_.push (p);
163                       announce_element (Audio_element_info (p, req_l_));
164                 }
165               i++;
166               j++;
167               
168             }
169         }
170       
171       if (!tie_p_arr_.size ())
172         {
173           req_l_->origin ()->warning (_("No ties were created!"));
174         }
175     }
176 }
177
178 void
179 Tie_performer::stop_translation_timestep ()
180 {
181   for (int i=0; i < now_notes_.size (); i++)
182     {
183       past_notes_pq_.insert (now_notes_[i]);
184     }
185   now_notes_.clear ();
186
187   for (int i=0; i<  tie_p_arr_.size (); i++)
188    {
189      //play_element (tie_p_arr_[i]);
190      tie_p_arr_[i]->note_l_drul_[RIGHT]->tie_to (tie_p_arr_[i]->note_l_drul_[LEFT]);
191    }
192   tie_p_arr_.clear ();
193 }
194
195 void
196 Tie_performer::start_translation_timestep ()
197 {
198   req_l_ =0;
199   done_ = false;
200   Moment now = now_mom ();
201   while (past_notes_pq_.size () && past_notes_pq_.front ().end_ < now)
202     past_notes_pq_.delmin ();
203 }
204
205
206 CNote_melodic_tuple::CNote_melodic_tuple ()
207 {
208   note_l_ =0;
209   req_l_ =0;
210   end_ = 0;
211 }
212
213 CNote_melodic_tuple::CNote_melodic_tuple (Audio_note *h, Melodic_req*m, Moment mom)
214 {
215   note_l_ = h;
216   req_l_ = m;
217   end_ = mom;
218 }
219
220 int
221 CNote_melodic_tuple::pitch_compare (CNote_melodic_tuple const&h1,
222                                     CNote_melodic_tuple const &h2)
223 {
224   SCM p1  = h1.req_l_->get_mus_property ("pitch");
225   SCM p2  = h2.req_l_->get_mus_property ("pitch");  
226   return Pitch::compare (*unsmob_pitch (p1),
227                                *unsmob_pitch (p2));
228 }
229
230 int
231 CNote_melodic_tuple::time_compare (CNote_melodic_tuple const&h1,
232                                    CNote_melodic_tuple const &h2)
233 {
234   return (h1.end_ - h2.end_ ).sign ();
235 }