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