]> git.donarmstrong.com Git - lilypond.git/blob - lily/metronome-engraver.cc
Metronome-mark: with multi measure rest: align at bar.
[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 "stream-event.hh"
30 #include "text-interface.hh"
31
32 #include "translator.icc"
33
34 class Metronome_mark_engraver : public Engraver
35 {
36 public:
37   TRANSLATOR_DECLARATIONS (Metronome_mark_engraver);
38
39 protected:
40   Item *text_;
41   Grob *support_;
42   Grob *bar_;
43
44   SCM last_duration_;
45   SCM last_count_;
46   SCM last_text_;
47
48   DECLARE_ACKNOWLEDGER (break_aligned);
49   DECLARE_ACKNOWLEDGER (grob);
50
51 protected:
52   virtual void derived_mark () const;
53   void stop_translation_timestep ();
54   void process_music ();
55 };
56
57 Metronome_mark_engraver::Metronome_mark_engraver ()
58 {
59   text_ = 0;
60   support_ = 0;
61   bar_ = 0;
62   last_duration_ = SCM_EOL;
63   last_count_ = SCM_EOL;
64   last_text_ = SCM_EOL;
65 }
66
67 void
68 Metronome_mark_engraver::derived_mark () const
69 {
70   scm_gc_mark (last_count_);
71   scm_gc_mark (last_duration_);
72   scm_gc_mark (last_text_);
73 }
74
75 void
76 Metronome_mark_engraver::acknowledge_break_aligned (Grob_info info)
77 {
78   Grob *g = info.grob ();
79
80   if (text_
81       && g->get_property_data ("break-align-symbol")
82       == ly_symbol2scm ("staff-bar"))
83       bar_ = g;
84   else if (text_
85            && !support_
86            && scm_member (g->get_property_data ("break-align-symbol"),
87                           text_->get_property_data ("break-align-symbols"))
88            != SCM_BOOL_F)
89     {
90       support_ = g;
91       text_->set_parent (g, X_AXIS);
92     }
93 }
94
95 SCM
96 grob_name_scm (Grob *g)
97 {
98   SCM name_pair = scm_assq (ly_symbol2scm ("name"), g->get_property ("meta"));
99   return scm_is_pair (name_pair) ? scm_cdr (name_pair) : SCM_EOL;
100 }
101
102 void
103 Metronome_mark_engraver::acknowledge_grob (Grob_info info)
104 {
105   Grob *g = info.grob ();
106
107   if (text_
108       && scm_member (grob_name_scm (g),
109                      text_->get_property_data ("non-break-align-symbols"))
110       != SCM_BOOL_F)
111       text_->set_parent (g, X_AXIS);
112 }
113
114 void
115 Metronome_mark_engraver::stop_translation_timestep ()
116 {
117   if (text_)
118     {
119       if (text_->get_parent (X_AXIS)
120           && text_->get_parent (X_AXIS)->internal_has_interface (ly_symbol2scm ("multi-measure-rest-interface"))
121           && bar_)
122         text_->set_parent (bar_, X_AXIS);
123       else if (!support_)
124         {
125           /*
126             Gardner Read "Music Notation", p.278
127
128             Align the metronome mark over the time signature (or the
129             first notational element of the measure if no time
130             signature is present in that measure).
131           */
132           if (Grob *mc = unsmob_grob (get_property ("currentMusicalColumn")))
133             text_->set_parent (mc, X_AXIS);
134           else if (Grob *cc = unsmob_grob (get_property ("currentCommandColumn")))
135             text_->set_parent (cc, X_AXIS);
136         }
137       text_->set_object ("side-support-elements",
138                          grob_list_to_grob_array (get_property ("stavesFound")));
139       text_ = 0;
140       support_ = 0;
141       bar_ = 0;
142     }
143 }
144
145 void
146 Metronome_mark_engraver::process_music ()
147 {
148   SCM count = get_property ("tempoUnitCount");
149   SCM duration = get_property ("tempoUnitDuration");
150   SCM text = get_property ("tempoText");
151
152   if ( ( (unsmob_duration (duration) && scm_is_number (count))
153         || Text_interface::is_markup (text) )
154       && !(ly_is_equal (count, last_count_)
155            && ly_is_equal (duration, last_duration_)
156            && ly_is_equal (text, last_text_)))
157     {
158       text_ = make_item ("MetronomeMark", SCM_EOL);
159
160       SCM proc = get_property ("metronomeMarkFormatter");
161       SCM result = scm_call_4 (proc,
162                                text,
163                                duration,
164                                count,
165                                context ()->self_scm ());
166
167       text_->set_property ("text", result);
168     }
169
170   last_duration_ = duration;
171   last_count_ = count;
172   last_text_ = text;
173 }
174
175
176
177 ADD_ACKNOWLEDGER (Metronome_mark_engraver, break_aligned);
178 ADD_ACKNOWLEDGER (Metronome_mark_engraver, grob);
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                 "stavesFound "
193                 "metronomeMarkFormatter "
194                 "tempoUnitDuration "
195                 "tempoUnitCount "
196                 "tempoText "
197                 "tempoHideNote ",
198
199                 /* write */
200                 ""
201                 );