]> git.donarmstrong.com Git - lilypond.git/blob - lily/chord.cc
patch::: 1.1.27.jcn3: geen genade
[lilypond.git] / lily / chord.cc
1 /*
2   chord.cc -- implement Chord
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1999 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
8
9 #include "chord.hh"
10 #include "warn.hh"
11
12 // doesn't seem common, and we should know about this during purple hit
13 // #define INVERSION_ADDED_AS_BASE 1
14
15 Chord::Chord (Array<Musical_pitch> pitch_arr)
16 {
17   pitch_arr_ = pitch_arr;
18 }
19
20 static void
21 rebuild_transpose (Musical_pitch tonic, Array<Musical_pitch>* pitch_arr_p)
22 {
23   for (int i = 0; i < pitch_arr_p->size (); i++)
24     {
25       Musical_pitch p = tonic;
26       Musical_pitch q = (*pitch_arr_p)[i];
27       // duh, c7 should mean <c bes>
28       if (q.notename_i_ == 6)
29         q.accidental_i_--;
30       p.transpose (q);
31       (*pitch_arr_p)[i] = p;
32     }
33   pitch_arr_p->sort (Musical_pitch::compare);
34 }
35
36 static int
37 find_pitch_i (Array<Musical_pitch> const* pitch_arr_p, Musical_pitch p)
38 {
39   for (int i = 0; i < pitch_arr_p->size (); i++)
40     if (p == (*pitch_arr_p)[i])
41       return i;
42   return -1;
43 }
44
45 static int
46 find_notename_i (Array<Musical_pitch> const* pitch_arr_p, Musical_pitch p)
47 {
48   int i = find_pitch_i (pitch_arr_p, p);
49   if (i == -1)
50     {
51       for (int i = 0; i < pitch_arr_p->size (); i++)
52         {
53           p.octave_i_ = (*pitch_arr_p)[i].octave_i_;
54           if (p == (*pitch_arr_p)[i])
55             return i;
56         }
57     }
58   return i;
59 }
60
61 static int
62 trap_i (Musical_pitch tonic, Musical_pitch p)
63 {
64   int i = p.notename_i_ - tonic.notename_i_
65     + (p.octave_i_ - tonic.octave_i_) * 7;
66   while (i < 0)
67     i += 7;
68   i++;
69   return i;
70 }
71
72 static Array<Musical_pitch>
73 missing_triads_pitch_arr (Array<Musical_pitch>const* pitch_arr_p)
74 {
75   Musical_pitch third (2);
76   Musical_pitch mthird (2, -1);
77
78   Array<Musical_pitch> triads;
79   triads.push (third);   // c e 
80   triads.push (mthird);  // d f 
81   triads.push (mthird);  // e g 
82   triads.push (third);   // f a 
83   triads.push (third);   // g b 
84   triads.push (mthird);  // a c 
85   triads.push (mthird);  // b d 
86
87   Musical_pitch tonic = (*pitch_arr_p)[0];
88   Musical_pitch last = tonic;
89   Array<Musical_pitch> missing_arr;
90
91   for (int i = 0; i < pitch_arr_p->size ();)
92     {
93       Musical_pitch p = (*pitch_arr_p)[i];
94       int trap = trap_i (tonic, p);
95       if (last.notename_i_ == p.notename_i_)
96         last.transpose (triads[(last.notename_i_ - tonic.notename_i_ + 7) % 7]);
97       if (trap > trap_i (tonic, last))
98         {
99           while (trap > trap_i (tonic, last))
100             {
101               if ((last.notename_i_ - tonic.notename_i_ + 7) % 7 == 6)
102                 {
103                   Musical_pitch special_seven = last;
104                   Musical_pitch lower (0, -1);
105                   special_seven.transpose (lower);
106                   missing_arr.push (special_seven);
107                 }
108               else
109                 {
110                   missing_arr.push (last);
111                 }
112               last.transpose (triads[(last.notename_i_ - tonic.notename_i_ + 7) % 7]);
113             }
114         }
115       else
116         {
117           i++;
118         }
119     }
120   return missing_arr;
121 }
122
123
124 /*
125   construct from parser output
126 */
127 Chord::Chord (Musical_pitch tonic, Array<Musical_pitch>* add_arr_p, Array<Musical_pitch>* sub_arr_p, Musical_pitch* inversion_p)
128 {
129   rebuild_transpose (tonic, add_arr_p);
130   rebuild_transpose (tonic, sub_arr_p);
131
132   Musical_pitch fifth = tonic;
133   fifth.transpose (Musical_pitch (2));
134   fifth.transpose (Musical_pitch (2, -1));
135
136   /*
137     default chord includes upto 5: <1, 3, 5>
138    */
139   add_arr_p->insert (tonic, 0);
140   int highest_trap = trap_i (tonic, add_arr_p->top ());
141   if (highest_trap < 5)
142     add_arr_p->push (fifth);
143
144   /*
145     find missing triads
146    */
147   Array<Musical_pitch> missing_arr = missing_triads_pitch_arr (add_arr_p);
148
149   /*
150     if additions include 4, assume sus4 and don't add third implicitely
151    */
152   Musical_pitch third = tonic;
153   third.transpose (Musical_pitch (2));
154   Musical_pitch sus = tonic;
155   sus.transpose (Musical_pitch (3));
156   if (::find_pitch_i (add_arr_p, sus) != -1)
157     {
158       int i = ::find_pitch_i (&missing_arr, third);
159       if (i != -1)
160         missing_arr.get (i);
161     }
162   
163   /*
164     complete the list of triads to be added
165    */
166   add_arr_p->concat (missing_arr);
167   add_arr_p->sort (Musical_pitch::compare);
168
169   /*
170    add all that aren't subtracted
171    */
172   for (int i = 0; i < add_arr_p->size (); i++)
173     {
174       Musical_pitch p = (*add_arr_p)[i];
175       int j = 0;
176       for (; j < sub_arr_p->size (); j++)
177         if (p == (*sub_arr_p)[j])
178           {
179             sub_arr_p->del (j);
180             j = -1;
181             break;
182           }
183       if (j == sub_arr_p->size ())
184         pitch_arr_.push (p);
185     }
186
187   pitch_arr_.sort (Musical_pitch::compare);
188
189   for (int i = 0; i < sub_arr_p->size (); i++)
190     warning (_f ("invalid subtraction: not part of chord: %s",
191                  (*sub_arr_p)[i].str ()));
192
193   if (inversion_p)
194     {
195       int i = 0;
196       for (; i < pitch_arr_.size (); i++)
197         {
198           if ((pitch_arr_[i].notename_i_ == inversion_p->notename_i_)
199               && (pitch_arr_[i].accidental_i_ == inversion_p->accidental_i_))
200             break;
201         }
202       if (i == pitch_arr_.size ())
203         {
204           warning (_f ("invalid inversion pitch: not part of chord: %s",
205                        inversion_p->str ()));
206         }
207       else
208         {
209 #if INVERSION_ADDED_AS_BASE
210           pitch_arr_.insert (pitch_arr_[i], 0);
211           rebuild_with_bass (0);
212 #else
213           rebuild_with_bass (i);
214 #endif
215           
216         }
217       delete inversion_p;
218     }
219 }
220
221 void
222 Chord::find_additions_and_subtractions(Array<Musical_pitch>* add_arr_p, Array<Musical_pitch>* sub_arr_p)
223 {
224   Musical_pitch tonic = pitch_arr_[0];
225   /*
226     all the triads that should be there
227    */
228   Array<Musical_pitch> all_arr;
229   all_arr.push (tonic);
230   all_arr.push (pitch_arr_.top ());
231   all_arr.concat (missing_triads_pitch_arr (&all_arr));
232   all_arr.sort (Musical_pitch::compare);
233   
234   int i = 0;
235   int j = 0;
236   while ((i < all_arr.size ()) || (j < pitch_arr_.size ()))
237     {
238       i = i <? all_arr.size () - 1;
239       j = j <? pitch_arr_.size () - 1;
240       Musical_pitch a = all_arr[i];
241       Musical_pitch p = pitch_arr_[j];
242       if (a == p)
243         {
244           i++;
245           j++;
246         }
247       else if ((p < a) || (p.notename_i_ == a.notename_i_))
248         {
249           add_arr_p->push (p);
250           j++;
251         }
252       else
253         {
254           sub_arr_p->push (a);
255           i++;
256         }
257     }
258       
259   /*
260     add highest addition, because it names chord
261    */
262   if (trap_i (tonic, pitch_arr_.top () > 5))
263     add_arr_p->push (pitch_arr_.top ());
264 }
265
266 String
267 Chord::banter_str (Musical_pitch* inversion) const
268 {
269   Musical_pitch tonic = pitch_arr_[0];
270
271   //urg, should do translation in scheme.
272   char const *acc[] = {"\\textflat\\textflat ", "\\textflat ", "", "\\textsharp " , "\\textsharp\\textsharp "};
273   String tonic_str = tonic.str ();
274   tonic_str = tonic_str.left_str (1).upper_str ()
275     + acc[tonic.accidental_i_ + 2];
276
277   Array<Musical_pitch> add_arr;
278   Array<Musical_pitch> sub_arr;
279   find_additions_and_subtractions (&add_arr, &sub_arr);
280                            
281   Array<Musical_pitch> scale;
282   scale.push (Musical_pitch (0)); // c
283   scale.push (Musical_pitch (1)); // d
284   scale.push (Musical_pitch (2)); // e
285   scale.push (Musical_pitch (3)); // f
286   scale.push (Musical_pitch (4)); // g
287   scale.push (Musical_pitch (5)); // a
288   scale.push (Musical_pitch (6)); // b
289   // 7 always means 7-...
290   //  scale.push (Musical_pitch (6, -1)); // b
291
292   rebuild_transpose (tonic, &scale);
293   
294   bool has3m_b = false;
295   bool has4_b = false;
296   String str;
297   String sep_str;
298   for (int i = 0; i < add_arr.size (); i++)
299     {
300       Musical_pitch p = add_arr[i];
301       int trap = trap_i (tonic, p);
302       if (trap == 4)
303         has4_b = true;
304       int accidental = p.accidental_i_ - scale[(trap - 1) % 7].accidental_i_;
305       if ((trap == 3) && (accidental == -1))
306         {
307           tonic_str += "m";
308           has3m_b = true;
309         }
310       else if (accidental
311                || (!(trap % 2) || ((i + 1 == add_arr.size ()) && (trap > 5))))
312         {
313           str += sep_str;
314           if ((trap == 7) && (accidental == 1))
315             str += "maj7";
316           else
317             {
318               str += to_str (trap);
319               if (accidental)
320                 str += accidental < 0 ? "-" : "+";
321             }
322           sep_str = "/";
323         }
324     }
325
326   for (int i = 0; i < sub_arr.size (); i++)
327     {
328       Musical_pitch p = sub_arr[i];
329       int trap = trap_i (tonic, p);
330       /*
331         if chord has 3-, assume minor and don't display 'no3'
332         if additions include 4, assume sus4 and don't display 'no3'
333       */
334       if (!((trap == 3) && (has3m_b || has4_b)))
335         {
336           str += sep_str + "no" + to_str (trap);
337           sep_str = "/";
338         }
339     }
340
341   String inversion_str;
342   if (inversion)
343     {
344       inversion_str = inversion->str ();
345       inversion_str = "/" + inversion_str.left_str (1).upper_str ()
346         + acc[inversion->accidental_i_ + 2];
347
348     }
349
350   return tonic_str + "$^{" + str + "}$" + inversion_str;
351 }
352
353 int
354 Chord::find_notename_i (Musical_pitch p) const
355 {
356   return ::find_notename_i (&pitch_arr_, p);
357 }
358
359 int
360 Chord::find_pitch_i (Musical_pitch p) const
361 {
362   return ::find_pitch_i (&pitch_arr_, p);
363 }
364
365 int
366 Chord::find_tonic_i () const
367 {
368   /*
369     find tonic
370     
371     first try: base of longest line of triads
372    */
373   int tonic_i = 0;
374   int longest_i = 0;
375   for (int i = 0; i < pitch_arr_.size (); i++)
376     {
377       int no_triad_i = 0;
378       int last_i = pitch_arr_[i % pitch_arr_.size ()].notename_i_;
379       int j = 0;
380       for (; j < pitch_arr_.size (); j++)
381         {
382           int cur_i = pitch_arr_[(i + j + 1) % pitch_arr_.size ()].notename_i_;
383           int gap = cur_i - last_i;
384           while (gap < 0)
385             gap += 7;
386           gap %= 7;
387           if (gap == 2)
388             last_i = cur_i;
389           else
390             no_triad_i++;
391         }
392       if (j - no_triad_i > longest_i)
393         {
394           longest_i = j - no_triad_i;
395           tonic_i = i;
396         }
397     }
398
399   /*
400     second try: note after biggest gap
401    */
402   int biggest_i = 0;
403   //  if (longest_i)
404   if (longest_i <= 1)
405     for (int i = 0; i < pitch_arr_.size (); i++)
406       {
407         int gap = pitch_arr_[i].notename_i_
408           - pitch_arr_[(i - 1 + pitch_arr_.size ()) 
409           % pitch_arr_.size ()].notename_i_;
410         while (gap < 0)
411           gap += 7;
412         gap %= 7;
413         if (gap > biggest_i)
414           {
415             biggest_i = gap;
416             tonic_i = i;
417           }
418       }
419   return tonic_i;
420 }
421
422 void
423 Chord::rebuild_from_base (int base_i)
424 {
425   assert (base_i >= 0);
426   Musical_pitch last (0, 0, -5);
427   Array<Musical_pitch> new_arr;
428   for (int i = 0; i < pitch_arr_.size (); i++)
429     {
430       Musical_pitch p = pitch_arr_[(base_i + i) % pitch_arr_.size ()];
431       if (p < last)
432         {
433           p.octave_i_ = last.octave_i_;
434           if (p < last)
435             p.octave_i_++;
436         }
437       new_arr.push (p);
438       last = p;
439     }
440   pitch_arr_ = new_arr;
441 }
442
443 void
444 Chord::rebuild_insert_inversion (int tonic_i)
445 {
446   assert (tonic_i > 0);
447 #if INVERSION_ADDED_AS_BASE
448   // inversion was added; don't insert
449   Musical_pitch inversion = pitch_arr_.get (0);
450   (void)inversion;
451 #else
452   Musical_pitch inversion = pitch_arr_.get (0);
453   rebuild_from_base (tonic_i - 1);
454   if (pitch_arr_.size ())
455     {
456       inversion.octave_i_ = pitch_arr_[0].octave_i_ - 1;
457       while (inversion < pitch_arr_[0])
458         inversion.octave_i_++;
459     }
460   for (int i = 0; i < pitch_arr_.size (); i++)
461     if (pitch_arr_[i] > inversion)
462       {
463         pitch_arr_.insert (inversion, i);
464         break;
465       }
466 #endif
467 }
468
469 void
470 Chord::rebuild_with_bass (int bass_i)
471 {
472   assert (bass_i >= 0);
473   Musical_pitch inversion = pitch_arr_.get (bass_i);
474   // is lowering fine, or should others be raised?
475   if (pitch_arr_.size ())
476     while (inversion > pitch_arr_[0])
477       inversion.octave_i_--;
478   pitch_arr_.insert (inversion, 0);
479 }