]> git.donarmstrong.com Git - lilypond.git/blob - lily/breathing-sign.cc
Web-ja: update introduction
[lilypond.git] / lily / breathing-sign.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1999--2015 Michael Krause
5   Extensions for ancient notation (c) 2003--2015 by Juergen Reuter
6
7   LilyPond is free software: you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11
12   LilyPond is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "breathing-sign.hh"
22
23 #include "dimensions.hh"
24 #include "direction.hh"
25 #include "directional-element-interface.hh"
26 #include "font-interface.hh"
27 #include "grob.hh"
28 #include "lookup.hh"
29 #include "output-def.hh"
30 #include "staff-symbol.hh"
31 #include "staff-symbol-referencer.hh"
32 #include "text-interface.hh"
33
34 /*
35   UGH : this is full of C&P code. Consolidate!  --hwn
36 */
37
38 /*
39   Gregorian chant divisio minima.  (Actually, this was the original
40   breathing sign by Michael. -- jr)
41 */
42 MAKE_SCHEME_CALLBACK (Breathing_sign, divisio_minima, 1);
43 SCM
44 Breathing_sign::divisio_minima (SCM smob)
45 {
46   Grob *me = unsmob<Grob> (smob);
47   Real staff_space = Staff_symbol_referencer::staff_space (me);
48
49   Real thickness = Staff_symbol_referencer::line_thickness (me);
50   thickness *= robust_scm2double (me->get_property ("thickness"), 1.0);
51
52   Real blotdiameter = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter"));
53
54   /*
55    * Draw a small vertical line through the uppermost (or, depending
56    * on direction, lowermost) staff line.
57    */
58   Interval xdim (0, thickness);
59   Interval ydim (-0.5 * staff_space, +0.5 * staff_space);
60   Box b (xdim, ydim);
61   Stencil out = Lookup::round_filled_box (b, blotdiameter);
62   return out.smobbed_copy ();
63 }
64
65 /*
66   Gregorian chant divisio maior.
67 */
68 MAKE_SCHEME_CALLBACK (Breathing_sign, divisio_maior, 1);
69 SCM
70 Breathing_sign::divisio_maior (SCM smob)
71 {
72   Grob *me = unsmob<Grob> (smob);
73   Real thickness = Staff_symbol_referencer::line_thickness (me);
74   thickness *= robust_scm2double (me->get_property ("thickness"), 1.0);
75
76   Real blotdiameter = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter"));
77
78   /*
79     Draw a vertical line that is roughly centered vertically in
80     the staff (just like a bar) with the following requirements:
81     1. length should be at least half the size of the staff
82     2. both ends should be in the middle of a staff space.
83
84     These two requirements contradict if the first or last space is
85     larger than half of the whole staff (e.g. the staff consists of
86     two lines only); in such cases the first prescription wins.
87   */
88   Interval ydim (0.0, 0.0);
89   if (Grob *staff = Staff_symbol_referencer::get_staff_symbol (me))
90     {
91       std::vector<Real> line_pos = Staff_symbol::line_positions (staff);
92       if (!line_pos.empty ())
93         {
94           std::sort (line_pos.begin (), line_pos.end ());
95           ydim[DOWN] = line_pos.front ();
96           ydim[UP] = line_pos.back ();
97           if (Real const height = ydim.length ())
98             {
99               ydim.widen (-0.25 * height);
100
101               /*
102                 ydim has now the required height; to satisfy req. 2
103                 find the staff spaces containing current endpoints.
104
105                 standard algorithms are suitable to find the upper
106                 line of these spaces; we must choose between
107                 upper_bound and lower_bound considering that if
108                 there's a line exactly at quarter of the staff (the
109                 lower end) then we need the space below it, while if
110                 there's a line exactly at three quarters of the staff
111                 (upper end) then we need the space above it.
112
113                 if the middle of the space found is not low/high
114                 enough, take the next space (if there are no more
115                 spaces, ydim won't be enlarged further).
116               */
117               std::vector<Real>::const_iterator it
118                 = std::lower_bound (line_pos.begin (), line_pos.end (),
119                                     ydim[DOWN]);
120               assert (line_pos.begin () < it);
121               double val = (it[-1] + it[0]) / 2;
122               if (ydim[DOWN] < val && line_pos.begin () < it - 1)
123                 val = (it[-2] + it[-1]) / 2;
124               ydim.add_point (val);
125
126               it = std::upper_bound (line_pos.begin (), line_pos.end (),
127                                      ydim[UP]);
128               assert (it < line_pos.end ());
129               val = (it[-1] + it[0]) / 2;
130               if (val < ydim[UP] && it + 1 < line_pos.end ())
131                 val = (it[0] + it[1]) / 2;
132               ydim.add_point (val);
133             }
134         }
135     }
136
137   ydim *= Staff_symbol_referencer::staff_space (me) / 2;
138
139   Interval xdim (0, thickness);
140   Box b (xdim, ydim);
141   Stencil out = Lookup::round_filled_box (b, blotdiameter);
142   return out.smobbed_copy ();
143 }
144
145 /*
146   Gregorian chant divisio maxima.
147 */
148 MAKE_SCHEME_CALLBACK (Breathing_sign, divisio_maxima, 1);
149 SCM
150 Breathing_sign::divisio_maxima (SCM smob)
151 {
152   Grob *me = unsmob<Grob> (smob);
153   Real staff_space = Staff_symbol_referencer::staff_space (me);
154   Real thickness = Staff_symbol_referencer::line_thickness (me);
155   thickness *= robust_scm2double (me->get_property ("thickness"), 1.0);
156
157   Real blotdiameter = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter"));
158
159   // like a "|" type bar
160   Interval xdim (0, thickness);
161   Interval ydim = Staff_symbol_referencer::staff_span (me);
162   ydim *= staff_space / 2;
163   Box b (xdim, ydim);
164   Stencil out = Lookup::round_filled_box (b, blotdiameter);
165   return out.smobbed_copy ();
166 }
167
168 /*
169   Gregorian chant finalis.
170 */
171 MAKE_SCHEME_CALLBACK (Breathing_sign, finalis, 1);
172 SCM
173 Breathing_sign::finalis (SCM smob)
174 {
175   Grob *me = unsmob<Grob> (smob);
176   Real staff_space = Staff_symbol_referencer::staff_space (me);
177   Real thickness = Staff_symbol_referencer::line_thickness (me);
178   thickness *= robust_scm2double (me->get_property ("thickness"), 1.0);
179
180   Real blotdiameter = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter"));
181
182   // like a "||" type bar
183   Interval xdim (0, thickness);
184   Interval ydim = Staff_symbol_referencer::staff_span (me);
185   ydim *= staff_space / 2;
186   Box b (xdim, ydim);
187   Stencil line1 = Lookup::round_filled_box (b, blotdiameter);
188   Stencil line2 (line1);
189   line2.translate_axis (0.5 * staff_space, X_AXIS);
190   line1.add_stencil (line2);
191
192   return line1.smobbed_copy ();
193 }
194
195 MAKE_SCHEME_CALLBACK (Breathing_sign, offset_callback, 1);
196 SCM
197 Breathing_sign::offset_callback (SCM smob)
198 {
199   Grob *me = unsmob<Grob> (smob);
200
201   Direction d = get_grob_direction (me);
202   if (!d)
203     {
204       d = UP;
205       set_grob_direction (me, d);
206     }
207
208   Grob *staff = Staff_symbol_referencer::get_staff_symbol (me);
209   if (staff)
210     {
211       Interval iv = Staff_symbol::line_span (staff);
212       Real inter = Staff_symbol::staff_space (staff) / 2;
213       return scm_from_double (inter * iv[d]);
214     }
215
216   return scm_from_double (0.0);
217 }
218
219 ADD_INTERFACE (Breathing_sign,
220                "A breathing sign.",
221
222                /* properties */
223                "direction "
224               );