]> git.donarmstrong.com Git - lilypond.git/blob - lily/grob-pq-engraver.cc
Update.
[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--2005  Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "context.hh"
10 #include "engraver.hh"
11 #include "grob.hh"
12 #include "warn.hh"
13
14 class Grob_pq_engraver : public Engraver
15 {
16 public:
17   TRANSLATOR_DECLARATIONS (Grob_pq_engraver);
18 protected:
19   virtual void initialize ();
20   virtual void acknowledge_grob (Grob_info);
21   virtual void start_translation_timestep ();
22   virtual void stop_translation_timestep ();
23 };
24
25 Grob_pq_engraver::Grob_pq_engraver ()
26 {
27 }
28
29 void
30 Grob_pq_engraver::initialize ()
31 {
32   context ()->set_property ("busyGrobs", SCM_EOL);
33 }
34
35 LY_DEFINE (ly_grob_pq_less_p, "ly:grob-pq-less?",
36            2, 0, 0, (SCM a, SCM b),
37            "Compare 2 grob priority queue entries. Internal")
38 {
39   if (Moment::compare (*unsmob_moment (scm_car (a)),
40                        *unsmob_moment (scm_car (b))) < 0)
41     return SCM_BOOL_T;
42   else
43     return SCM_BOOL_F;
44 }
45
46 void
47 Grob_pq_engraver::acknowledge_grob (Grob_info gi)
48 {
49   Music *m = gi.music_cause ();
50
51   if (m
52       && !gi.grob_->internal_has_interface (ly_symbol2scm ("multi-measure-interface")))
53     {
54       Moment n = now_mom ();
55       Moment l = m->get_length ();
56
57       if (!l.to_bool ())
58         return;
59
60       if (n.grace_part_)
61         {
62           l.grace_part_ = l.main_part_;
63           l.main_part_ = 0;
64         }
65
66       Moment end = n + l;
67       SCM lst = scm_acons (end.smobbed_copy (),
68                            gi.grob_->self_scm (),
69                            SCM_EOL);
70
71       SCM busy = get_property ("busyGrobs");
72       busy = scm_merge_x (lst, busy, ly_grob_pq_less_p_proc);
73       context ()->set_property ("busyGrobs", busy);
74     }
75 }
76
77 void
78 Grob_pq_engraver::stop_translation_timestep ()
79 {
80   Moment now = now_mom ();
81   SCM start_busy = get_property ("busyGrobs");
82   SCM busy = start_busy;
83   while (scm_is_pair (busy) && *unsmob_moment (scm_caar (busy)) == now)
84     {
85       busy = scm_cdr (busy);
86     }
87
88   if (start_busy != busy)
89     context ()->set_property ("busyGrobs", busy);
90 }
91
92 void
93 Grob_pq_engraver::start_translation_timestep ()
94 {
95   Moment now = now_mom ();
96
97   SCM start_busy = get_property ("busyGrobs");
98   SCM busy = start_busy;
99   while (scm_is_pair (busy) && *unsmob_moment (scm_caar (busy)) < now)
100     {
101       /*
102         The grob-pq-engraver is not water tight, and stuff like
103         tupletSpannerDuration confuses it.
104       */
105       busy = scm_cdr (busy);
106     }
107
108   if (start_busy != busy)
109     context ()->set_property ("busyGrobs", busy);
110 }
111
112 ADD_TRANSLATOR (Grob_pq_engraver,
113
114                 /* descr */ "Administrate when certain grobs (eg. note heads) stop playing; this \
115 engraver is a sort-of a failure, since it doesn't handle all sorts of \
116 borderline cases very well. \
117 ",
118
119                 /* creats*/ "",\
120                 /* accepts */ "",\
121                 /* acks  */ "grob-interface",\
122                 /* reads */ "busyGrobs",\
123                 /* write */ "busyGrobs");