]> git.donarmstrong.com Git - lilypond.git/blob - lily/pitch.cc
Merge http://git.sv.gnu.org/r/lilypond
[lilypond.git] / lily / pitch.cc
1 /*
2   musical-pitch.cc -- implement Pitch
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1998--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "pitch.hh"
10
11 #include "main.hh"
12 #include "scale.hh"
13 #include "string-convert.hh"
14 #include "warn.hh"
15
16 #include "ly-smobs.icc"
17
18
19 Pitch::Pitch (int o, int n, Rational a)
20 {
21   notename_ = n;
22   alteration_ = a;
23   octave_ = o;
24   scale_ = default_global_scale; 
25   normalize ();
26 }
27
28 /* FIXME: why is octave == 0 and default not middleC ? */
29 Pitch::Pitch ()
30 {
31   notename_ = 0;
32   scale_ = default_global_scale; 
33   octave_ = 0;
34 }
35
36 int
37 Pitch::compare (Pitch const &m1, Pitch const &m2)
38 {
39   int o = m1.octave_ - m2.octave_;
40   int n = m1.notename_ - m2.notename_;
41   Rational a = m1.alteration_ - m2.alteration_;
42
43   if (o)
44     return o;
45   if (n)
46     return n;
47   if (a)
48     return a;
49   
50   return 0;
51 }
52
53 int
54 Pitch::steps () const
55 {
56   return notename_ + octave_ * scale_->step_tones_.size ();
57 }
58
59 Rational
60 Pitch::tone_pitch () const
61 {
62   int o = octave_;
63   int n = notename_;
64   while (n < 0)
65     {
66       n += scale_->step_tones_.size ();
67       o--;
68     }
69
70   /*
71     we're effictively hardcoding the octave to 6 whole-tones,
72     which is as arbitrary as coding it to 1200 cents
73   */
74   Rational tones ((o + n / scale_->step_tones_.size ()) * 6, 1);
75   tones += scale_->step_tones_[n % scale_->step_tones_.size ()];
76
77   tones += alteration_;
78   
79   return tones;
80 }
81
82 /* Calculate pitch height in 12th octave steps.  Don't assume
83    normalized pitch as this function is used to normalize the pitch.  */
84 int
85 Pitch::rounded_semitone_pitch () const
86 {
87   return int (double (tone_pitch () * Rational (2)));
88 }
89
90 int
91 Pitch::rounded_quartertone_pitch () const
92 {
93   return int (double (tone_pitch () * Rational (4)));
94 }
95
96 void
97 Pitch::normalize ()
98 {
99   Rational pitch = tone_pitch ();
100   while (notename_ >= (int) scale_->step_tones_.size ())
101     {
102       notename_ -= scale_->step_tones_.size ();
103       octave_++;
104       alteration_ -= tone_pitch () - pitch;
105     }
106   while (notename_ < 0)
107     {
108       notename_ += scale_->step_tones_.size ();
109       octave_--;
110       alteration_ -= tone_pitch () - pitch;
111     }
112
113   while (alteration_ > Rational (1))
114     {
115       if (notename_ == int (scale_->step_tones_.size ()))
116         {
117           notename_ = 0;
118           octave_++;
119         }
120       else
121         notename_++;
122
123       alteration_ = Rational (0);
124       alteration_ -= tone_pitch () - pitch;
125     }
126   while (alteration_ < Rational (-1))
127     {
128       if (notename_ == 0)
129         {
130           notename_ = scale_->step_tones_.size ();
131           octave_--;
132         }
133       else
134         notename_--;
135
136       alteration_ = 0;
137       alteration_ -= tone_pitch () - pitch;
138     }
139 }
140
141 void
142 Pitch::transpose (Pitch delta)
143 {
144   Rational new_alter = tone_pitch () + delta.tone_pitch ();
145
146   octave_ += delta.octave_;
147   notename_ += delta.notename_;
148   alteration_ += new_alter - tone_pitch ();
149
150   normalize ();
151 }
152
153 Pitch
154 pitch_interval (Pitch const &from, Pitch const &to)
155 {
156   Rational sound = to.tone_pitch () - from.tone_pitch ();
157   Pitch pt (to.get_octave () - from.get_octave (),
158             to.get_notename () - from.get_notename (),
159
160             to.get_alteration () - from.get_alteration ());
161
162   return pt.transposed (Pitch (0, 0, sound - pt.tone_pitch ()));
163 }
164
165 /* FIXME
166    Merge with *pitch->text* funcs in chord-name.scm  */
167 char const *accname[] = {"eses", "eseh", "es", "eh", "",
168                          "ih", "is", "isih", "isis"};
169
170 string
171 Pitch::to_string () const
172 {
173   int n = (notename_ + 2) % scale_->step_tones_.size ();
174   string s = ::to_string (char (n + 'a'));
175   Rational qtones = alteration_ * Rational (4,1);
176   int qt = int (rint (Real (qtones)));
177       
178   s += string (accname[qt + 4]);
179   if (octave_ >= 0)
180     {
181       int o = octave_ + 1;
182       while (o--)
183         s += "'";
184     }
185   else if (octave_ < 0)
186     {
187       int o = (-octave_) - 1;
188       while (o--)
189         s += ::to_string (',');
190     }
191
192   return s;
193 }
194
195 /* Change me to relative, counting from last pitch p
196    return copy of resulting pitch.  */
197 Pitch
198 Pitch::to_relative_octave (Pitch p) const
199 {
200   /* account for c' = octave 1 iso. 0 4 */
201   int oct_mod = octave_ + 1;
202   Pitch up_pitch (p);
203   Pitch down_pitch (p);
204
205   up_pitch.alteration_ = alteration_;
206   down_pitch.alteration_ = alteration_;
207
208   Pitch n = *this;
209   up_pitch.up_to (notename_);
210   down_pitch.down_to (notename_);
211
212   int h = p.steps ();
213   if (abs (up_pitch.steps () - h) < abs (down_pitch.steps () - h))
214     n = up_pitch;
215   else
216     n = down_pitch;
217
218   n.octave_ += oct_mod;
219   return n;
220 }
221
222 void
223 Pitch::up_to (int notename)
224 {
225   if (notename_ > notename)
226     octave_++;
227   notename_ = notename;
228 }
229
230 void
231 Pitch::down_to (int notename)
232 {
233   if (notename_ < notename)
234     octave_--;
235   notename_ = notename;
236 }
237
238 IMPLEMENT_TYPE_P (Pitch, "ly:pitch?");
239 SCM
240 Pitch::mark_smob (SCM x)
241 {
242   Pitch *p = (Pitch*) SCM_CELL_WORD_1 (x);
243   return p->scale_->self_scm ();
244 }
245
246 IMPLEMENT_SIMPLE_SMOBS (Pitch);
247 int
248 Pitch::print_smob (SCM s, SCM port, scm_print_state *)
249 {
250   Pitch *r = (Pitch *) SCM_CELL_WORD_1 (s);
251   scm_puts ("#<Pitch ", port);
252   scm_display (ly_string2scm (r->to_string ()), port);
253   scm_puts (" >", port);
254   return 1;
255 }
256
257 SCM
258 Pitch::equal_p (SCM a, SCM b)
259 {
260   Pitch *p = (Pitch *) SCM_CELL_WORD_1 (a);
261   Pitch *q = (Pitch *) SCM_CELL_WORD_1 (b);
262
263   bool eq = p->notename_ == q->notename_
264     && p->octave_ == q->octave_
265     && p->alteration_ == q->alteration_;
266
267   return eq ? SCM_BOOL_T : SCM_BOOL_F;
268 }
269
270 MAKE_SCHEME_CALLBACK (Pitch, less_p, 2);
271 SCM
272 Pitch::less_p (SCM p1, SCM p2)
273 {
274   Pitch *a = unsmob_pitch (p1);
275   Pitch *b = unsmob_pitch (p2);
276
277   if (compare (*a, *b) < 0)
278     return SCM_BOOL_T;
279   else
280     return SCM_BOOL_F;
281 }
282
283 int
284 Pitch::get_octave () const
285 {
286   return octave_;
287 }
288
289 int
290 Pitch::get_notename () const
291 {
292   return notename_;
293 }
294
295 Rational
296 Pitch::get_alteration () const
297 {
298   return alteration_;
299 }
300
301 Pitch
302 Pitch::transposed (Pitch d) const
303 {
304   Pitch p = *this;
305   p.transpose (d);
306   return p;
307 }
308
309 Rational NATURAL_ALTERATION (0);
310 Rational FLAT_ALTERATION (-1, 2);
311 Rational DOUBLE_FLAT_ALTERATION (-1);
312 Rational SHARP_ALTERATION (1, 2);
313
314 Pitch
315 Pitch::negated () const
316 {
317   return pitch_interval (*this, Pitch ());
318 }