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