]> git.donarmstrong.com Git - lilypond.git/blob - lily/pitch.cc
patch::: 1.3.134.jcn2
[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--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9 #include "pitch.hh"
10 #include "debug.hh"
11 #include "main.hh"
12 #include "ly-smobs.icc"
13
14
15
16 Pitch::Pitch (int o, int n, int a)
17 {
18   notename_i_ = n;
19   alteration_i_ = a;
20   octave_i_ = o;
21
22   if (n < 0 || n >= 7 ||
23       a < -2 || a > 2)
24     {
25       String s = _("Pitch arguments out of range");
26       s += ": alteration = " + to_str (a);
27       s += ", notename = " + to_str (n);
28       warning (s);
29     }
30   normalise ();
31 }
32
33 Pitch::Pitch ()
34 {
35   notename_i_ = 0;
36   alteration_i_ = 0;
37   octave_i_ = 0;
38 }
39
40 int
41 Pitch::compare (Pitch const &m1, Pitch const &m2)
42 {
43   int o=  m1.octave_i_ - m2.octave_i_;
44   int n = m1.notename_i_ - m2.notename_i_;
45   int a = m1.alteration_i_ - m2.alteration_i_;
46
47   if (o)
48         return o;
49   if (n)
50         return n;
51   if (a)
52         return a;
53   return 0;
54 }
55
56 int
57 Pitch::steps () const
58 {
59   return  notename_i_ + octave_i_*7;
60 }
61
62 /*
63   should be settable from input?
64  */
65 static Byte pitch_byte_a[  ] = { 0, 2, 4, 5, 7, 9, 11 };
66
67 int
68 sign_safe_div (int n, int d)
69 {
70   if (n < 0)
71      return - (-n / d) - 1;
72   return n / d;
73 }
74
75 /* Calculate pitch height in 12th octave steps.  Don't assume
76    normalised pitch as this function is used to normalise the pitch.  */
77 int
78 Pitch::semitone_pitch () const
79 {
80   return (octave_i_ + sign_safe_div (notename_i_, 7)) * 12
81     + pitch_byte_a[notename_i_ % 7]
82     + alteration_i_;
83 }
84
85 void
86 Pitch::normalise ()
87 {
88   int pitch = semitone_pitch ();
89   while (notename_i_ >= 7)
90     {
91       notename_i_ -= 7;
92       octave_i_++;
93       alteration_i_ -= semitone_pitch () - pitch;
94     }
95   while (notename_i_ < 0)
96     {
97       notename_i_ += 7;
98       octave_i_--;
99       alteration_i_ -= semitone_pitch () - pitch;
100     }
101   while (alteration_i_ >= 3)
102     {
103       if (notename_i_ == 6)
104         {
105           notename_i_ = 0;
106           octave_i_++;
107         }
108       else
109         notename_i_++;
110
111       alteration_i_ = 0;
112       alteration_i_ -= semitone_pitch () - pitch;
113     }
114   while (alteration_i_ <= -3)
115     {
116       if (notename_i_ == 0)
117         {
118           notename_i_ = 6;
119           octave_i_--;
120         }
121       else
122         notename_i_--;
123
124       alteration_i_ = 0;
125       alteration_i_ -= semitone_pitch () - pitch;
126     }
127 }
128
129 /* WHugh, wat een intervaas */
130 void
131 Pitch::transpose (Pitch delta)
132 {
133   int old_semi = semitone_pitch ();
134   int delta_semi = delta.semitone_pitch ();
135   octave_i_ += delta.octave_i_;
136   notename_i_ += delta.notename_i_;
137
138   int new_semi = semitone_pitch ();
139   int delta_acc = new_semi - old_semi - delta_semi;
140   alteration_i_ -= delta_acc;
141
142   normalise ();
143 }
144
145
146 /* FIXME
147    Merge with *pitch->text* funcs in chord-name.scm
148  */
149 char const *accname[] = {"eses", "es", "", "is" , "isis"};
150
151 String
152 Pitch::str () const
153 {
154   int n = (notename_i_ + 2) % 7;
155   String s = to_str (char(n + 'a'));
156   if (alteration_i_)
157     s += String (accname[alteration_i_ + 2]);
158
159   if (octave_i_ > 0)
160     {
161       int o = octave_i_ + 1;
162       while (o--)
163         s += "'";
164     }
165   else if (octave_i_ <0)
166     {
167       int o = (-octave_i_) - 1;
168       while (o--)
169         s += to_str (',');
170     }
171
172   return s;
173 }
174
175 /*
176   change me to relative, counting from last pitch p
177   return copy of resulting pitch
178  */
179 Pitch
180 Pitch::to_relative_octave (Pitch p)
181 {
182   int oct_mod = octave_i_  + 1; // account for c' = octave 1 iso. 0 4
183   Pitch up_pitch (p);
184   Pitch down_pitch (p);
185
186   up_pitch.alteration_i_ = alteration_i_;
187   down_pitch.alteration_i_ = alteration_i_;
188   
189   Pitch n = *this;
190   up_pitch.up_to (notename_i_);
191   down_pitch.down_to (notename_i_);
192
193   int h = p.steps ();
194   if (abs (up_pitch.steps () - h) < abs (down_pitch.steps () - h))
195     n = up_pitch;
196   else
197     n = down_pitch;
198   
199   n.octave_i_ += oct_mod;
200
201   *this = n;
202   return *this;
203 }
204
205 void
206 Pitch::up_to (int notename)
207 {
208   if (notename_i_  > notename)
209     {
210       octave_i_ ++;
211     }
212   notename_i_  = notename;
213 }
214
215 void
216 Pitch::down_to (int notename)
217 {
218   if (notename_i_ < notename)
219     {
220       octave_i_ --;
221     }
222   notename_i_ = notename;
223 }
224
225 ///MAKE_SCHEME_CALLBACK (Pitch, transpose, 2);
226 ///transpose_proc?
227 SCM
228 Pitch::transpose (SCM p, SCM delta)
229 {
230   Pitch t = *unsmob_pitch (p);
231   t.transpose (*unsmob_pitch (delta));
232   return t.smobbed_copy ();
233 }
234
235 static SCM
236 pitch_transpose (SCM p, SCM delta)
237 {
238   return Pitch::transpose (p, delta);
239 }
240
241 /****************************************************************/
242
243
244 IMPLEMENT_TYPE_P(Pitch, "pitch?");
245 IMPLEMENT_UNSMOB(Pitch, pitch);
246 SCM
247 Pitch::mark_smob (SCM )
248 {
249   return SCM_EOL;
250 }
251
252 IMPLEMENT_SIMPLE_SMOBS(Pitch);
253
254
255 int
256 Pitch::print_smob (SCM s, SCM port, scm_print_state *)
257 {
258   Pitch  *r = (Pitch *) gh_cdr (s);
259      
260   scm_puts ("#<Pitch ", port);
261   scm_display (ly_str02scm (r->str().ch_C()), port);
262   scm_puts (" >", port);
263   
264   return 1;
265 }
266
267 SCM
268 Pitch::equal_p (SCM a , SCM b)
269 {
270   Pitch  *p = (Pitch *) gh_cdr (a);
271   Pitch  *q = (Pitch *) gh_cdr (b);  
272
273   bool eq = p->notename_i_ == q->notename_i_
274     && p->octave_i_ == q->octave_i_
275     && p->alteration_i_ == q->alteration_i_;
276
277   return eq ? SCM_BOOL_T : SCM_BOOL_F;
278 }
279
280 MAKE_SCHEME_CALLBACK(Pitch, less_p, 2);
281 SCM
282 Pitch::less_p (SCM p1, SCM p2)
283 {
284   Pitch *a = unsmob_pitch (p1);
285   Pitch *b = unsmob_pitch (p2);
286
287   if (compare(*a, *b) < 0 )
288     return SCM_BOOL_T;
289   else
290     return SCM_BOOL_F;
291 }
292
293 /*
294   should add optional args
295  */
296
297 static SCM
298 make_pitch (SCM o, SCM n, SCM a)
299 {
300   Pitch p (gh_scm2int (o), gh_scm2int (n), gh_scm2int (a));
301   return p.smobbed_copy ();
302 }
303
304 static SCM
305 pitch_octave (SCM pp)
306 {
307   Pitch *p = unsmob_pitch (pp);
308   int q = 0;
309   if (!p)
310     warning ("Not a pitch");
311   else
312     q = p->octave_i();
313
314   return gh_int2scm (q);
315 }
316
317 static SCM
318 pitch_alteration (SCM pp)
319 {
320   Pitch *p = unsmob_pitch (pp);
321   int q = 0;
322   if (!p)
323     warning ("Not a pitch");
324   else
325     q = p->alteration_i();
326
327   return gh_int2scm (q);
328 }
329
330 static SCM
331 pitch_notename (SCM pp)
332 {
333   Pitch *p = unsmob_pitch (pp);
334   int q = 0;
335   if (!p)
336     warning ("Not a pitch");
337   else
338     q = p->notename_i();
339
340   return gh_int2scm (q);
341 }
342
343 static SCM
344 pitch_semitones (SCM pp)
345 {
346   Pitch *p = unsmob_pitch (pp);
347   int q = 0;
348   if (!p)
349     warning ("Not a pitch");
350   else
351     q = p->steps();
352
353   return gh_int2scm (q);
354 }
355
356 static void
357 add_funcs()
358 {
359   // should take list?: (make-pitch '(octave name accidental))
360   scm_make_gsubr ("make-pitch", 3, 0, 0, (Scheme_function_unknown)make_pitch);
361
362   scm_make_gsubr ("pitch-octave", 1, 0, 0, (Scheme_function_unknown)pitch_octave);
363   scm_make_gsubr ("pitch-notename", 1, 0, 0, (Scheme_function_unknown)pitch_notename);
364   scm_make_gsubr ("pitch-alteration", 1, 0, 0, (Scheme_function_unknown)pitch_alteration);
365   scm_make_gsubr ("pitch-semitones", 1, 0, 0, (Scheme_function_unknown)pitch_semitones);
366   scm_make_gsubr ("Pitch::transpose", 2, 0, 0, (Scheme_function_unknown) pitch_transpose);
367 }
368
369 ADD_SCM_INIT_FUNC(pitch, add_funcs);
370
371 SCM
372 Pitch::smobbed_copy ()const
373 {
374   Pitch *  p = new Pitch (*this);
375   return p->smobbed_self ();
376 }
377
378 int
379 Pitch::octave_i ()const
380 {
381   return octave_i_;
382 }
383
384 int
385 Pitch::notename_i () const
386 {
387   return notename_i_;
388 }
389
390 int
391 Pitch::alteration_i () const
392 {
393   return alteration_i_;
394 }