]> git.donarmstrong.com Git - lilypond.git/blob - lily/grob-pq-engraver.cc
Revert "Issue 4550 (2/2) Avoid "using namespace std;" in included files"
[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 using std::vector;
28
29 struct Grob_pq_entry
30 {
31   Grob *grob_;
32   Moment end_;
33 };
34
35 bool
36 operator < (Grob_pq_entry const &a, Grob_pq_entry const &b)
37 {
38   return a.end_ < b.end_;
39 }
40
41 class Grob_pq_engraver : public Engraver
42 {
43 public:
44   TRANSLATOR_DECLARATIONS (Grob_pq_engraver);
45 protected:
46   virtual void initialize ();
47   DECLARE_ACKNOWLEDGER (grob);
48   void start_translation_timestep ();
49   void stop_translation_timestep ();
50   void process_acknowledged ();
51
52   vector<Grob_pq_entry> started_now_;
53 };
54
55 Grob_pq_engraver::Grob_pq_engraver ()
56 {
57 }
58
59 void
60 Grob_pq_engraver::initialize ()
61 {
62   context ()->set_property ("busyGrobs", SCM_EOL);
63 }
64
65 LY_DEFINE (ly_grob_pq_less_p, "ly:grob-pq<?",
66            2, 0, 0, (SCM a, SCM b),
67            "Compare two grob priority queue entries."
68            "  This is an internal function.")
69 {
70   if (Moment::compare (*unsmob<Moment> (scm_car (a)),
71                        *unsmob<Moment> (scm_car (b))) < 0)
72     return SCM_BOOL_T;
73   else
74     return SCM_BOOL_F;
75 }
76
77 void
78 Grob_pq_engraver::acknowledge_grob (Grob_info gi)
79 {
80   Stream_event *ev = gi.event_cause ();
81
82   if (ev
83       && !gi.grob ()->internal_has_interface (ly_symbol2scm ("multi-measure-interface")))
84     {
85       Moment n = now_mom ();
86       Moment l = get_event_length (ev, n);
87
88       if (!l.to_bool ())
89         return;
90
91       Moment end = n + l;
92
93       Grob_pq_entry e;
94       e.grob_ = gi.grob ();
95       e.end_ = end;
96
97       started_now_.push_back (e);
98     }
99 }
100
101 void
102 Grob_pq_engraver::process_acknowledged ()
103 {
104   vector_sort (started_now_, less<Grob_pq_entry> ());
105   SCM lst = SCM_EOL;
106   SCM *tail = &lst;
107   for (vsize i = 0; i < started_now_.size (); i++)
108     {
109       *tail = scm_acons (started_now_[i].end_.smobbed_copy (),
110                          started_now_[i].grob_->self_scm (),
111                          SCM_EOL);
112       tail = SCM_CDRLOC (*tail);
113     }
114
115   SCM busy = get_property ("busyGrobs");
116   busy = scm_merge_x (lst, busy, ly_grob_pq_less_p_proc);
117   context ()->set_property ("busyGrobs", busy);
118
119   started_now_.clear ();
120 }
121
122 void
123 Grob_pq_engraver::stop_translation_timestep ()
124 {
125   Moment now = now_mom ();
126   SCM start_busy = get_property ("busyGrobs");
127   SCM busy = start_busy;
128   while (scm_is_pair (busy) && *unsmob<Moment> (scm_caar (busy)) == now)
129     busy = scm_cdr (busy);
130
131 }
132
133 void
134 Grob_pq_engraver::start_translation_timestep ()
135 {
136   Moment now = now_mom ();
137
138   SCM start_busy = get_property ("busyGrobs");
139   SCM busy = start_busy;
140   while (scm_is_pair (busy) && *unsmob<Moment> (scm_caar (busy)) < now)
141     {
142       /*
143         The grob-pq-engraver is not water tight, and stuff like
144         tupletSpannerDuration confuses it.
145       */
146       busy = scm_cdr (busy);
147     }
148
149   if (start_busy != busy)
150     context ()->set_property ("busyGrobs", busy);
151 }
152
153 ADD_ACKNOWLEDGER (Grob_pq_engraver, grob);
154 ADD_TRANSLATOR (Grob_pq_engraver,
155                 /* doc */
156                 "Administrate when certain grobs (e.g., note heads) stop"
157                 " playing.",
158
159                 /* create */
160                 "",
161
162                 /* read */
163                 "busyGrobs ",
164
165                 /* write */
166                 "busyGrobs "
167                );