]> git.donarmstrong.com Git - lilypond.git/blob - lily/chord-name.cc
patch::: 1.3.45.jcn1
[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     {
82       Molecule acc = paper_l ()->lookup_l (-3)->afm_find
83         (String ("accidentals-") + to_str (p.accidental_i_));
84       // urg, howto get a good superscript_y?
85       Real super_y = lookup_l ()->text ("", "x", paper_l ()).extent
86         ()[Y_AXIS].length () / 2;
87       super_y += -acc.extent ()[Y_AXIS][MIN];
88       acc.translate_axis (super_y, Y_AXIS);
89       mol.add_at_edge (X_AXIS, RIGHT, acc, 0.0);
90     }
91                      
92   return mol;
93 }
94
95 Musical_pitch
96 diff_pitch (Musical_pitch tonic, Musical_pitch  p)
97 {
98   Musical_pitch diff (p.notename_i_ - tonic.notename_i_, 
99     p.accidental_i_ - tonic.accidental_i_, 
100     p.octave_i_ - tonic.octave_i_);
101
102   while  (diff.notename_i_ >= 7)
103     {
104       diff.notename_i_ -= 7;
105       diff.octave_i_ ++;
106     }
107   while  (diff.notename_i_ < 0)
108     {
109       diff.notename_i_ += 7;
110       diff.octave_i_ --;
111     }
112
113   diff.accidental_i_ -= (tonic.semitone_pitch () + diff.semitone_pitch ())
114     - p.semitone_pitch ();
115
116   return diff;
117 }
118
119 /*
120   JUNKME
121  */
122 bool
123 Chord_name::user_chord_name (Array<Musical_pitch> pitch_arr, Chord_mol* name_p) const
124 {
125   Array<Musical_pitch> chord_type = pitch_arr;
126   Chord::rebuild_transpose (&chord_type, diff_pitch (pitch_arr[0], Musical_pitch (0)), false);
127
128   SCM chord = SCM_EOL;
129   for (int i= chord_type.size (); i--; )
130     chord = gh_cons (chord_type[i].to_scm (), chord);
131
132
133   SCM name = scm_eval (gh_list (ly_symbol2scm ("user-chord-name"),
134                                 ly_quote_scm (chord),
135                                 SCM_UNDEFINED));
136   if (gh_pair_p (name))
137     {
138       name_p->modifier_mol = ly_text2molecule (gh_car (name));
139       name_p->addition_mol = ly_text2molecule (gh_cdr (name));
140       return true;
141     }
142   return false;
143 }
144
145 void
146 Chord_name::banter (Array<Musical_pitch> pitch_arr, Chord_mol* name_p) const
147 {
148   Array<Musical_pitch> add_arr;
149   Array<Musical_pitch> sub_arr;
150   Chord::find_additions_and_subtractions (pitch_arr, &add_arr, &sub_arr);
151                            
152   Array<Musical_pitch> scale;
153   for (int i=0; i < 7; i++)
154     scale.push (Musical_pitch (i));
155
156   Musical_pitch tonic = pitch_arr[0];
157   Chord::rebuild_transpose (&scale, tonic, true);
158   
159   /*
160     Does chord include this step?  -1 if flat
161    */
162   int has[16];
163   for (int i=0; i<16; i++)
164     has[i] = 0;
165
166   String mod_str;
167   String add_str;
168   String sep_str;
169   for (int i = 0; i < add_arr.size (); i++)
170     {
171       Musical_pitch p = add_arr[i];
172       int step = Chord::step_i (tonic, p);
173       int accidental = p.accidental_i_ - scale[(step - 1) % 7].accidental_i_;
174       if ((step < 16) && (has[step] != -1))
175         has[step] = accidental == -1 ? -1 : 1;
176       // only from guile table ?
177       if ((step == 3) && (accidental == -1))
178         {
179           mod_str = "m";
180         }
181       else if (accidental
182                || (!(step % 2) 
183                || ((i == add_arr.size () - 1) && (step > 5))))
184         {
185           add_str += sep_str;
186           sep_str = "/";
187           if ((step == 7) && (accidental == 1))
188             {
189               add_str += "maj7";
190             }
191           else
192             {
193               add_str += to_str (step);
194               if (accidental)
195                 add_str += accidental < 0 ? "-" : "+";
196             }
197         }
198     }
199
200   for (int i = 0; i < sub_arr.size (); i++)
201     {
202       Musical_pitch p = sub_arr[i];
203       int step = Chord::step_i (tonic, p);
204       /*
205         if additions include 2 or 4, assume sus2/4 and don't display 'no3'
206       */
207       if (!((step == 3) && (has[2] || has[4])))
208         {
209           add_str += sep_str + "no" + to_str (step);
210           sep_str = "/";
211         }
212     }
213
214   if (mod_str.length_i ())
215     name_p->modifier_mol.add_at_edge (X_AXIS, RIGHT, 
216       lookup_l ()->text ("roman", mod_str, paper_l ()), 0);
217   if (add_str.length_i ())
218     {
219       if (!name_p->addition_mol.empty_b ())
220         add_str = "/" + add_str;
221       name_p->addition_mol.add_at_edge (X_AXIS, RIGHT,
222        lookup_l ()->text ("script", add_str, paper_l ()), 0);
223     }
224 }
225
226 /*
227   TODO:
228     fix silly to-and-fro scm conversions
229  */
230 Molecule 
231 Chord_name::do_brew_molecule () const
232 {
233   Array<Musical_pitch> pitch_arr;
234   
235   for (SCM s = get_elt_property ("pitches"); s != SCM_EOL; s = gh_cdr (s))
236     pitch_arr.push (Musical_pitch (gh_car (s)));
237   
238   Musical_pitch tonic = pitch_arr[0];
239   
240   Chord_mol name;
241   name.tonic_mol = pitch2molecule (tonic);
242
243   /*
244     if user has explicitely listed chord name, use that
245     
246     TODO
247     urg
248     maybe we should check all sub-lists of pitches, not
249     just full list and base triad?
250    */
251   if (!user_chord_name (pitch_arr, &name))
252     {
253       /*
254         else, check if user has listed base triad
255         use user base name and add banter for remaining part
256        */
257       if ((pitch_arr.size () > 2)
258           && user_chord_name (pitch_arr.slice (0, 3), &name))
259         {
260           Array<Musical_pitch> base = Chord::base_arr (tonic);
261           base.concat (pitch_arr.slice (3, pitch_arr.size ()));
262           banter (base, &name);
263         }
264       /*
265         else, use pure banter
266        */
267       else
268         {
269           banter (pitch_arr, &name);
270         }
271     }
272
273   SCM s = get_elt_property ("inversion");
274   if (s != SCM_UNDEFINED)
275     {
276       name.inversion_mol = lookup_l ()->text ("", "/", paper_l ());
277       Musical_pitch p (s);
278
279       Molecule mol = pitch2molecule (p);
280       name.inversion_mol.add_at_edge (X_AXIS, RIGHT, mol, 0);
281     }
282
283   s = get_elt_property ("bass");
284   if (s != SCM_UNDEFINED)
285     {
286       name.bass_mol = lookup_l ()->text ("", "/", paper_l ());
287       Musical_pitch p (s);
288       Molecule mol = pitch2molecule (p);
289       name.bass_mol.add_at_edge (X_AXIS, RIGHT, mol, 0);
290     }
291
292   // urg, howto get a good superscript_y?
293   Real super_y = lookup_l ()->text ("", "x", paper_l ()).extent
294     ()[Y_AXIS].length () / 2;
295   if (!name.addition_mol.empty_b ())
296     name.addition_mol.translate (Offset (0, super_y));
297
298   Molecule  mol;
299   mol.add_at_edge (X_AXIS, RIGHT, name.tonic_mol, 0);
300   // huh?
301   if (!name.modifier_mol.empty_b ())
302     mol.add_at_edge (X_AXIS, RIGHT, name.modifier_mol, 0);
303   if (!name.addition_mol.empty_b ())
304     mol.add_at_edge (X_AXIS, RIGHT, name.addition_mol, 0);
305   if (!name.inversion_mol.empty_b ())
306     mol.add_at_edge (X_AXIS, RIGHT, name.inversion_mol, 0);
307   if (!name.bass_mol.empty_b ())
308     mol.add_at_edge (X_AXIS, RIGHT, name.bass_mol, 0);
309
310   s = get_elt_property ("word-space");
311   if (gh_number_p (s))
312     mol.dim_.interval_a_[X_AXIS][RIGHT] += gh_scm2double (s)
313       * staff_symbol_referencer (this).staff_space ();
314
315   return mol;
316 }