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