]> git.donarmstrong.com Git - lilypond.git/blob - lily/metronome-engraver.cc
b4cd2ce328b89707ac7497ed0cff6ca18a6ab1ec
[lilypond.git] / lily / metronome-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1998--2012 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   DECLARE_ACKNOWLEDGER (break_aligned);
50   DECLARE_ACKNOWLEDGER (break_alignment);
51   DECLARE_ACKNOWLEDGER (grob);
52
53   DECLARE_TRANSLATOR_LISTENER (tempo_change);
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 IMPLEMENT_TRANSLATOR_LISTENER (Metronome_mark_engraver, tempo_change);
65 void
66 Metronome_mark_engraver::listen_tempo_change (Stream_event *ev)
67 {
68   ASSIGN_EVENT_ONCE (tempo_ev_, ev);
69 }
70
71 static bool
72 safe_is_member (SCM scm, SCM lst)
73 {
74   return scm_list_p (lst) == SCM_BOOL_T
75          && scm_member (scm, lst) != SCM_BOOL_F;
76 }
77
78 void
79 Metronome_mark_engraver::acknowledge_break_aligned (Grob_info info)
80 {
81   Grob *g = info.grob ();
82
83   if (text_
84       && g->get_property ("break-align-symbol")
85       == ly_symbol2scm ("staff-bar"))
86     bar_ = g;
87   else if (text_
88            && !support_
89            && safe_is_member (g->get_property ("break-align-symbol"),
90                               text_->get_property ("break-align-symbols"))
91            && Item::break_visible (g))
92     {
93       support_ = g;
94       text_->set_parent (g, X_AXIS);
95     }
96   if (bar_ || support_)
97     text_->set_property ("non-musical", SCM_BOOL_T);
98 }
99
100 void
101 Metronome_mark_engraver::acknowledge_break_alignment (Grob_info info)
102 {
103   Grob *g = info.grob ();
104
105   if (text_
106       && support_
107       && dynamic_cast<Item *> (g))
108     text_->set_parent (g, X_AXIS);
109 }
110
111 void
112 Metronome_mark_engraver::acknowledge_grob (Grob_info info)
113 {
114   Grob *g = info.grob ();
115
116   if (text_)
117     for (SCM s = text_->get_property ("non-break-align-symbols");
118          scm_is_pair (s);
119          s = scm_cdr (s))
120       if (g->internal_has_interface (scm_car (s)))
121         text_->set_parent (g, X_AXIS);
122 }
123
124 void
125 Metronome_mark_engraver::stop_translation_timestep ()
126 {
127   if (text_)
128     {
129       if (text_->get_parent (X_AXIS)
130           && text_->get_parent (X_AXIS)->internal_has_interface (ly_symbol2scm ("multi-measure-rest-interface"))
131           && bar_)
132         text_->set_parent (bar_, X_AXIS);
133       else if (!support_)
134         {
135           /*
136             Gardner Read "Music Notation", p.278
137
138             Align the metronome mark over the time signature (or the
139             first notational element of the measure if no time
140             signature is present in that measure).
141           */
142           if (Grob *mc = unsmob_grob (get_property ("currentMusicalColumn")))
143             text_->set_parent (mc, X_AXIS);
144           else if (Grob *cc = unsmob_grob (get_property ("currentCommandColumn")))
145             text_->set_parent (cc, X_AXIS);
146         }
147       text_->set_object ("side-support-elements",
148                          grob_list_to_grob_array (get_property ("stavesFound")));
149       text_ = 0;
150       support_ = 0;
151       bar_ = 0;
152       tempo_ev_ = 0;
153     }
154 }
155
156 void
157 Metronome_mark_engraver::process_music ()
158 {
159   if (tempo_ev_)
160     {
161       text_ = make_item ("MetronomeMark", tempo_ev_->self_scm ());
162
163       SCM proc = get_property ("metronomeMarkFormatter");
164       SCM result = scm_call_2 (proc,
165                                tempo_ev_->self_scm (),
166                                context ()->self_scm ());
167
168       text_->set_property ("text", result);
169     }
170 }
171
172 ADD_ACKNOWLEDGER (Metronome_mark_engraver, break_aligned);
173 ADD_ACKNOWLEDGER (Metronome_mark_engraver, break_alignment);
174 ADD_ACKNOWLEDGER (Metronome_mark_engraver, grob);
175
176 ADD_TRANSLATOR (Metronome_mark_engraver,
177                 /* doc */
178                 "Engrave metronome marking.  This delegates the formatting"
179                 " work to the function in the @code{metronomeMarkFormatter}"
180                 " property.  The mark is put over all staves.  The staves are"
181                 " taken from the @code{stavesFound} property, which is"
182                 " maintained by @ref{Staff_collecting_engraver}.",
183
184                 /* create */
185                 "MetronomeMark ",
186
187                 /* read */
188                 "currentCommandColumn "
189                 "currentMusicalColumn "
190                 "metronomeMarkFormatter "
191                 "stavesFound "
192                 "tempoHideNote ",
193
194                 /* write */
195                 ""
196                );