]> git.donarmstrong.com Git - lilypond.git/blob - lily/metronome-engraver.cc
Issue 4957: parser.yy: loc_on_music -> loc_on_copy
[lilypond.git] / lily / metronome-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1998--2015 Jan Nieuwenhuizen <janneke@gnu.org>
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 <cctype>
21 using namespace std;
22
23 #include "engraver.hh"
24
25 #include "context.hh"
26 #include "duration.hh"
27 #include "grob-array.hh"
28 #include "item.hh"
29 #include "music.hh"
30 #include "stream-event.hh"
31 #include "text-interface.hh"
32
33 #include "translator.icc"
34
35 class Metronome_mark_engraver : public Engraver
36 {
37   Item *text_;
38   Grob *support_;
39   Grob *bar_;
40   Stream_event *tempo_ev_;
41
42 public:
43   TRANSLATOR_DECLARATIONS (Metronome_mark_engraver);
44
45 protected:
46   void stop_translation_timestep ();
47   void process_music ();
48
49   void acknowledge_break_aligned (Grob_info);
50   void acknowledge_break_alignment (Grob_info);
51   void acknowledge_grob (Grob_info);
52
53   void listen_tempo_change (Stream_event *);
54 };
55
56 Metronome_mark_engraver::Metronome_mark_engraver ()
57 {
58   text_ = 0;
59   support_ = 0;
60   bar_ = 0;
61   tempo_ev_ = 0;
62 }
63
64 void
65 Metronome_mark_engraver::listen_tempo_change (Stream_event *ev)
66 {
67   ASSIGN_EVENT_ONCE (tempo_ev_, ev);
68 }
69
70 static bool
71 safe_is_member (SCM scm, SCM lst)
72 {
73   return ly_is_list (lst) && scm_is_true (scm_member (scm, lst));
74 }
75
76 void
77 Metronome_mark_engraver::acknowledge_break_aligned (Grob_info info)
78 {
79   Grob *g = info.grob ();
80
81   if (text_
82       && scm_is_eq (g->get_property ("break-align-symbol"),
83                     ly_symbol2scm ("staff-bar")))
84     bar_ = g;
85   else if (text_
86            && !support_
87            && safe_is_member (g->get_property ("break-align-symbol"),
88                               text_->get_property ("break-align-symbols"))
89            && Item::break_visible (g))
90     {
91       support_ = g;
92       text_->set_parent (g, X_AXIS);
93     }
94   if (bar_ || support_)
95     text_->set_property ("non-musical", SCM_BOOL_T);
96 }
97
98 void
99 Metronome_mark_engraver::acknowledge_break_alignment (Grob_info info)
100 {
101   Grob *g = info.grob ();
102
103   if (text_
104       && support_
105       && dynamic_cast<Item *> (g))
106     text_->set_parent (g, X_AXIS);
107 }
108
109 void
110 Metronome_mark_engraver::acknowledge_grob (Grob_info info)
111 {
112   Grob *g = info.grob ();
113
114   if (text_)
115     for (SCM s = text_->get_property ("non-break-align-symbols");
116          scm_is_pair (s);
117          s = scm_cdr (s))
118       if (g->internal_has_interface (scm_car (s)))
119         text_->set_parent (g, X_AXIS);
120 }
121
122 void
123 Metronome_mark_engraver::stop_translation_timestep ()
124 {
125   if (text_)
126     {
127       if (text_->get_parent (X_AXIS)
128           && text_->get_parent (X_AXIS)->internal_has_interface (ly_symbol2scm ("multi-measure-rest-interface"))
129           && bar_)
130         text_->set_parent (bar_, X_AXIS);
131       else if (!support_)
132         {
133           /*
134             Gardner Read "Music Notation", p.278
135
136             Align the metronome mark over the time signature (or the
137             first notational element of the measure if no time
138             signature is present in that measure).
139           */
140           if (Grob *mc = unsmob<Grob> (get_property ("currentMusicalColumn")))
141             text_->set_parent (mc, X_AXIS);
142           else if (Grob *cc = unsmob<Grob> (get_property ("currentCommandColumn")))
143             text_->set_parent (cc, X_AXIS);
144         }
145       text_->set_object ("side-support-elements",
146                          grob_list_to_grob_array (get_property ("stavesFound")));
147       text_ = 0;
148       support_ = 0;
149       bar_ = 0;
150       tempo_ev_ = 0;
151     }
152 }
153
154 void
155 Metronome_mark_engraver::process_music ()
156 {
157   if (tempo_ev_)
158     {
159       text_ = make_item ("MetronomeMark", tempo_ev_->self_scm ());
160
161       SCM proc = get_property ("metronomeMarkFormatter");
162       SCM result = scm_call_2 (proc,
163                                tempo_ev_->self_scm (),
164                                context ()->self_scm ());
165
166       text_->set_property ("text", result);
167     }
168 }
169
170
171 void
172 Metronome_mark_engraver::boot ()
173 {
174   ADD_LISTENER (Metronome_mark_engraver, tempo_change);
175   ADD_ACKNOWLEDGER (Metronome_mark_engraver, break_aligned);
176   ADD_ACKNOWLEDGER (Metronome_mark_engraver, break_alignment);
177   ADD_ACKNOWLEDGER (Metronome_mark_engraver, grob);
178 }
179
180 ADD_TRANSLATOR (Metronome_mark_engraver,
181                 /* doc */
182                 "Engrave metronome marking.  This delegates the formatting"
183                 " work to the function in the @code{metronomeMarkFormatter}"
184                 " property.  The mark is put over all staves.  The staves are"
185                 " taken from the @code{stavesFound} property, which is"
186                 " maintained by @ref{Staff_collecting_engraver}.",
187
188                 /* create */
189                 "MetronomeMark ",
190
191                 /* read */
192                 "currentCommandColumn "
193                 "currentMusicalColumn "
194                 "metronomeMarkFormatter "
195                 "stavesFound "
196                 "tempoHideNote ",
197
198                 /* write */
199                 ""
200                );