lilypond-1.3.16
[lilypond.git] / lily / chord-name.cc
blobf994dd34527405a7edf9bfce51da9827a01007c0
1 /*
2 chord-name.cc -- implement Chord_name
4 source file of the GNU LilyPond music typesetter
6 (c) 1999 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
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"
19 TODO: move text lookup out of Chord_name
23 word is roman text or styled text:
24 "text"
25 ("style" . "text")
27 Molecule
28 Chord_name::ly_word2molecule (SCM scm) const
30 String style;
31 if (gh_pair_p (scm))
33 style = ly_scm2string (gh_car (scm));
34 scm = gh_cdr (scm);
36 String text = ly_scm2string (scm);
37 return lookup_l ()->text (style, text, paper_l ());
41 scm is word or list of words:
42 word
43 (word word)
45 Molecule
46 Chord_name::ly_text2molecule (SCM scm) const
48 Molecule mol;
49 if (gh_list_p (scm))
51 while (gh_cdr (scm) != SCM_EOL)
53 mol.add_at_edge (X_AXIS, RIGHT, ly_word2molecule (gh_car (scm)), 0);
54 scm = gh_cdr (scm);
56 scm = gh_car (scm);
58 mol.add_at_edge (X_AXIS, RIGHT, ly_word2molecule (scm), 0);
59 return mol;
62 Molecule
63 Chord_name::pitch2molecule (Musical_pitch p) const
65 SCM name = scm_eval (gh_list (ly_symbol2scm ("user-pitch-name"),
66 ly_quote_scm (to_scm (p)),
67 SCM_UNDEFINED));
69 if (name != SCM_UNSPECIFIED)
71 return ly_text2molecule (name);
74 Molecule mol = lookup_l ()->text ("", p.str ().left_str (1).upper_str (), paper_l ());
77 We want the smaller size, even if we're big ourselves.
79 if (p.accidental_i_)
80 mol.add_at_edge (X_AXIS, RIGHT,
82 paper_l ()->lookup_l (-2)->afm_find (String ("accidentals-") + to_str (p.accidental_i_)), 0.0);
83 return mol;
86 Musical_pitch
87 diff_pitch (Musical_pitch tonic, Musical_pitch p)
89 Musical_pitch diff (p.notename_i_ - tonic.notename_i_,
90 p.accidental_i_ - tonic.accidental_i_,
91 p.octave_i_ - tonic.octave_i_);
93 while (diff.notename_i_ >= 7)
95 diff.notename_i_ -= 7;
96 diff.octave_i_ ++;
98 while (diff.notename_i_ < 0)
100 diff.notename_i_ += 7;
101 diff.octave_i_ --;
104 diff.accidental_i_ -= (tonic.semitone_pitch () + diff.semitone_pitch ())
105 - p.semitone_pitch ();
107 return diff;
111 JUNKME
113 bool
114 Chord_name::user_chord_name (Array<Musical_pitch> pitch_arr, Chord_mol* name_p) const
116 Array<Musical_pitch> chord_type = pitch_arr;
117 Chord::rebuild_transpose (&chord_type, diff_pitch (pitch_arr[0], Musical_pitch (0)), false);
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
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))
132 name_p->modifier_mol = ly_text2molecule (gh_car (name));
133 name_p->addition_mol = ly_text2molecule (gh_cdr (name));
134 return true;
136 return false;
139 void
140 Chord_name::banter (Array<Musical_pitch> pitch_arr, Chord_mol* name_p) const
142 Array<Musical_pitch> add_arr;
143 Array<Musical_pitch> sub_arr;
144 Chord::find_additions_and_subtractions (pitch_arr, &add_arr, &sub_arr);
146 Array<Musical_pitch> scale;
147 for (int i=0; i < 7; i++)
148 scale.push (Musical_pitch (i));
150 Musical_pitch tonic = pitch_arr[0];
151 Chord::rebuild_transpose (&scale, tonic, true);
154 Does chord include this step? -1 if flat
156 int has[16];
157 for (int i=0; i<16; i++)
158 has[i] = 0;
160 String mod_str;
161 String add_str;
162 String sep_str;
163 for (int i = 0; i < add_arr.size (); i++)
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))
173 mod_str = "m";
175 else if (accidental
176 || (!(step % 2)
177 || ((i == add_arr.size () - 1) && (step > 5))))
179 add_str += sep_str;
180 sep_str = "/";
181 if ((step == 7) && (accidental == 1))
183 add_str += "maj7";
185 else
187 add_str += to_str (step);
188 if (accidental)
189 add_str += accidental < 0 ? "-" : "+";
194 for (int i = 0; i < sub_arr.size (); i++)
196 Musical_pitch p = sub_arr[i];
197 int step = Chord::step_i (tonic, p);
199 if additions include 2 or 4, assume sus2/4 and don't display 'no3'
201 if (!((step == 3) && (has[2] || has[4])))
203 add_str += sep_str + "no" + to_str (step);
204 sep_str = "/";
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 ())
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);
221 TODO:
222 fix silly to-and-fro scm conversions
224 Molecule*
225 Chord_name::do_brew_molecule_p () const
227 Array<Musical_pitch> pitch_arr;
228 scm_to_array (get_elt_property ("pitches"), &pitch_arr);
229 Musical_pitch tonic = pitch_arr[0];
231 Chord_mol name;
232 name.tonic_mol = pitch2molecule (tonic);
235 if user has explicitely listed chord name, use that
237 TODO
239 maybe we should check all sub-lists of pitches, not
240 just full list and base triad?
242 if (!user_chord_name (pitch_arr, &name))
245 else, check if user has listed base triad
246 use user base name and add banter for remaining part
248 if ((pitch_arr.size () > 2)
249 && user_chord_name (pitch_arr.slice (0, 3), &name))
251 Array<Musical_pitch> base = Chord::base_arr (tonic);
252 base.concat (pitch_arr.slice (3, pitch_arr.size ()));
253 banter (base, &name);
256 else, use pure banter
258 else
260 banter (pitch_arr, &name);
264 SCM s = get_elt_property ("inversion");
265 if (s != SCM_UNDEFINED)
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);
274 s = get_elt_property ("bass");
275 if (s != SCM_UNDEFINED)
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);
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));
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;