]> git.donarmstrong.com Git - lilypond.git/blob - lily/chord.cc
patch::: 1.1.26.jcn4: koord vixen
[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 Chord::Chord (Array<Musical_pitch> pitch_arr)
13 {
14   pitch_arr_ = pitch_arr;
15 }
16
17 // construct from parser output
18 // urg: should split this up into understandable chunks
19 Chord::Chord (Musical_pitch tonic, Array<Musical_pitch>* add_arr_p, Array<Musical_pitch>* sub_arr_p, Musical_pitch* inversion_p)
20 {
21   for (int i = 0; i < add_arr_p->size (); i++)
22     {
23       Musical_pitch p = tonic;
24       Musical_pitch q = (*add_arr_p)[i];
25       // duh, c7 should mean <c bes>
26       if (q.notename_i_ == 6)
27         q.accidental_i_--;
28       p.transpose (q);
29       (*add_arr_p)[i] = p;
30     }
31   add_arr_p->sort (Musical_pitch::compare);
32   for (int i = 0; i < sub_arr_p->size (); i++)
33     {
34       Musical_pitch p = tonic;
35       Musical_pitch q = (*sub_arr_p)[i];
36       // duh, c7 should mean <c bes>
37       if (q.notename_i_ == 6)
38         q.accidental_i_--;
39       p.transpose (q);
40       (*sub_arr_p)[i] = p;
41     }
42   sub_arr_p->sort (Musical_pitch::compare);
43
44   Musical_pitch third (2);
45   Musical_pitch mthird (2, -1);
46   Musical_pitch missing;
47   missing = tonic;
48   missing.transpose (third);
49
50   Musical_pitch p;
51   p = tonic;
52   p.transpose (third);
53   p.transpose (mthird);
54
55   /*
56    must have minimum at 5 (3 is added automatically as missing)
57    */
58   if (!add_arr_p->size ())
59     add_arr_p->push (p);
60   else if ((add_arr_p->top () < p) && (add_arr_p->top ().notename_i_ != p.notename_i_))
61     add_arr_p->push (p);
62   add_arr_p->sort (Musical_pitch::compare);
63
64   Array<Musical_pitch> triads;
65   triads.push (third);   // c e 
66   triads.push (mthird);  // d f 
67   triads.push (mthird);  // e g 
68   triads.push (third);   // f a 
69   triads.push (third);   // g b 
70   triads.push (mthird);  // a c 
71   triads.push (mthird);  // b d 
72
73   /*
74     if first addition is 4, assume sus4 and don't add third implicitely
75    */
76   Musical_pitch sus (3);
77   sus.transpose (tonic);
78   if (add_arr_p->size ())
79     if ((*add_arr_p)[0] == sus)
80       missing.transpose (mthird);
81
82   /*
83    add missing triads
84    */
85   for (int i = 0; i < add_arr_p->size ();)
86     {
87       Musical_pitch p = (*add_arr_p)[i];
88       if (p > missing)
89         while (p > missing)
90           {
91             if (p.notename_i_ != missing.notename_i_)
92               {
93                 if ((missing.notename_i_ - tonic.notename_i_ + 7) % 7 == 6)
94                   {
95                     Musical_pitch special_seven = missing;
96                     Musical_pitch lower (0, -1);
97                     special_seven.transpose (lower);
98                     add_arr_p->insert (special_seven, i++);
99                   }
100                 else
101                   add_arr_p->insert (missing, i++);
102               }
103             missing.transpose (triads[(missing.notename_i_ - tonic.notename_i_ + 7) % 7]);
104           }
105       else if (p.notename_i_ == missing.notename_i_)
106         missing.transpose (triads[(missing.notename_i_ - tonic.notename_i_ + 7) % 7]);
107       else
108         i++;
109     }
110
111   /*
112     add tonic
113    */
114   if (!add_arr_p->size () || ((*add_arr_p)[0] != tonic))
115     add_arr_p->insert (tonic, 0);
116
117   /*
118    add all that aren't subtracted
119    */
120   for (int i = 0; i < add_arr_p->size (); i++)
121     {
122       Musical_pitch p = (*add_arr_p)[i];
123       int j = 0;
124       for (; j < sub_arr_p->size (); j++)
125         if (p == (*sub_arr_p)[j])
126           {
127             sub_arr_p->del (j);
128             j = -1;
129             break;
130           }
131       if (j == sub_arr_p->size ())
132         pitch_arr_.push (p);
133     }
134
135   for (int i = 0; i < sub_arr_p->size (); i++)
136     warning (_f ("invalid subtraction: not part of chord: %s",
137                  (*sub_arr_p)[i].str ()));
138
139   if (inversion_p)
140     {
141       int i = 0;
142       for (; i < pitch_arr_.size (); i++)
143         if ((pitch_arr_[i].notename_i_ == inversion_p->notename_i_)
144           && (pitch_arr_[i].accidental_i_ == inversion_p->accidental_i_))
145           break;
146       if (i == pitch_arr_.size ())
147         warning (_f ("invalid inversion pitch: not part of chord: %s",
148                       inversion_p->str ()));
149       else
150         {
151           /*
152             urg
153             should be run-time switchable "chordInversionPreserve", howto?
154
155             there are two ways commonly used to rearrange a chord with
156             an inversion:
157
158             1. rebuild pitch list, taking inversion as base
159               */
160 #if 0
161           rebuild_from_base (i);
162 #else
163           /*
164             or
165             2. insert inversion as lowest (at first position)
166           */
167           rebuild_with_bass (i);
168 #endif
169         }
170       delete inversion_p;
171     }
172 }
173
174 String
175 Chord::banter_str (Musical_pitch* inversion) const
176 {
177   Musical_pitch tonic = pitch_arr_[0];
178
179   Array<Musical_pitch> scale;
180   scale.push (Musical_pitch (0)); // c
181   scale.push (Musical_pitch (1)); // d
182   scale.push (Musical_pitch (2)); // e
183   scale.push (Musical_pitch (3)); // f
184   scale.push (Musical_pitch (4)); // g
185   scale.push (Musical_pitch (5)); // a
186   // 7 always means 7-...
187   scale.push (Musical_pitch (6, -1)); // b
188
189
190   for (int i = 0; i < scale.size (); i++)
191     scale[i].transpose (tonic);
192
193   //urg, should do translation in scheme.
194   char const *acc[] = {"\\textflat\\textflat ", "\\textflat ", "", "\\textsharp " , "\\textsharp\\textsharp "};
195   String tonic_str = tonic.str ();
196   tonic_str = tonic_str.left_str (1).upper_str ()
197     + acc[tonic.accidental_i_ + 2];
198
199   String add_str;
200   String sub_str;
201   String sep_str;
202   String sub_sep_str;
203   int last_trap = 1;
204   for (int i=1; i < pitch_arr_.size (); i++)
205     {
206       Musical_pitch p = pitch_arr_[i];
207       int trap = p.notename_i_ - tonic.notename_i_
208         + (p.octave_i_ - tonic.octave_i_) * 7;
209       while (trap < 0)
210         trap += 7;
211       trap++;
212       while (trap - last_trap > 2)
213         {
214           last_trap += 2;
215           sub_str += sub_sep_str + "no" + to_str (last_trap);
216           sub_sep_str = "/";
217         }
218       last_trap = trap;
219       int accidental = p.accidental_i_ - scale[(trap - 1) % 7].accidental_i_;
220       if ((trap == 3) && (accidental == -1))
221         tonic_str += "m"; // hmm
222       else if (accidental || (!(trap % 2) || ((i + 1 == pitch_arr_.size ()) && (trap > 5))))
223         {
224           add_str += sep_str;
225           if ((trap == 7) && (accidental == 1))
226             add_str += "maj7";
227           else
228             {
229               add_str += to_str (trap);
230               if (accidental)
231                 add_str += accidental < 0 ? "-" : "+";
232               // catch "C4/no3"; remove "no3"
233               if (trap == 4)
234                 {
235                   int i = sub_str.index_i ("no3");
236                   if (i != -1)
237                     sub_str = sub_str.nomid_str (i, 3);
238                   if (!sub_str.length_i ())
239                     sub_sep_str = "";
240                 }
241             }
242           sep_str = "/";
243         }
244     }
245
246   String inversion_str;
247   if (inversion)
248     {
249       inversion_str = inversion->str ();
250       inversion_str = "/" + inversion_str.left_str (1).upper_str ()
251         + acc[tonic.accidental_i_ + 2];
252
253     }
254
255   if (sub_str.length_i ())
256     sub_str = sep_str + sub_str;
257   String str = tonic_str + "$^{" + add_str + sub_str + "}$" + inversion_str;
258   return str;
259 }
260
261 int
262 Chord::find_tonic_i () const
263 {
264   /*
265     find tonic
266     
267     first try: base of longest line of triads
268    */
269   int tonic_i = 0;
270   int longest_i = 0;
271   for (int i = 0; i < pitch_arr_.size (); i++)
272     {
273       int no_triad_i = 0;
274       int last_i = pitch_arr_[i % pitch_arr_.size ()].notename_i_;
275       int j = 0;
276       for (; j < pitch_arr_.size (); j++)
277         {
278           int cur_i = pitch_arr_[(i + j + 1) % pitch_arr_.size ()].notename_i_;
279           int gap = cur_i - last_i;
280           while (gap < 0)
281             gap += 7;
282           gap %= 7;
283           if (gap == 2)
284             last_i = cur_i;
285           else
286             no_triad_i++;
287         }
288       if (j - no_triad_i > longest_i)
289         {
290           longest_i = j - no_triad_i;
291           tonic_i = i;
292         }
293     }
294
295   /*
296     second try: note after biggest gap
297    */
298   int biggest_i = 0;
299   //  if (longest_i)
300   if (longest_i <= 1)
301     for (int i = 0; i < pitch_arr_.size (); i++)
302       {
303         int gap = pitch_arr_[i].notename_i_
304           - pitch_arr_[(i - 1 + pitch_arr_.size ()) 
305           % pitch_arr_.size ()].notename_i_;
306         while (gap < 0)
307           gap += 7;
308         gap %= 7;
309         if (gap > biggest_i)
310           {
311             biggest_i = gap;
312             tonic_i = i;
313           }
314       }
315   return tonic_i;
316 }
317
318 void
319 Chord::rebuild_from_base (int base_i)
320 {
321   Musical_pitch last (0, 0, -5);
322   Array<Musical_pitch> new_arr;
323   for (int i = 0; i < pitch_arr_.size (); i++)
324     {
325       Musical_pitch p = pitch_arr_[(base_i + i) % pitch_arr_.size ()];
326       if (p < last)
327         {
328           p.octave_i_ = last.octave_i_;
329           if (p < last)
330             p.octave_i_++;
331         }
332       new_arr.push (p);
333       last = p;
334     }
335   pitch_arr_ = new_arr;
336 }
337
338 void
339 Chord::rebuild_insert_inversion (int tonic_i)
340 {
341   Musical_pitch inversion = pitch_arr_.get (0);
342   rebuild_from_base (tonic_i - 1);
343   if (pitch_arr_.size ())
344     {
345       inversion.octave_i_ = pitch_arr_[0].octave_i_ - 1;
346       while (inversion < pitch_arr_[0])
347         inversion.octave_i_++;
348     }
349   for (int i = 0; i < pitch_arr_.size (); i++)
350     if (pitch_arr_[i] > inversion)
351       {
352         pitch_arr_.insert (inversion, i);
353         break;
354       }
355 }
356
357 void
358 Chord::rebuild_with_bass (int bass_i)
359 {
360   Musical_pitch inversion = pitch_arr_.get (bass_i);
361   // is lowering fine, or should others be raised?
362   if (pitch_arr_.size ())
363     while (inversion > pitch_arr_[0])
364       inversion.octave_i_--;
365   pitch_arr_.insert (inversion, 0);
366 }