]> git.donarmstrong.com Git - lilypond.git/blob - lily/grob-pq-engraver.cc
6f6ee8faabd901ba2b851af7d52c6e5cf79c4cc5
[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--2006  Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "context.hh"
10 #include "engraver.hh"
11 #include "grob.hh"
12 #include "warn.hh"
13
14 struct Grob_pq_entry
15 {
16   Grob *grob_;
17   Moment end_;
18 };
19
20 bool
21 operator< (Grob_pq_entry const &a, Grob_pq_entry const &b)
22 {
23   return a.end_ < b.end_;
24 }
25
26 class Grob_pq_engraver : public Engraver
27 {
28 public:
29   TRANSLATOR_DECLARATIONS (Grob_pq_engraver);
30 protected:
31   virtual void initialize ();
32   DECLARE_ACKNOWLEDGER (grob);
33   void start_translation_timestep ();
34   void stop_translation_timestep ();
35
36   vector<Grob_pq_entry> started_now_;
37 };
38
39 Grob_pq_engraver::Grob_pq_engraver ()
40 {
41 }
42
43 void
44 Grob_pq_engraver::initialize ()
45 {
46   context ()->set_property ("busyGrobs", SCM_EOL);
47 }
48
49 LY_DEFINE (ly_grob_pq_less_p, "ly:grob-pq-less?",
50            2, 0, 0, (SCM a, SCM b),
51            "Compare 2 grob priority queue entries. Internal")
52 {
53   if (Moment::compare (*unsmob_moment (scm_car (a)),
54                        *unsmob_moment (scm_car (b))) < 0)
55     return SCM_BOOL_T;
56   else
57     return SCM_BOOL_F;
58 }
59
60 void
61 Grob_pq_engraver::acknowledge_grob (Grob_info gi)
62 {
63   Stream_event *ev = gi.event_cause ();
64
65   if (ev
66       && !gi.grob ()->internal_has_interface (ly_symbol2scm ("multi-measure-interface")))
67     {
68       Moment n = now_mom ();
69       Moment l = get_event_length (ev);
70
71       if (!l.to_bool ())
72         return;
73
74       if (n.grace_part_)
75         {
76           l.grace_part_ = l.main_part_;
77           l.main_part_ = 0;
78         }
79
80       Moment end = n + l;
81
82       Grob_pq_entry e;
83       e.grob_ = gi.grob ();
84       e.end_ = end;
85
86       started_now_.push_back (e);
87     }
88 }
89
90 void
91 Grob_pq_engraver::stop_translation_timestep ()
92 {
93   Moment now = now_mom ();
94   SCM start_busy = get_property ("busyGrobs");
95   SCM busy = start_busy;
96   while (scm_is_pair (busy) && *unsmob_moment (scm_caar (busy)) == now)
97     busy = scm_cdr (busy);
98
99   vector_sort (started_now_, less<Grob_pq_entry> ());
100   SCM lst = SCM_EOL;
101   SCM *tail = &lst;
102   for (vsize i = 0; i < started_now_.size (); i++)
103     {
104       *tail = scm_acons (started_now_[i].end_.smobbed_copy (),
105                          started_now_[i].grob_->self_scm (),
106                          SCM_EOL);
107       tail = SCM_CDRLOC (*tail);
108     }
109
110   busy = scm_merge_x (lst, busy, ly_grob_pq_less_p_proc);
111   context ()->set_property ("busyGrobs", busy);
112
113   started_now_.clear ();
114 }
115
116 void
117 Grob_pq_engraver::start_translation_timestep ()
118 {
119   Moment now = now_mom ();
120
121   SCM start_busy = get_property ("busyGrobs");
122   SCM busy = start_busy;
123   while (scm_is_pair (busy) && *unsmob_moment (scm_caar (busy)) < now)
124     {
125       /*
126         The grob-pq-engraver is not water tight, and stuff like
127         tupletSpannerDuration confuses it.
128       */
129       busy = scm_cdr (busy);
130     }
131
132   if (start_busy != busy)
133     context ()->set_property ("busyGrobs", busy);
134 }
135
136 #include "translator.icc"
137 ADD_ACKNOWLEDGER (Grob_pq_engraver, grob);
138 ADD_TRANSLATOR (Grob_pq_engraver,
139
140                 /* doc */ "Administrate when certain grobs (eg. note heads) stop playing",
141                 /* create */ "",
142                 /* accept */ "",
143                 /* read */ "busyGrobs",
144                 /* write */ "busyGrobs");