]> git.donarmstrong.com Git - lilypond.git/blob - lily/pitch.cc
* input/regression/ambitus.ly: move file.
[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--2003 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9 #include "pitch.hh"
10 #include "warn.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_ = n;
19   alteration_ = a;
20   octave_ = 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_string (a);
27       s += ", notename = " + to_string (n);
28       warning (s);
29     }
30   normalise ();
31 }
32
33 Pitch::Pitch ()
34 {
35   notename_ = 0;
36   alteration_ = 0;
37   octave_ = 0;
38 }
39
40 int
41 Pitch::compare (Pitch const &m1, Pitch const &m2)
42 {
43   int o=  m1.octave_ - m2.octave_;
44   int n = m1.notename_ - m2.notename_;
45   int a = m1.alteration_ - m2.alteration_;
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_ + octave_*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
68 /* Calculate pitch height in 12th octave steps.  Don't assume
69    normalised pitch as this function is used to normalise the pitch.  */
70 int
71 Pitch::semitone_pitch () const
72 {
73   int o = octave_;
74   int n = notename_;
75   while (n < 0)
76     {
77       n += 7;
78       o --;
79     }
80   return (o + n / 7) * 12 + pitch_byte_a[n % 7] + alteration_;
81 }
82
83 void
84 Pitch::normalise ()
85 {
86   int pitch = semitone_pitch ();
87   while (notename_ >= 7)
88     {
89       notename_ -= 7;
90       octave_++;
91       alteration_ -= semitone_pitch () - pitch;
92     }
93   while (notename_ < 0)
94     {
95       notename_ += 7;
96       octave_--;
97       alteration_ -= semitone_pitch () - pitch;
98     }
99   while (alteration_ >= 3)
100     {
101       if (notename_ == 6)
102         {
103           notename_ = 0;
104           octave_++;
105         }
106       else
107         notename_++;
108
109       alteration_ = 0;
110       alteration_ -= semitone_pitch () - pitch;
111     }
112   while (alteration_ <= -3)
113     {
114       if (notename_ == 0)
115         {
116           notename_ = 6;
117           octave_--;
118         }
119       else
120         notename_--;
121
122       alteration_ = 0;
123       alteration_ -= semitone_pitch () - pitch;
124     }
125 }
126
127 /* WHugh, wat een intervaas */
128 void
129 Pitch::transpose (Pitch delta)
130 {
131   int new_semi = semitone_pitch ()  +delta.semitone_pitch();
132   octave_ += delta.octave_;
133   notename_ += delta.notename_;
134   alteration_ += new_semi - semitone_pitch();
135
136   normalise ();
137 }
138
139 Pitch
140 interval (Pitch const & from , Pitch const & to )
141 {
142   int sound = to.semitone_pitch()  - from.semitone_pitch ();
143   Pitch pt (to.get_octave () - from.get_octave (),
144             to.get_notename() - from.get_notename(),
145             to.get_alteration() - from.get_alteration());
146
147   return pt.transposed (Pitch(0,0,sound - pt.semitone_pitch()));
148 }
149
150
151 /* FIXME
152    Merge with *pitch->text* funcs in chord-name.scm
153  */
154 char const *accname[] = {"eses", "es", "", "is" , "isis"};
155
156 String
157 Pitch::string () const
158 {
159   int n = (notename_ + 2) % 7;
160   String s = to_string (char (n + 'a'));
161   if (alteration_)
162     s += String (accname[alteration_ + 2]);
163
164   if (octave_ >= 0)
165     {
166       int o = octave_ + 1;
167       while (o--)
168         s += "'";
169     }
170   else if (octave_ < 0)
171     {
172       int o = (-octave_) - 1;
173       while (o--)
174         s += to_string (',');
175     }
176
177   return s;
178 }
179
180 /*
181   change me to relative, counting from last pitch p
182   return copy of resulting pitch
183  */
184 Pitch
185 Pitch::to_relative_octave (Pitch p) const
186 {
187   int oct_mod = octave_  + 1;   // account for c' = octave 1 iso. 0 4
188   Pitch up_pitch (p);
189   Pitch down_pitch (p);
190
191   up_pitch.alteration_ = alteration_;
192   down_pitch.alteration_ = alteration_;
193   
194   Pitch n = *this;
195   up_pitch.up_to (notename_);
196   down_pitch.down_to (notename_);
197
198   int h = p.steps ();
199   if (abs (up_pitch.steps () - h) < abs (down_pitch.steps () - h))
200     n = up_pitch;
201   else
202     n = down_pitch;
203   
204   n.octave_ += oct_mod;
205   return n;
206 }
207
208 void
209 Pitch::up_to (int notename)
210 {
211   if (notename_  > notename)
212     {
213       octave_ ++;
214     }
215   notename_  = notename;
216 }
217
218 void
219 Pitch::down_to (int notename)
220 {
221   if (notename_ < notename)
222     {
223       octave_ --;
224     }
225   notename_ = notename;
226 }
227  
228 LY_DEFINE(ly_pitch_transpose,
229           "ly:pitch-transpose", 2, 0, 0,
230           (SCM p, SCM delta),
231           "Transpose @var{p} by the amount @var{delta}, where @var{delta} is the "
232 " pitch that central C is transposed to.")
233 {
234   Pitch* t = unsmob_pitch (p);
235   Pitch *d = unsmob_pitch (delta);
236   SCM_ASSERT_TYPE(t, p, SCM_ARG1, __FUNCTION__, "pitch")  ;
237   SCM_ASSERT_TYPE(d, delta, SCM_ARG1, __FUNCTION__, "pitch")  ;
238
239   return t->transposed (*d).smobbed_copy ();
240 }
241
242 /****************************************************************/
243
244
245 IMPLEMENT_TYPE_P (Pitch, "ly:pitch?");
246
247 SCM
248 Pitch::mark_smob (SCM)
249 {
250   return SCM_EOL;
251 }
252
253 IMPLEMENT_SIMPLE_SMOBS (Pitch);
254 int
255 Pitch::print_smob (SCM s, SCM port, scm_print_state *)
256 {
257   Pitch  *r = (Pitch *) ly_cdr (s);
258      
259   scm_puts ("#<Pitch ", port);
260   scm_display (scm_makfrom0str (r->string ().to_str0 ()), port);
261   scm_puts (" >", port);
262   
263   return 1;
264 }
265
266 SCM
267 Pitch::equal_p (SCM a , SCM b)
268 {
269   Pitch  *p = (Pitch *) ly_cdr (a);
270   Pitch  *q = (Pitch *) ly_cdr (b);  
271
272   bool eq = p->notename_ == q->notename_
273     && p->octave_ == q->octave_
274     && p->alteration_ == q->alteration_;
275
276   return eq ? SCM_BOOL_T : SCM_BOOL_F;
277 }
278
279 MAKE_SCHEME_CALLBACK (Pitch, less_p, 2);
280 SCM
281 Pitch::less_p (SCM p1, SCM p2)
282 {
283   Pitch *a = unsmob_pitch (p1);
284   Pitch *b = unsmob_pitch (p2);
285
286   if (compare (*a, *b) < 0)
287     return SCM_BOOL_T;
288   else
289     return SCM_BOOL_F;
290 }
291
292 /*
293   should add optional args
294  */
295
296 LY_DEFINE(make_pitch, "ly:make-pitch", 3, 0, 0, 
297           (SCM o, SCM n, SCM a),
298           "@var{octave} is specified by an integer, zero for the octave containing "
299           "middle C.  @var{note} is a number from 0 to 6, with 0 corresponding to C "
300           "and 6 corresponding to B.  The shift is zero for a natural, negative for "
301           "flats, or positive for sharps. ")
302 {
303   SCM_ASSERT_TYPE(gh_number_p (o), o, SCM_ARG1, __FUNCTION__, "number");
304   SCM_ASSERT_TYPE(gh_number_p (n), n, SCM_ARG2, __FUNCTION__, "number");
305   SCM_ASSERT_TYPE(gh_number_p (a), a, SCM_ARG3, __FUNCTION__, "number");
306
307   Pitch p (gh_scm2int (o), gh_scm2int (n), gh_scm2int (a));
308   return p.smobbed_copy ();
309 }
310
311
312 LY_DEFINE(pitch_octave, "ly:pitch-octave", 1, 0, 0, 
313           (SCM pp),
314           "extract the octave from pitch @var{p}.")
315 {
316   Pitch *p = unsmob_pitch (pp);
317    SCM_ASSERT_TYPE(p, pp, SCM_ARG1, __FUNCTION__, "Pitch");
318   int q = p->get_octave ();
319
320   return gh_int2scm (q);
321 }
322
323 LY_DEFINE(pitch_alteration, "ly:pitch-alteration", 1, 0, 0, 
324           (SCM pp),
325           "extract the alteration from pitch  @var{p}.")
326 {
327   Pitch *p = unsmob_pitch (pp);
328   SCM_ASSERT_TYPE(p, pp, SCM_ARG1, __FUNCTION__, "Pitch");
329   int     q = p->get_alteration ();
330
331   return gh_int2scm (q);
332 }
333
334 LY_DEFINE(pitch_notename, "ly:pitch-notename", 1, 0, 0, 
335           (SCM pp),
336           "extract the note name from pitch  @var{pp}.")
337 {
338   Pitch *p = unsmob_pitch (pp);
339   SCM_ASSERT_TYPE(p, pp, SCM_ARG1, __FUNCTION__, "Pitch");
340   int q  = p->get_notename ();
341
342   return gh_int2scm (q);
343 }
344
345 LY_DEFINE(pitch_semitones,  "ly:pitch-semitones", 1, 0, 0, 
346           (SCM pp),
347           "calculate the number of semitones of @var{p} from central C.")
348 {
349   Pitch *p = unsmob_pitch (pp);
350   SCM_ASSERT_TYPE(p, pp, SCM_ARG1, __FUNCTION__, "Pitch");
351  
352   int q = p->semitone_pitch ();
353   
354   // Was :
355   //
356   //int q = p->steps ();
357   //
358   // As the function is called "pitch_semitones", I assume it was a mistake !
359   // Jiba
360
361   return gh_int2scm (q);
362 }
363
364 LY_DEFINE(pitch_less, "ly:pitch<?", 2,0,0, (SCM p1, SCM p2),
365           "Is @var{p1} lower than @var{p2}? This uses lexicographic ordening.")
366 {
367   return Pitch::less_p (ly_car (p1),  ly_car (p2));
368 }
369
370 SCM
371 Pitch::smobbed_copy ()const
372 {
373   Pitch *  p = new Pitch (*this);
374   return p->smobbed_self ();
375 }
376
377 int
378 Pitch::get_octave ()const
379 {
380   return octave_;
381 }
382
383 int
384 Pitch::get_notename () const
385 {
386   return notename_;
387 }
388
389 int
390 Pitch::get_alteration () const
391 {
392   return alteration_;
393 }
394
395 Pitch
396 Pitch::transposed (Pitch d) const
397 {
398   Pitch p =*this;
399   p.transpose (d);
400   return p;
401 }