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