]> git.donarmstrong.com Git - lilypond.git/blob - lily/tie-performer.cc
* configure.in: bump GCC requirements to 3.x
[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--2003 Jan Nieuwenhuizen <janneke@gnu.org>
7   
8  */
9
10
11 #include "audio-item.hh"
12 #include "event.hh"
13 #include "pqueue.hh"
14 #include "performer.hh"
15
16 struct CNote_melodic_tuple {
17   Music *event_ ;
18   Audio_note *note_;
19   Moment end_;
20   CNote_melodic_tuple ();
21   CNote_melodic_tuple (Audio_note*, Music*, 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 Music, 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   TRANSLATOR_DECLARATIONS(Tie_performer);
43 private:
44   bool done_;
45   
46   Array<CNote_melodic_tuple> now_notes_;
47   Array<CNote_melodic_tuple> tied_notes_;
48
49   Music *event_;
50   Music * prev_event_;
51   
52   Link_array<Audio_tie> ties_;
53   
54 protected:
55   virtual void initialize ();
56   virtual void start_translation_timestep ();
57   virtual void stop_translation_timestep ();
58   virtual void acknowledge_audio_element (Audio_element_info);
59   virtual bool try_music (Music*);
60   virtual void create_audio_elements ();
61 };
62
63
64 Tie_performer::Tie_performer ()
65 {
66   event_ = 0;
67   done_ = false;
68 }
69
70 ENTER_DESCRIPTION (Tie_performer, "", "",
71                    "tie-event",
72                    "", "", "");
73
74
75 void
76 Tie_performer::initialize ()
77 {
78   event_ = 0;
79 }
80
81
82 bool
83 Tie_performer::try_music (Music *m)
84 {
85   if (!event_)
86     {
87       event_ = m;
88       return true;
89     }
90   return false;
91 }
92
93 void
94 Tie_performer::acknowledge_audio_element (Audio_element_info i)
95 {
96   if (Audio_note *nh = dynamic_cast<Audio_note *> (i.elem_))
97     {
98       Music *m = i.event_;
99       if (m->is_mus_type ("note-event"))
100         now_notes_.push (CNote_melodic_tuple (nh, m, now_mom ()+ m->get_length ()));
101     }
102 }
103
104 void
105 Tie_performer::create_audio_elements ()
106 {
107   /*
108     This is a nested loop. Not optimal, but good enough.
109    */
110   if (tied_notes_.size ())
111     {
112       Moment now = now_mom();
113       for (int i = tied_notes_.size (); i--; )
114         {
115           if (tied_notes_[i].end_ != now)
116             continue;
117
118           for (int j = now_notes_.size(); j--;)
119             {
120               int comp
121                 = Pitch::compare (*unsmob_pitch (tied_notes_[i].event_->get_mus_property ("pitch")),
122                                   *unsmob_pitch (now_notes_[j].event_->get_mus_property ("pitch")));
123
124               if (comp == 0)
125                 {
126                   
127                   Audio_tie * p = new Audio_tie;
128                   p->set_note (LEFT, tied_notes_[i].note_);
129                   p->set_note (RIGHT, now_notes_[j].note_);
130                   ties_.push (p);
131                   announce_element (Audio_element_info (p, event_));
132
133                   tied_notes_.del (i);
134                 }
135             }
136         }
137     }
138 }
139
140
141 void
142 Tie_performer::stop_translation_timestep ()
143 {
144   if (prev_event_ && tied_notes_.size () && !ties_.size ())
145     {
146       prev_event_->origin ()->warning (_ ("No ties were performed."));
147     }
148   else
149     prev_event_ = 0;
150   
151   if (event_)
152     {
153       tied_notes_ = now_notes_ ;
154       prev_event_ = event_;
155     }
156   else
157     {
158       tied_notes_.clear (); 
159     }
160
161   event_ = 0;
162   now_notes_ .clear ();
163
164   for (int i=0; i<  ties_.size (); i++)
165     {
166       ties_[i]->note_drul_[RIGHT]->tie_to (ties_[i]->note_drul_[LEFT]);
167     }
168   
169   ties_.clear ();
170 }
171
172 void
173 Tie_performer::start_translation_timestep ()
174 {
175   event_ =0;
176   done_ = false;
177   Moment now = now_mom ();
178   for (int i= tied_notes_.size ();
179        i -- ;)
180     {
181       if (tied_notes_[i].end_ < now)
182         tied_notes_.del (i);
183       else
184         break ;
185     }
186 }
187
188
189 CNote_melodic_tuple::CNote_melodic_tuple ()
190 {
191   note_ =0;
192   event_ =0;
193   end_ = 0;
194 }
195
196 CNote_melodic_tuple::CNote_melodic_tuple (Audio_note *h, Music*m, Moment mom)
197 {
198   note_ = h;
199   event_ = m;
200   end_ = mom;
201 }
202
203 int
204 CNote_melodic_tuple::pitch_compare (CNote_melodic_tuple const&h1,
205                                     CNote_melodic_tuple const &h2)
206 {
207   SCM p1  = h1.event_->get_mus_property ("pitch");
208   SCM p2  = h2.event_->get_mus_property ("pitch");  
209   return Pitch::compare (*unsmob_pitch (p1),
210                                *unsmob_pitch (p2));
211 }
212
213 int
214 CNote_melodic_tuple::time_compare (CNote_melodic_tuple const&h1,
215                                    CNote_melodic_tuple const &h2)
216 {
217   return (h1.end_ - h2.end_).main_part_.sign ();
218 }
219