]> git.donarmstrong.com Git - lilypond.git/blob - lily/new-tie-engraver.cc
8ee6d218fff8ccf173ea4cdd257628df8529440e
[lilypond.git] / lily / new-tie-engraver.cc
1 /*   
2   new-tie-engraver.cc --  implement Tie_engraver
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 1998--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9
10 #include "event.hh"
11 #include "tie.hh"
12 #include "translator-group.hh"
13 #include "spanner.hh"
14 #include "tie-column.hh"
15 #include "engraver.hh"
16 #include "item.hh"
17 #include "grob-pitch-tuple.hh"
18 #include "warn.hh"
19 #include "note-head.hh"
20
21 /**
22    Manufacture ties.  Acknowledge noteheads, and put them into a
23    priority queue. If we have a TieEvent, connect the notes that finish
24    just at this time, and note that start at this time.
25
26    TODO: Remove the dependency on musical info. We should tie on the
27    basis of position and duration-log of the heads (not of the events).
28
29    TODO: support sparseTies.
30
31    TODO: melismata will fuck up now:
32
33    < { c8 ~ c8 }
34      { c16 c c c  } >
35
36    melisma is after the 2nd 8th note, but will now be signaled as
37    lasting till the 3rd 16th.
38 */
39 class New_tie_engraver : public Engraver
40 {
41   Music *event_;
42   Music *last_event_;
43   Link_array<Grob> now_heads_;
44   Link_array<Grob> heads_to_tie_;
45   Link_array<Grob> ties_;
46   
47   Spanner * tie_column_;
48   
49   
50 protected:
51   virtual void stop_translation_timestep ();
52   virtual void acknowledge_grob (Grob_info);
53   virtual bool try_music (Music*);
54   virtual void process_acknowledged_grobs ();
55   void typeset_tie (Grob*);
56 public:
57   TRANSLATOR_DECLARATIONS(New_tie_engraver);
58 };
59
60
61
62 New_tie_engraver::New_tie_engraver ()
63 {
64   event_ = 0;
65   last_event_  = 0;
66   tie_column_ = 0;
67 }
68
69
70 bool
71 New_tie_engraver::try_music (Music *mus)
72 {
73   if (mus->is_mus_type ("new-tie-event"))
74     {
75       event_ = mus;
76     }
77   
78   if (event_)
79     {
80       SCM m = get_property ("automaticMelismata");
81       bool am = gh_boolean_p (m) &&gh_scm2bool (m);
82       if (am)
83         {
84   daddy_trans_->set_property ("tieMelismaBusy", m ? SCM_BOOL_T : SCM_BOOL_F);
85         }
86     }
87   return true;
88 }
89
90 void
91 New_tie_engraver::acknowledge_grob (Grob_info i)
92 {
93   if (Note_head::has_interface (i.grob_))
94     {
95       Grob * h  = i.grob_;
96       now_heads_.push (h);
97       for  (int  i=heads_to_tie_.size (); i--;)
98         {
99           Grob *th =  heads_to_tie_[i];
100           int staff_pos = gh_scm2int (h->get_grob_property ("staff-position"));
101           int left_staff_pos = gh_scm2int (th->get_grob_property ("staff-position"));
102           if (staff_pos == left_staff_pos)
103             {
104               Grob * p = new Spanner (get_property ("Tie"));
105               Tie::set_interface (p); // cannot remove yet!
106           
107               Tie::set_head (p, LEFT, th);
108               Tie::set_head (p, RIGHT, h);
109           
110               ties_.push (p);
111               announce_grob(p, last_event_->self_scm());
112             }
113         }
114     }
115 }
116
117 void
118 New_tie_engraver::process_acknowledged_grobs ()
119 {
120   if (ties_.size () > 1 && !tie_column_)
121     {
122       tie_column_ = new Spanner (get_property ("TieColumn"));
123       
124       for (int i = ties_.size (); i--;)
125         Tie_column::add_tie (tie_column_,ties_ [i]);
126
127       announce_grob(tie_column_, SCM_EOL);
128     }
129 }
130
131
132 void
133 New_tie_engraver::stop_translation_timestep ()
134 {
135
136   if (ties_.size ())
137     {
138       heads_to_tie_.clear ();
139       for (int i=0; i<  ties_.size (); i++)
140         {
141           typeset_tie (ties_[i]);
142         }
143
144       ties_.clear();
145       last_event_ = 0;
146       if (tie_column_)
147         {
148           typeset_grob (tie_column_);
149           tie_column_ =0;
150         }
151     }
152   
153   if (event_)
154     {
155       heads_to_tie_ = now_heads_;
156       last_event_ = event_;
157     }
158   event_ = 0;
159   now_heads_.clear ();
160 }
161
162 void
163 New_tie_engraver::typeset_tie (Grob *her)
164 {
165   if (! (Tie::head (her,LEFT) && Tie::head (her,RIGHT)))
166     warning (_ ("lonely tie"));
167
168   Direction d = LEFT;
169   Drul_array<Grob *> new_head_drul;
170   new_head_drul[LEFT] = Tie::head (her,LEFT);
171   new_head_drul[RIGHT] = Tie::head (her,RIGHT);  
172   do {
173     if (!Tie::head (her,d))
174       new_head_drul[d] = Tie::head (her, (Direction)-d);
175   } while (flip (&d) != LEFT);
176
177   index_set_cell (her->get_grob_property ("heads"), LEFT, new_head_drul[LEFT]->self_scm ());
178   index_set_cell (her->get_grob_property ("heads"), RIGHT, new_head_drul[RIGHT]->self_scm ());
179
180   typeset_grob (her);
181 }
182
183
184 ENTER_DESCRIPTION(New_tie_engraver,
185 /* descr */       "Generate ties between noteheads of equal pitch.",
186 /* creats*/       "Tie TieColumn",
187 /* accepts */     "new-tie-event",
188 /* acks  */      "rhythmic-head-interface",
189 /* reads */       "tieMelismaBusy",
190 /* write */       "");