]> git.donarmstrong.com Git - lilypond.git/blob - lily/grob-pq-engraver.cc
2003 -> 2004
[lilypond.git] / lily / grob-pq-engraver.cc
1 /*   
2   grob-pq-engraver.cc --  implement Grob_pq_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2001--2004  Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "translator-group.hh"
10 #include "engraver.hh"
11 #include "grob.hh"
12 #include "warn.hh"
13
14 /*
15   TODO: should junk this engraver.
16  */
17
18 struct Grob_mom
19 {
20   Grob * grob_ ;
21   Moment end_;
22   Grob_mom () {}
23   Grob_mom (Grob*gr, Moment e)
24   {
25     grob_ = gr;
26     end_ = e;
27   }
28 };
29
30 int compare  (Grob_mom const &a, Grob_mom const &b)
31 {
32   return Moment::compare (a.end_, b.end_);
33 }
34
35 /****************/
36
37 class Grob_pq_engraver: public Engraver
38 {
39 public:
40   TRANSLATOR_DECLARATIONS(Grob_pq_engraver);
41
42   Array<Grob_mom> current_grobs_;
43 protected:
44   virtual void initialize ();
45   virtual void acknowledge_grob (Grob_info);
46   virtual void start_translation_timestep ();
47   virtual void stop_translation_timestep ();
48 };
49
50
51 Grob_pq_engraver::Grob_pq_engraver()
52 {
53 }
54
55
56 void
57 Grob_pq_engraver::initialize ()
58 {
59   daddy_trans_->set_property ("busyGrobs", SCM_EOL); 
60 }
61
62 void
63 Grob_pq_engraver::acknowledge_grob (Grob_info gi)
64 {
65   Music  * m = gi.music_cause ();
66
67   if (m
68       && !gi.grob_->internal_has_interface (ly_symbol2scm ("multi-measure-interface")))
69     {
70       Moment n = now_mom ();
71       Moment l = m->get_length ();
72
73       if (!l.to_bool ())
74         return ;
75       
76       if (n.grace_part_)
77         {
78           l.grace_part_ = l.main_part_;
79           l.main_part_ = 0;
80         }
81
82       current_grobs_.push (Grob_mom (gi.grob_, n + l));
83     }
84 }
85
86 LY_DEFINE(ly_grob_pq_less_p, 
87           "ly:grob-pq-less?", 2 , 0 ,0, (SCM a, SCM b), 
88           "Compare 2 Grob PQ entries. Internal")
89 {
90   if ( Moment::compare (*unsmob_moment (gh_car (a)),
91                                       *unsmob_moment (gh_car (b))) < 0)
92     return SCM_BOOL_T;
93   else
94     return SCM_BOOL_F;
95 }
96           
97
98 void
99 Grob_pq_engraver::stop_translation_timestep ()
100 {
101   Moment now = now_mom();
102
103   current_grobs_.sort (&compare);
104   SCM current_list = SCM_EOL;
105   for (int i = current_grobs_.size(); i--;)
106     current_list = scm_cons (scm_cons (current_grobs_[i].end_.smobbed_copy(), 
107                                        current_grobs_[i].grob_->self_scm ()), current_list);
108
109   /*
110     We generate some garbage here.
111    */
112   SCM busy = get_property ("busyGrobs");
113   while (gh_pair_p (busy) && *unsmob_moment (gh_caar (busy)) == now)
114     {
115       busy = gh_cdr (busy);
116     }
117   
118   busy = scm_merge_x (current_list, busy, ly_grob_pq_less_p_proc);
119   current_grobs_.clear ();
120   daddy_trans_->set_property ("busyGrobs", busy);
121 }
122
123 void
124 Grob_pq_engraver::start_translation_timestep ()
125 {
126   Moment now = now_mom();
127
128   SCM start_busy = get_property ("busyGrobs");
129   SCM busy = start_busy;
130   while (gh_pair_p (busy) && *unsmob_moment (gh_caar (busy)) < now)
131     {
132       /*
133         Todo: do something sensible. The grob-pq-engraver is not water
134         tight, and stuff like tupletSpannerDuration confuses it.
135        */
136       programming_error (_f("Skipped something?\nGrob %s ended before I expected it to end.", unsmob_grob (gh_cdar (busy))->name().to_str0()));
137       
138       busy = gh_cdr (busy);
139     }
140
141   if (start_busy != busy)
142     daddy_trans_->set_property ("busyGrobs", busy);
143
144 }
145
146
147 ENTER_DESCRIPTION(Grob_pq_engraver,
148
149 /* descr */       "Administrate when certain grobs (eg. note heads) stop playing; this \
150 engraver is a sort-of a failure, since it doesn't handle all sorts of \
151 borderline cases very well. \
152 ",                                                                                                \
153                   
154 /* creats*/       "",                                                                             \
155 /* accepts */     "",                                                                             \
156 /* acks  */      "grob-interface",                                                                \
157 /* reads */       "busyGrobs",                                                                    \
158 /* write */       "busyGrobs");