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