]> git.donarmstrong.com Git - lilypond.git/blob - lily/pitch.cc
string() -> to_string()
[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   normalise ();
22 }
23
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 /*
54   should be settable from input?
55  */
56 static Byte pitch_byte_a[  ] = { 0, 2, 4, 5, 7, 9, 11 };
57
58
59 /* Calculate pitch height in 12th octave steps.  Don't assume
60    normalised pitch as this function is used to normalise the pitch.  */
61 int
62 Pitch::semitone_pitch () const
63 {
64   int o = octave_;
65   int n = notename_;
66   while (n < 0)
67     {
68       n += 7;
69       o --;
70     }
71   return (o + n / 7) * 12 + pitch_byte_a[n % 7] + alteration_;
72 }
73
74 void
75 Pitch::normalise ()
76 {
77   int pitch = semitone_pitch ();
78   while (notename_ >= 7)
79     {
80       notename_ -= 7;
81       octave_++;
82       alteration_ -= semitone_pitch () - pitch;
83     }
84   while (notename_ < 0)
85     {
86       notename_ += 7;
87       octave_--;
88       alteration_ -= semitone_pitch () - pitch;
89     }
90   while (alteration_ >= 3)
91     {
92       if (notename_ == 6)
93         {
94           notename_ = 0;
95           octave_++;
96         }
97       else
98         notename_++;
99
100       alteration_ = 0;
101       alteration_ -= semitone_pitch () - pitch;
102     }
103   while (alteration_ <= -3)
104     {
105       if (notename_ == 0)
106         {
107           notename_ = 6;
108           octave_--;
109         }
110       else
111         notename_--;
112
113       alteration_ = 0;
114       alteration_ -= semitone_pitch () - pitch;
115     }
116 }
117
118 /* WHugh, wat een intervaas */
119 void
120 Pitch::transpose (Pitch delta)
121 {
122   int new_semi = semitone_pitch ()  +delta.semitone_pitch();
123   octave_ += delta.octave_;
124   notename_ += delta.notename_;
125   alteration_ += new_semi - semitone_pitch();
126
127   normalise ();
128 }
129
130 Pitch
131 interval (Pitch const & from , Pitch const & to )
132 {
133   int sound = to.semitone_pitch()  - from.semitone_pitch ();
134   Pitch pt (to.get_octave () - from.get_octave (),
135             to.get_notename() - from.get_notename(),
136             to.get_alteration() - from.get_alteration());
137
138   return pt.transposed (Pitch(0,0,sound - pt.semitone_pitch()));
139 }
140
141
142 /* FIXME
143    Merge with *pitch->text* funcs in chord-name.scm
144  */
145 char const *accname[] = {"eses", "es", "", "is" , "isis"};
146
147 String
148 Pitch::to_string () const
149 {
150   int n = (notename_ + 2) % 7;
151   String s = ::to_string (char (n + 'a'));
152   if (alteration_)
153     s += String (accname[alteration_ + 2]);
154
155   if (octave_ >= 0)
156     {
157       int o = octave_ + 1;
158       while (o--)
159         s += "'";
160     }
161   else if (octave_ < 0)
162     {
163       int o = (-octave_) - 1;
164       while (o--)
165         s += ::to_string (',');
166     }
167
168   return s;
169 }
170
171 /*
172   change me to relative, counting from last pitch p
173   return copy of resulting pitch
174  */
175 Pitch
176 Pitch::to_relative_octave (Pitch p) const
177 {
178   int oct_mod = octave_  + 1;   // account for c' = octave 1 iso. 0 4
179   Pitch up_pitch (p);
180   Pitch down_pitch (p);
181
182   up_pitch.alteration_ = alteration_;
183   down_pitch.alteration_ = alteration_;
184   
185   Pitch n = *this;
186   up_pitch.up_to (notename_);
187   down_pitch.down_to (notename_);
188
189   int h = p.steps ();
190   if (abs (up_pitch.steps () - h) < abs (down_pitch.steps () - h))
191     n = up_pitch;
192   else
193     n = down_pitch;
194   
195   n.octave_ += oct_mod;
196   return n;
197 }
198
199 void
200 Pitch::up_to (int notename)
201 {
202   if (notename_  > notename)
203     {
204       octave_ ++;
205     }
206   notename_  = notename;
207 }
208
209 void
210 Pitch::down_to (int notename)
211 {
212   if (notename_ < notename)
213     {
214       octave_ --;
215     }
216   notename_ = notename;
217 }
218  
219 LY_DEFINE(ly_pitch_transpose,
220           "ly:pitch-transpose", 2, 0, 0,
221           (SCM p, SCM delta),
222           "Transpose @var{p} by the amount @var{delta}, where @var{delta} is the "
223 " pitch that central C is transposed to.")
224 {
225   Pitch* t = unsmob_pitch (p);
226   Pitch *d = unsmob_pitch (delta);
227   SCM_ASSERT_TYPE(t, p, SCM_ARG1, __FUNCTION__, "pitch")  ;
228   SCM_ASSERT_TYPE(d, delta, SCM_ARG1, __FUNCTION__, "pitch")  ;
229
230   return t->transposed (*d).smobbed_copy ();
231 }
232
233 /****************************************************************/
234
235
236 IMPLEMENT_TYPE_P (Pitch, "ly:pitch?");
237
238 SCM
239 Pitch::mark_smob (SCM)
240 {
241   return SCM_EOL;
242 }
243
244 IMPLEMENT_SIMPLE_SMOBS (Pitch);
245 int
246 Pitch::print_smob (SCM s, SCM port, scm_print_state *)
247 {
248   Pitch  *r = (Pitch *) ly_cdr (s);
249      
250   scm_puts ("#<Pitch ", port);
251   scm_display (scm_makfrom0str (r->to_string ().to_str0 ()), port);
252   scm_puts (" >", port);
253   
254   return 1;
255 }
256
257 SCM
258 Pitch::equal_p (SCM a , SCM b)
259 {
260   Pitch  *p = (Pitch *) ly_cdr (a);
261   Pitch  *q = (Pitch *) ly_cdr (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 /*
284   should add optional args
285  */
286
287 LY_DEFINE(make_pitch, "ly:make-pitch", 3, 0, 0, 
288           (SCM o, SCM n, SCM a),
289           "@var{octave} is specified by an integer, zero for the octave containing "
290           "middle C.  @var{note} is a number from 0 to 6, with 0 corresponding to C "
291           "and 6 corresponding to B.  The shift is zero for a natural, negative for "
292           "flats, or positive for sharps. ")
293 {
294   SCM_ASSERT_TYPE(gh_number_p (o), o, SCM_ARG1, __FUNCTION__, "number");
295   SCM_ASSERT_TYPE(gh_number_p (n), n, SCM_ARG2, __FUNCTION__, "number");
296   SCM_ASSERT_TYPE(gh_number_p (a), a, SCM_ARG3, __FUNCTION__, "number");
297
298   Pitch p (gh_scm2int (o), gh_scm2int (n), gh_scm2int (a));
299   return p.smobbed_copy ();
300 }
301
302 LY_DEFINE(pitch_steps, "ly:pitch-steps", 1, 0,0,
303           (SCM p),
304           "Number of steps counted from central C of the pitch @var{p}.")
305 {
306   Pitch *pp = unsmob_pitch (p);
307   SCM_ASSERT_TYPE(pp, p, SCM_ARG1, __FUNCTION__, "Pitch");
308
309   return gh_int2scm (pp->steps());
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   return gh_int2scm (q);
355 }
356
357 LY_DEFINE(pitch_less, "ly:pitch<?", 2,0,0, (SCM p1, SCM p2),
358           "Is @var{p1} lower than @var{p2}? This uses lexicographic ordening.")
359 {
360   Pitch *a = unsmob_pitch (p1);
361   Pitch *b = unsmob_pitch (p2);
362   
363   SCM_ASSERT_TYPE(a, p1, SCM_ARG1, __FUNCTION__, "Pitch");
364   SCM_ASSERT_TYPE(b, p2, SCM_ARG2, __FUNCTION__, "Pitch");
365
366   if (Pitch::compare (*a, *b) < 0)
367     return SCM_BOOL_T;
368   else
369     return SCM_BOOL_F;
370 }
371
372 LY_DEFINE(ly_pitch_diff, "ly:pitch-diff", 2 ,0 ,0,
373           (SCM pitch, SCM  root),
374           "Return pitch with value DELTA =  PITCH - ROOT, ie, "
375 "ROOT == (ly:pitch-transpose root delta).")
376 {
377   Pitch *p = unsmob_pitch (pitch);
378   Pitch *r = unsmob_pitch (root);
379   SCM_ASSERT_TYPE(p, pitch, SCM_ARG1, __FUNCTION__, "Pitch");
380   SCM_ASSERT_TYPE(r, root, SCM_ARG2, __FUNCTION__, "Pitch");
381
382   return interval (*r,  *p).smobbed_copy();
383 }
384
385           
386
387
388
389 SCM
390 Pitch::smobbed_copy ()const
391 {
392   Pitch *  p = new Pitch (*this);
393   return p->smobbed_self ();
394 }
395
396 int
397 Pitch::get_octave ()const
398 {
399   return octave_;
400 }
401
402 int
403 Pitch::get_notename () const
404 {
405   return notename_;
406 }
407
408 int
409 Pitch::get_alteration () const
410 {
411   return alteration_;
412 }
413
414 Pitch
415 Pitch::transposed (Pitch d) const
416 {
417   Pitch p =*this;
418   p.transpose (d);
419   return p;
420 }