]> git.donarmstrong.com Git - lilypond.git/blob - lily/metronome-engraver.cc
Merge branch 'master' into lilypond/translation
[lilypond.git] / lily / metronome-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1998--2011 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 public:
38   TRANSLATOR_DECLARATIONS (Metronome_mark_engraver);
39
40 protected:
41   Item *text_;
42   Grob *support_;
43   Grob *bar_;
44
45   SCM last_duration_;
46   SCM last_count_;
47   SCM last_text_;
48
49   DECLARE_ACKNOWLEDGER (break_aligned);
50   DECLARE_ACKNOWLEDGER (break_alignment);
51   DECLARE_ACKNOWLEDGER (grob);
52
53 protected:
54   virtual void derived_mark () const;
55   void stop_translation_timestep ();
56   void process_music ();
57 };
58
59 Metronome_mark_engraver::Metronome_mark_engraver ()
60 {
61   text_ = 0;
62   support_ = 0;
63   bar_ = 0;
64   last_duration_ = SCM_EOL;
65   last_count_ = SCM_EOL;
66   last_text_ = SCM_EOL;
67 }
68
69 void
70 Metronome_mark_engraver::derived_mark () const
71 {
72   scm_gc_mark (last_count_);
73   scm_gc_mark (last_duration_);
74   scm_gc_mark (last_text_);
75 }
76
77 static bool
78 safe_is_member (SCM scm, SCM lst)
79 {
80   return scm_list_p (lst) == SCM_BOOL_T
81     && scm_member (scm, lst) != SCM_BOOL_F;
82 }
83
84 void
85 Metronome_mark_engraver::acknowledge_break_aligned (Grob_info info)
86 {
87   Grob *g = info.grob ();
88
89   if (text_
90       && g->get_property ("break-align-symbol")
91       == ly_symbol2scm ("staff-bar"))
92       bar_ = g;
93   else if (text_
94            && !support_
95            && safe_is_member (g->get_property ("break-align-symbol"),
96                               text_->get_property ("break-align-symbols"))
97            && Item::break_visible (g))
98     {
99       support_ = g;
100       text_->set_parent (g, X_AXIS);
101     }
102 }
103
104 void
105 Metronome_mark_engraver::acknowledge_break_alignment (Grob_info info)
106 {
107   Grob *g = info.grob ();
108
109   if (text_
110       && support_
111       && dynamic_cast<Item *> (g))
112     text_->set_parent (g, X_AXIS);
113 }
114
115 void
116 Metronome_mark_engraver::acknowledge_grob (Grob_info info)
117 {
118   Grob *g = info.grob ();
119
120   if (text_)
121     for (SCM s = text_->get_property ("non-break-align-symbols");
122          scm_is_pair (s);
123          s = scm_cdr (s))
124       if (g->internal_has_interface (scm_car (s)))
125         text_->set_parent (g, X_AXIS);
126 }
127
128 void
129 Metronome_mark_engraver::stop_translation_timestep ()
130 {
131   if (text_)
132     {
133       if (text_->get_parent (X_AXIS)
134           && text_->get_parent (X_AXIS)->internal_has_interface (ly_symbol2scm ("multi-measure-rest-interface"))
135           && bar_)
136         text_->set_parent (bar_, X_AXIS);
137       else if (!support_)
138         {
139           /*
140             Gardner Read "Music Notation", p.278
141
142             Align the metronome mark over the time signature (or the
143             first notational element of the measure if no time
144             signature is present in that measure).
145           */
146           if (Grob *mc = unsmob_grob (get_property ("currentMusicalColumn")))
147             text_->set_parent (mc, X_AXIS);
148           else if (Grob *cc = unsmob_grob (get_property ("currentCommandColumn")))
149             text_->set_parent (cc, X_AXIS);
150         }
151       text_->set_object ("side-support-elements",
152                          grob_list_to_grob_array (get_property ("stavesFound")));
153       text_ = 0;
154       support_ = 0;
155       bar_ = 0;
156     }
157 }
158
159 void
160 Metronome_mark_engraver::process_music ()
161 {
162   SCM count = get_property ("tempoUnitCount");
163   SCM duration = get_property ("tempoUnitDuration");
164   SCM text = get_property ("tempoText");
165
166   if ( ( (unsmob_duration (duration) && scm_is_true (count))
167         || Text_interface::is_markup (text) )
168       && !(ly_is_equal (count, last_count_)
169            && ly_is_equal (duration, last_duration_)
170            && ly_is_equal (text, last_text_)))
171     {
172       text_ = make_item ("MetronomeMark", SCM_EOL);
173
174       SCM proc = get_property ("metronomeMarkFormatter");
175       SCM result = scm_call_4 (proc,
176                                text,
177                                duration,
178                                count,
179                                context ()->self_scm ());
180
181       text_->set_property ("text", result);
182     }
183
184   last_duration_ = duration;
185   last_count_ = count;
186   last_text_ = text;
187 }
188
189
190
191 ADD_ACKNOWLEDGER (Metronome_mark_engraver, break_aligned);
192 ADD_ACKNOWLEDGER (Metronome_mark_engraver, break_alignment);
193 ADD_ACKNOWLEDGER (Metronome_mark_engraver, grob);
194
195 ADD_TRANSLATOR (Metronome_mark_engraver,
196                 /* doc */
197                 "Engrave metronome marking.  This delegates the formatting"
198                 " work to the function in the @code{metronomeMarkFormatter}"
199                 " property.  The mark is put over all staves.  The staves are"
200                 " taken from the @code{stavesFound} property, which is"
201                 " maintained by @ref{Staff_collecting_engraver}.",
202
203                 /* create */
204                 "MetronomeMark ",
205
206                 /* read */
207                 "stavesFound "
208                 "metronomeMarkFormatter "
209                 "tempoUnitDuration "
210                 "tempoUnitCount "
211                 "tempoText "
212                 "tempoHideNote ",
213
214                 /* write */
215                 ""
216                 );