1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3 
4   Copyright (C) 1999--2020 Han-Wen Nienhuys <hanwen@xs4all.nl>
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 "moment.hh"
21 
22 /* TODO: add optional factor argument. */
23 LY_DEFINE (ly_make_moment, "ly:make-moment",
24            1, 3, 0, (SCM m, SCM g, SCM gn, SCM gd),
25            "Create the moment with rational main timing @var{m},"
26            " and optional grace timing @var{g}.\n"
27            "\n"
28            "A @dfn{moment} is a point in musical time.  It consists of"
29            " a pair of rationals (@var{m},@tie{}@var{g}), where @var{m} is"
30            " the timing for the main notes, and @var{g} the timing for"
31            " grace notes.  In absence of grace notes, @var{g}@tie{}is zero.\n"
32            "\n"
33            "For compatibility reasons, it is possible to write two"
34            " numbers specifying numerator and denominator instead of"
35            " the rationals.  These forms cannot be mixed, and the two-"
36            "argument form is disambiguated by the sign of the second"
37            " argument: if it is positive, it can only be a denominator"
38            " and not a grace timing."
39           )
40 {
41   LY_ASSERT_TYPE (is_scm<Rational>, m, 1);
42   if (SCM_UNBNDP (g))
43     return Moment (from_scm<Rational> (m)).smobbed_copy ();
44 
45   if (SCM_UNBNDP (gn))
46     {
47       LY_ASSERT_TYPE (is_scm<Rational>, g, 2);
48       if (scm_is_true (scm_positive_p (g)))
49         {
50           LY_ASSERT_TYPE (scm_is_integer, m, 1);
51           LY_ASSERT_TYPE (scm_is_integer, g, 2);
52           return Moment (Rational (scm_to_int64 (m),
53                                    scm_to_int64 (g))).smobbed_copy ();
54         }
55       return Moment (from_scm<Rational> (m),
56                      from_scm<Rational> (g)).smobbed_copy ();
57     }
58 
59   LY_ASSERT_TYPE (scm_is_integer, m, 1);
60   LY_ASSERT_TYPE (scm_is_integer, g, 2);
61   LY_ASSERT_TYPE (scm_is_integer, gn, 3);
62   I64 grace_num = scm_to_int64 (gn);
63   I64 grace_den = 1;
64   if (!SCM_UNBNDP (gd))
65     {
66       LY_ASSERT_TYPE (scm_is_integer, gd, 4);
67       grace_den = scm_to_int64 (gd);
68     }
69 
70   return Moment (Rational (scm_to_int64 (m), scm_to_int64 (g)),
71                  Rational (grace_num, grace_den)).smobbed_copy ();
72 }
73 
74 LY_DEFINE (ly_moment_sub, "ly:moment-sub",
75            2, 0, 0, (SCM a, SCM b),
76            "Subtract two moments.")
77 {
78   LY_ASSERT_SMOB (Moment, a, 1);
79   LY_ASSERT_SMOB (Moment, b, 2);
80 
81   Moment *ma = unsmob<Moment> (a);
82   Moment *mb = unsmob<Moment> (b);
83 
84   return (*ma - *mb).smobbed_copy ();
85 }
86 
87 LY_DEFINE (ly_moment_add, "ly:moment-add",
88            2, 0, 0, (SCM a, SCM b),
89            "Add two moments.")
90 {
91   LY_ASSERT_SMOB (Moment, a, 1);
92   LY_ASSERT_SMOB (Moment, b, 2);
93 
94   Moment *ma = unsmob<Moment> (a);
95   Moment *mb = unsmob<Moment> (b);
96 
97   return (*ma + *mb).smobbed_copy ();
98 }
99 
100 LY_DEFINE (ly_moment_mul, "ly:moment-mul",
101            2, 0, 0, (SCM a, SCM b),
102            "Multiply two moments.")
103 {
104   LY_ASSERT_SMOB (Moment, a, 1);
105   LY_ASSERT_SMOB (Moment, b, 2); // TODO: should be Rational
106 
107   Moment *ma = unsmob<Moment> (a);
108   Moment *mb = unsmob<Moment> (b);
109   return (*ma * mb->main_part_).smobbed_copy ();
110 }
111 
112 LY_DEFINE (ly_moment_div, "ly:moment-div",
113            2, 0, 0, (SCM a, SCM b),
114            "Divide two moments.")
115 {
116   LY_ASSERT_SMOB (Moment, a, 1);
117   LY_ASSERT_SMOB (Moment, b, 2); // TODO: should be Rational
118 
119   Moment *ma = unsmob<Moment> (a);
120   Moment *mb = unsmob<Moment> (b);
121 
122   return (*ma / mb->main_part_).smobbed_copy ();
123 }
124 
125 LY_DEFINE (ly_moment_mod, "ly:moment-mod",
126            2, 0, 0, (SCM a, SCM b),
127            "Modulo of two moments.")
128 {
129   LY_ASSERT_SMOB (Moment, a, 1);
130   LY_ASSERT_SMOB (Moment, b, 2); // TODO: should be Rational
131 
132   Moment *ma = unsmob<Moment> (a);
133   Moment *mb = unsmob<Moment> (b);
134   return (*ma % mb->main_part_).smobbed_copy ();
135 }
136 
137 LY_DEFINE (ly_moment_grace, "ly:moment-grace",
138            1, 0, 0, (SCM mom),
139            "Extract grace timing as a rational number from @var{mom}.")
140 {
141   LY_ASSERT_SMOB (Moment, mom, 1);
142 
143   return to_scm (unsmob<Moment> (mom)->grace_part_);
144 }
145 
146 LY_DEFINE (ly_moment_grace_numerator, "ly:moment-grace-numerator",
147            1, 0, 0, (SCM mom),
148            "Extract numerator from grace timing.")
149 {
150   LY_ASSERT_SMOB (Moment, mom, 1);
151 
152   Moment *ma = unsmob<Moment> (mom);
153 
154   return to_scm (ma->grace_part_.numerator ());
155 }
156 
157 LY_DEFINE (ly_moment_grace_denominator, "ly:moment-grace-denominator",
158            1, 0, 0, (SCM mom),
159            "Extract denominator from grace timing.")
160 {
161   LY_ASSERT_SMOB (Moment, mom, 1);
162   Moment *ma = unsmob<Moment> (mom);
163 
164   return to_scm (ma->grace_part_.denominator ());
165 }
166 
167 LY_DEFINE (ly_moment_main, "ly:moment-main",
168            1, 0, 0, (SCM mom),
169            "Extract main timing as a rational number from @var{mom}.")
170 {
171   LY_ASSERT_SMOB (Moment, mom, 1);
172 
173   return to_scm (unsmob<Moment> (mom)->main_part_);
174 }
175 
176 LY_DEFINE (ly_moment_main_numerator, "ly:moment-main-numerator",
177            1, 0, 0, (SCM mom),
178            "Extract numerator from main timing.")
179 {
180   LY_ASSERT_SMOB (Moment, mom, 1);
181   Moment *ma = unsmob<Moment> (mom);
182 
183   return to_scm (ma->main_part_.numerator ());
184 }
185 
186 LY_DEFINE (ly_moment_main_denominator, "ly:moment-main-denominator",
187            1, 0, 0, (SCM mom),
188            "Extract denominator from main timing.")
189 {
190   LY_ASSERT_SMOB (Moment, mom, 1);
191   Moment *ma = unsmob<Moment> (mom);
192 
193   return to_scm (ma->main_part_.denominator ());
194 }
195 
196 LY_DEFINE (ly_moment_less_p, "ly:moment<?",
197            2, 0, 0, (SCM a, SCM b),
198            "Compare two moments.")
199 {
200   LY_ASSERT_SMOB (Moment, a, 1);
201   LY_ASSERT_SMOB (Moment, b, 2);
202 
203   Moment *ma = unsmob<Moment> (a);
204   Moment *mb = unsmob<Moment> (b);
205 
206   return ly_bool2scm (*ma < *mb);
207 }
208 
209