]> git.donarmstrong.com Git - lilypond.git/blob - lily/chord-name.cc
27e3342e51e7ecd34de67b75593a881206ad6083
[lilypond.git] / lily / chord-name.cc
1 /*
2   chord-name.cc -- implement Chord_name
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1999--2000 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
8
9 #include "chord-name.hh"
10 #include "musical-request.hh"
11 #include "warn.hh"
12 #include "debug.hh"
13 #include "molecule.hh"
14 #include "paper-def.hh"
15 #include "lookup.hh"
16 #include "staff-symbol-referencer.hh"
17
18
19 /*
20   TODO: move text lookup out of Chord_name
21  */
22
23 /*
24   word is roman text or styled text:
25    "text"
26    ("style" . "text")
27  */
28 Molecule
29 Chord_name::ly_word2molecule (SCM scm) const
30 {
31   String style;
32   if (gh_pair_p (scm))
33     {
34       style = ly_scm2string (gh_car (scm));
35       scm = gh_cdr (scm);
36     }
37   String text = ly_scm2string (scm);
38   return lookup_l ()->text (style, text, paper_l ());
39 }
40
41 /*
42  scm is word or list of words:
43    word
44    (word word)
45  */
46 Molecule
47 Chord_name::ly_text2molecule (SCM scm) const
48 {
49   Molecule mol;
50   if (gh_list_p (scm))
51     {
52       while (gh_cdr (scm) != SCM_EOL)
53         {
54           mol.add_at_edge (X_AXIS, RIGHT, ly_word2molecule (gh_car (scm)), 0);
55           scm = gh_cdr (scm);
56         }
57       scm = gh_car (scm);
58     }  
59   mol.add_at_edge (X_AXIS, RIGHT, ly_word2molecule (scm), 0);
60   return mol;
61 }
62
63 Molecule
64 Chord_name::pitch2molecule (Musical_pitch p) const
65 {
66   SCM name = scm_eval (gh_list (ly_symbol2scm ("user-pitch-name"),
67                                 ly_quote_scm (p.to_scm ()),
68                                 SCM_UNDEFINED));
69
70   if (name != SCM_UNSPECIFIED)
71     {
72       return ly_text2molecule (name);
73     }
74
75   Molecule mol = lookup_l ()->text ("", p.str ().left_str (1).upper_str (), paper_l ());
76
77   /*
78     We want the smaller size, even if we're big ourselves.
79    */
80   if (p.accidental_i_)
81     mol.add_at_edge (X_AXIS, RIGHT, 
82                      
83                      paper_l ()->lookup_l (-2)->afm_find (String ("accidentals-") + to_str (p.accidental_i_)), 0.0);
84   return mol;
85 }
86
87 Musical_pitch
88 diff_pitch (Musical_pitch tonic, Musical_pitch  p)
89 {
90   Musical_pitch diff (p.notename_i_ - tonic.notename_i_, 
91     p.accidental_i_ - tonic.accidental_i_, 
92     p.octave_i_ - tonic.octave_i_);
93
94   while  (diff.notename_i_ >= 7)
95     {
96       diff.notename_i_ -= 7;
97       diff.octave_i_ ++;
98     }
99   while  (diff.notename_i_ < 0)
100     {
101       diff.notename_i_ += 7;
102       diff.octave_i_ --;
103     }
104
105   diff.accidental_i_ -= (tonic.semitone_pitch () + diff.semitone_pitch ())
106     - p.semitone_pitch ();
107
108   return diff;
109 }
110
111 /*
112   JUNKME
113  */
114 bool
115 Chord_name::user_chord_name (Array<Musical_pitch> pitch_arr, Chord_mol* name_p) const
116 {
117   Array<Musical_pitch> chord_type = pitch_arr;
118   Chord::rebuild_transpose (&chord_type, diff_pitch (pitch_arr[0], Musical_pitch (0)), false);
119
120   SCM chord = SCM_EOL;
121   for (int i= chord_type.size (); i--; )
122     chord = gh_cons (chord_type[i].to_scm (), chord);
123
124
125   SCM name = scm_eval (gh_list (ly_symbol2scm ("user-chord-name"),
126                                 ly_quote_scm (chord),
127                                 SCM_UNDEFINED));
128   if (gh_pair_p (name))
129     {
130       name_p->modifier_mol = ly_text2molecule (gh_car (name));
131       name_p->addition_mol = ly_text2molecule (gh_cdr (name));
132       return true;
133     }
134   return false;
135 }
136
137 void
138 Chord_name::banter (Array<Musical_pitch> pitch_arr, Chord_mol* name_p) const
139 {
140   Array<Musical_pitch> add_arr;
141   Array<Musical_pitch> sub_arr;
142   Chord::find_additions_and_subtractions (pitch_arr, &add_arr, &sub_arr);
143                            
144   Array<Musical_pitch> scale;
145   for (int i=0; i < 7; i++)
146     scale.push (Musical_pitch (i));
147
148   Musical_pitch tonic = pitch_arr[0];
149   Chord::rebuild_transpose (&scale, tonic, true);
150   
151   /*
152     Does chord include this step?  -1 if flat
153    */
154   int has[16];
155   for (int i=0; i<16; i++)
156     has[i] = 0;
157
158   String mod_str;
159   String add_str;
160   String sep_str;
161   for (int i = 0; i < add_arr.size (); i++)
162     {
163       Musical_pitch p = add_arr[i];
164       int step = Chord::step_i (tonic, p);
165       int accidental = p.accidental_i_ - scale[(step - 1) % 7].accidental_i_;
166       if ((step < 16) && (has[step] != -1))
167         has[step] = accidental == -1 ? -1 : 1;
168       // only from guile table ?
169       if ((step == 3) && (accidental == -1))
170         {
171           mod_str = "m";
172         }
173       else if (accidental
174                || (!(step % 2) 
175                || ((i == add_arr.size () - 1) && (step > 5))))
176         {
177           add_str += sep_str;
178           sep_str = "/";
179           if ((step == 7) && (accidental == 1))
180             {
181               add_str += "maj7";
182             }
183           else
184             {
185               add_str += to_str (step);
186               if (accidental)
187                 add_str += accidental < 0 ? "-" : "+";
188             }
189         }
190     }
191
192   for (int i = 0; i < sub_arr.size (); i++)
193     {
194       Musical_pitch p = sub_arr[i];
195       int step = Chord::step_i (tonic, p);
196       /*
197         if additions include 2 or 4, assume sus2/4 and don't display 'no3'
198       */
199       if (!((step == 3) && (has[2] || has[4])))
200         {
201           add_str += sep_str + "no" + to_str (step);
202           sep_str = "/";
203         }
204     }
205
206   if (mod_str.length_i ())
207     name_p->modifier_mol.add_at_edge (X_AXIS, RIGHT, 
208       lookup_l ()->text ("roman", mod_str, paper_l ()), 0);
209   if (add_str.length_i ())
210     {
211       if (!name_p->addition_mol.empty_b ())
212         add_str = "/" + add_str;
213       name_p->addition_mol.add_at_edge (X_AXIS, RIGHT,
214        lookup_l ()->text ("script", add_str, paper_l ()), 0);
215     }
216 }
217
218 /*
219   TODO:
220     fix silly to-and-fro scm conversions
221  */
222 Molecule 
223 Chord_name::do_brew_molecule () const
224 {
225   Array<Musical_pitch> pitch_arr;
226   
227   for (SCM s = get_elt_property ("pitches"); s != SCM_EOL; s = gh_cdr (s))
228     pitch_arr.push (Musical_pitch (gh_car (s)));
229   
230   Musical_pitch tonic = pitch_arr[0];
231   
232   Chord_mol name;
233   name.tonic_mol = pitch2molecule (tonic);
234
235   /*
236     if user has explicitely listed chord name, use that
237     
238     TODO
239     urg
240     maybe we should check all sub-lists of pitches, not
241     just full list and base triad?
242    */
243   if (!user_chord_name (pitch_arr, &name))
244     {
245       /*
246         else, check if user has listed base triad
247         use user base name and add banter for remaining part
248        */
249       if ((pitch_arr.size () > 2)
250           && user_chord_name (pitch_arr.slice (0, 3), &name))
251         {
252           Array<Musical_pitch> base = Chord::base_arr (tonic);
253           base.concat (pitch_arr.slice (3, pitch_arr.size ()));
254           banter (base, &name);
255         }
256       /*
257         else, use pure banter
258        */
259       else
260         {
261           banter (pitch_arr, &name);
262         }
263     }
264
265   SCM s = get_elt_property ("inversion");
266   if (s != SCM_UNDEFINED)
267     {
268       name.inversion_mol = lookup_l ()->text ("", "/", paper_l ());
269       Musical_pitch p (s);
270
271       Molecule mol = pitch2molecule (p);
272       name.inversion_mol.add_at_edge (X_AXIS, RIGHT, mol, 0);
273     }
274
275   s = get_elt_property ("bass");
276   if (s != SCM_UNDEFINED)
277     {
278       name.bass_mol = lookup_l ()->text ("", "/", paper_l ());
279       Musical_pitch p (s);
280       Molecule mol = pitch2molecule (p);
281       name.bass_mol.add_at_edge (X_AXIS, RIGHT, mol, 0);
282     }
283
284   // urg, howto get a good superscript_y?
285   Real super_y = lookup_l ()->text ("", "x", paper_l ()).dim_.y ().length ()/2;
286   if (!name.addition_mol.empty_b ())
287     name.addition_mol.translate (Offset (0, super_y));
288
289   Molecule  mol;
290   mol.add_at_edge (X_AXIS, RIGHT, name.tonic_mol, 0);
291   // huh?
292   if (!name.modifier_mol.empty_b ())
293     mol.add_at_edge (X_AXIS, RIGHT, name.modifier_mol, 0);
294   if (!name.addition_mol.empty_b ())
295     mol.add_at_edge (X_AXIS, RIGHT, name.addition_mol, 0);
296   if (!name.inversion_mol.empty_b ())
297     mol.add_at_edge (X_AXIS, RIGHT, name.inversion_mol, 0);
298   if (!name.bass_mol.empty_b ())
299     mol.add_at_edge (X_AXIS, RIGHT, name.bass_mol, 0);
300
301   s = get_elt_property ("word-space");
302   if (gh_number_p (s))
303     mol.dim_.interval_a_[X_AXIS][RIGHT] += gh_scm2double (s)
304       * staff_symbol_referencer (this).staff_space ();
305
306   return mol;
307 }