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