]> 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--2010 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     support_ = g;
99 }
100
101 void
102 Metronome_mark_engraver::acknowledge_break_alignment (Grob_info info)
103 {
104   Grob *g = info.grob ();
105
106   if (text_
107       && support_
108       && dynamic_cast<Item *> (g))
109     text_->set_parent (g, X_AXIS);
110 }
111
112 void
113 Metronome_mark_engraver::acknowledge_grob (Grob_info info)
114 {
115   Grob *g = info.grob ();
116
117   if (text_)
118     for (SCM s = text_->get_property ("non-break-align-symbols");
119          scm_is_pair (s);
120          s = scm_cdr (s))
121       if (g->internal_has_interface (scm_car (s)))
122         text_->set_parent (g, X_AXIS);
123 }
124
125 void
126 Metronome_mark_engraver::stop_translation_timestep ()
127 {
128   if (text_)
129     {
130       if (text_->get_parent (X_AXIS)
131           && text_->get_parent (X_AXIS)->internal_has_interface (ly_symbol2scm ("multi-measure-rest-interface"))
132           && bar_)
133         text_->set_parent (bar_, X_AXIS);
134       else if (!support_)
135         {
136           /*
137             Gardner Read "Music Notation", p.278
138
139             Align the metronome mark over the time signature (or the
140             first notational element of the measure if no time
141             signature is present in that measure).
142           */
143           if (Grob *mc = unsmob_grob (get_property ("currentMusicalColumn")))
144             text_->set_parent (mc, X_AXIS);
145           else if (Grob *cc = unsmob_grob (get_property ("currentCommandColumn")))
146             text_->set_parent (cc, X_AXIS);
147         }
148       text_->set_object ("side-support-elements",
149                          grob_list_to_grob_array (get_property ("stavesFound")));
150       text_ = 0;
151       support_ = 0;
152       bar_ = 0;
153     }
154 }
155
156 void
157 Metronome_mark_engraver::process_music ()
158 {
159   SCM count = get_property ("tempoUnitCount");
160   SCM duration = get_property ("tempoUnitDuration");
161   SCM text = get_property ("tempoText");
162
163   if ( ( (unsmob_duration (duration) && scm_is_true (count))
164         || Text_interface::is_markup (text) )
165       && !(ly_is_equal (count, last_count_)
166            && ly_is_equal (duration, last_duration_)
167            && ly_is_equal (text, last_text_)))
168     {
169       text_ = make_item ("MetronomeMark", SCM_EOL);
170
171       SCM proc = get_property ("metronomeMarkFormatter");
172       SCM result = scm_call_4 (proc,
173                                text,
174                                duration,
175                                count,
176                                context ()->self_scm ());
177
178       text_->set_property ("text", result);
179     }
180
181   last_duration_ = duration;
182   last_count_ = count;
183   last_text_ = text;
184 }
185
186
187
188 ADD_ACKNOWLEDGER (Metronome_mark_engraver, break_aligned);
189 ADD_ACKNOWLEDGER (Metronome_mark_engraver, break_alignment);
190 ADD_ACKNOWLEDGER (Metronome_mark_engraver, grob);
191
192 ADD_TRANSLATOR (Metronome_mark_engraver,
193                 /* doc */
194                 "Engrave metronome marking.  This delegates the formatting"
195                 " work to the function in the @code{metronomeMarkFormatter}"
196                 " property.  The mark is put over all staves.  The staves are"
197                 " taken from the @code{stavesFound} property, which is"
198                 " maintained by @ref{Staff_collecting_engraver}.",
199
200                 /* create */
201                 "MetronomeMark ",
202
203                 /* read */
204                 "stavesFound "
205                 "metronomeMarkFormatter "
206                 "tempoUnitDuration "
207                 "tempoUnitCount "
208                 "tempoText "
209                 "tempoHideNote ",
210
211                 /* write */
212                 ""
213                 );