]> git.donarmstrong.com Git - lilypond.git/blob - lily/chord-name-engraver.cc
release: 1.1.18
[lilypond.git] / lily / chord-name-engraver.cc
1 /*
2   chord-name-engraver.cc -- implement Chord_name_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1998 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
8
9 #include "chord-name-engraver.hh"
10 #include "musical-request.hh"
11 #include "text-item.hh"
12 #include "paper-def.hh"
13 #include "lookup.hh"
14 #include "paper-def.hh"
15 #include "main.hh"
16 #include "dimensions.hh"
17 #include "g-text-item.hh"
18
19 ADD_THIS_TRANSLATOR (Chord_name_engraver);
20
21 Chord_name_engraver::Chord_name_engraver ()
22 {
23 }
24
25 void
26 Chord_name_engraver::acknowledge_element (Score_element_info i)
27 {
28   if (Note_req* n = dynamic_cast<Note_req*> (i.req_l_))
29     pitch_arr_.push (n->pitch_);
30 }
31
32 bool
33 Chord_name_engraver::do_try_music (Music* m)
34 {
35   if (Note_req* n = dynamic_cast<Note_req*> (m))
36     {
37       pitch_arr_.push (n->pitch_);
38       return true;
39     }
40   return false;
41 }
42
43 /*
44   UGH.
45
46   Split this routine into neat packets
47  */
48 void
49 Chord_name_engraver::do_process_requests ()
50 {
51   if (text_p_arr_.size ())
52     return;
53   if (!pitch_arr_.size ())
54     return;
55
56   /*
57    Banter style chord names (almost).
58    TODO:
59      - move this stuff to new Item class Chord_name
60      - switch on property, add american (?) chordNameStyle
61
62   Scalar chordNameStyle = get_property ("chordNameStyle", 0);
63   if (chordNameStyle == "Banter")
64      chord = pitches_to_banter (pitch_arr_));
65
66    */
67
68   
69   /*
70     find tonic: after longest line of triads
71    */
72
73   int tonic_i = 0;
74   Scalar chord_inversions = get_property ("chordInversion", 0);
75   if (chord_inversions.to_bool ())
76     {
77       int longest_i = 0;
78       for (int i = 0; i < pitch_arr_.size (); i++)
79         for (int j = 0; j < pitch_arr_.size (); j++)
80           {
81             int gap = pitch_arr_[(i + j + 1) % pitch_arr_.size ()].notename_i_
82               - pitch_arr_[(i + j) % pitch_arr_.size ()].notename_i_;
83             while (gap < 0)
84               gap += 7;
85             gap %= 7;
86             if (gap != 2)
87               {
88                 if (j > longest_i)
89                   {
90                     longest_i = j;
91                     tonic_i = i;
92                   }
93                 break;
94               }
95           }
96
97       int biggest_i = 0;
98       if (!longest_i)
99         for (int i = 0; i < pitch_arr_.size (); i++)
100           {
101             int gap = pitch_arr_[i].notename_i_
102               - pitch_arr_[(i - 1 + pitch_arr_.size ()) 
103               % pitch_arr_.size ()].notename_i_;
104             while (gap < 0)
105               gap += 7;
106             gap %= 7;
107             if (gap > biggest_i)
108               {
109                 biggest_i = gap;
110                 tonic_i = i;
111               }
112           }
113     }
114
115   Musical_pitch inversion = pitch_arr_[0];
116   if (tonic_i)
117     {
118       Musical_pitch last (0, 0, -5);
119       Array<Musical_pitch> pitches;
120       for (int i = 0; i < pitch_arr_.size (); i++)
121         {
122           Musical_pitch p = pitch_arr_[(tonic_i + i) % pitch_arr_.size ()];
123           if (p < last)
124             {
125               p.octave_i_ = last.octave_i_;
126               if (p < last)
127                 p.octave_i_++;
128             }
129           pitches.push (p);
130           last = p;
131         }
132       pitch_arr_ = pitches;
133     }
134
135   Musical_pitch tonic = pitch_arr_[0];
136
137   Array<Musical_pitch> scale;
138   scale.push (Musical_pitch (0)); // c
139   scale.push (Musical_pitch (1)); // d
140   scale.push (Musical_pitch (2)); // e
141   scale.push (Musical_pitch (3)); // f
142   scale.push (Musical_pitch (4)); // g
143   scale.push (Musical_pitch (5)); // a
144   // 7 always means 7-...
145   scale.push (Musical_pitch (6, -1)); // b
146
147
148   for (int i = 0; i < scale.size (); i++)
149     scale[i].transpose (tonic);
150
151   //urg, should do translation in scheme.
152   char const *acc[] = {"\\textflat\\textflat ", "\\textflat ", "", "\\textsharp " , "\\textsharp\\textsharp "};
153   String tonic_str = tonic.str ();
154   tonic_str = tonic_str.left_str (1).upper_str ()
155     + acc[tonic.accidental_i_ + 2];
156
157   String add_str;
158   String sep_str;
159   for (int i=1; i < pitch_arr_.size (); i++)
160     {
161       Musical_pitch p = pitch_arr_[i];
162       int trap = p.notename_i_ - tonic.notename_i_ 
163         + (p.octave_i_ - tonic.octave_i_) * 7 + 1;
164       int accidental = p.accidental_i_ - scale[(trap - 1) % 7].accidental_i_;
165       if ((trap == 3) && (accidental == -1))
166         tonic_str += "m"; // hmm
167       else if (accidental || (!(trap % 2) || ((i + 1 == pitch_arr_.size ()) && (trap > 5))))
168         {
169           add_str += sep_str;
170           if ((trap == 7) && (accidental == 1))
171             add_str += "maj7";
172           else
173             {
174               add_str += to_str (trap);
175               if (accidental)
176                 add_str += accidental < 0 ? "-" : "+";
177             }
178           sep_str = "/";
179         }
180     }
181
182   String inversion_str;
183   if (tonic_i)
184     {
185       inversion_str = inversion.str ();
186       inversion_str = "/" + inversion_str.left_str (1).upper_str ()
187         + acc[tonic.accidental_i_ + 2];
188
189     }
190   
191   G_text_item* item_p =  new G_text_item;
192
193
194   item_p->text_str_ = tonic_str + "$^{" + add_str + "}$" + inversion_str;
195   Scalar style = get_property ("textstyle", 0);
196   if (style.length_i ())
197     item_p->style_str_ = style;
198   
199   text_p_arr_.push (item_p);
200   announce_element (Score_element_info (item_p, 0));
201 }
202
203 void
204 Chord_name_engraver::do_pre_move_processing ()
205 {
206   for (int i=0; i < text_p_arr_.size (); i++)
207     {
208       typeset_element (text_p_arr_[i]);
209     }
210   text_p_arr_.clear ();
211   pitch_arr_.clear ();
212 }
213