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