]> git.donarmstrong.com Git - lilypond.git/blob - lily/grob-pq-engraver.cc
Issue 4997/6: Use Preinit for font metrics
[lilypond.git] / lily / grob-pq-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2001--2015  Han-Wen Nienhuys <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "context.hh"
21 #include "engraver.hh"
22 #include "grob.hh"
23 #include "warn.hh"
24
25 #include "translator.icc"
26
27 struct Grob_pq_entry
28 {
29   Grob *grob_;
30   Moment end_;
31 };
32
33 bool
34 operator < (Grob_pq_entry const &a, Grob_pq_entry const &b)
35 {
36   return a.end_ < b.end_;
37 }
38
39 class Grob_pq_engraver : public Engraver
40 {
41 public:
42   TRANSLATOR_DECLARATIONS (Grob_pq_engraver);
43 protected:
44   virtual void initialize ();
45   void acknowledge_grob (Grob_info);
46   void start_translation_timestep ();
47   void stop_translation_timestep ();
48   void process_acknowledged ();
49
50   vector<Grob_pq_entry> started_now_;
51 };
52
53 Grob_pq_engraver::Grob_pq_engraver ()
54 {
55 }
56
57 void
58 Grob_pq_engraver::initialize ()
59 {
60   context ()->set_property ("busyGrobs", SCM_EOL);
61 }
62
63 LY_DEFINE (ly_grob_pq_less_p, "ly:grob-pq<?",
64            2, 0, 0, (SCM a, SCM b),
65            "Compare two grob priority queue entries."
66            "  This is an internal function.")
67 {
68   if (Moment::compare (*unsmob<Moment> (scm_car (a)),
69                        *unsmob<Moment> (scm_car (b))) < 0)
70     return SCM_BOOL_T;
71   else
72     return SCM_BOOL_F;
73 }
74
75 void
76 Grob_pq_engraver::acknowledge_grob (Grob_info gi)
77 {
78   Stream_event *ev = gi.event_cause ();
79
80   if (ev
81       && !gi.grob ()->internal_has_interface (ly_symbol2scm ("multi-measure-interface")))
82     {
83       Moment n = now_mom ();
84       Moment l = get_event_length (ev, n);
85
86       if (!l.to_bool ())
87         return;
88
89       Moment end = n + l;
90
91       Grob_pq_entry e;
92       e.grob_ = gi.grob ();
93       e.end_ = end;
94
95       started_now_.push_back (e);
96     }
97 }
98
99 void
100 Grob_pq_engraver::process_acknowledged ()
101 {
102   vector_sort (started_now_, less<Grob_pq_entry> ());
103   SCM lst = SCM_EOL;
104   SCM *tail = &lst;
105   for (vsize i = 0; i < started_now_.size (); i++)
106     {
107       *tail = scm_acons (started_now_[i].end_.smobbed_copy (),
108                          started_now_[i].grob_->self_scm (),
109                          SCM_EOL);
110       tail = SCM_CDRLOC (*tail);
111     }
112
113   SCM busy = get_property ("busyGrobs");
114   busy = scm_merge_x (lst, busy, ly_grob_pq_less_p_proc);
115   context ()->set_property ("busyGrobs", busy);
116
117   started_now_.clear ();
118 }
119
120 void
121 Grob_pq_engraver::stop_translation_timestep ()
122 {
123   Moment now = now_mom ();
124   SCM start_busy = get_property ("busyGrobs");
125   SCM busy = start_busy;
126   while (scm_is_pair (busy) && *unsmob<Moment> (scm_caar (busy)) == now)
127     busy = scm_cdr (busy);
128
129 }
130
131 void
132 Grob_pq_engraver::start_translation_timestep ()
133 {
134   Moment now = now_mom ();
135
136   SCM start_busy = get_property ("busyGrobs");
137   SCM busy = start_busy;
138   while (scm_is_pair (busy) && *unsmob<Moment> (scm_caar (busy)) < now)
139     {
140       /*
141         The grob-pq-engraver is not water tight, and stuff like
142         tupletSpannerDuration confuses it.
143       */
144       busy = scm_cdr (busy);
145     }
146
147   if (start_busy != busy)
148     context ()->set_property ("busyGrobs", busy);
149 }
150
151 void
152 Grob_pq_engraver::boot ()
153 {
154   ADD_ACKNOWLEDGER (Grob_pq_engraver, grob);
155 }
156
157 ADD_TRANSLATOR (Grob_pq_engraver,
158                 /* doc */
159                 "Administrate when certain grobs (e.g., note heads) stop"
160                 " playing.",
161
162                 /* create */
163                 "",
164
165                 /* read */
166                 "busyGrobs ",
167
168                 /* write */
169                 "busyGrobs "
170                );