2 chord-name.cc -- implement Chord_name
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2000 Jan Nieuwenhuizen <janneke@gnu.org>
9 #include "chord-name.hh"
10 #include "musical-request.hh"
13 #include "molecule.hh"
14 #include "paper-def.hh"
16 #include "staff-symbol-referencer.hh"
20 TODO: move text lookup out of Chord_name
24 word is roman text or styled text:
29 Chord_name::ly_word2molecule (SCM scm) const
36 style = ly_scm2string (s);
39 if (gh_string_p (scm))
40 return lookup_l ()->text (style, ly_scm2string (scm), paper_l ());
45 scm is word or list of words:
50 Chord_name::ly_text2molecule (SCM scm) const
55 while (gh_cdr (scm) != SCM_EOL)
57 Molecule m = ly_word2molecule (gh_car (scm));
59 mol.add_at_edge (X_AXIS, RIGHT, m, 0);
64 Molecule m = ly_word2molecule (scm);
66 mol.add_at_edge (X_AXIS, RIGHT, m, 0);
71 Chord_name::pitch2molecule (Musical_pitch p) const
73 SCM name = scm_eval (gh_list (ly_symbol2scm ("user-pitch-name"),
74 ly_quote_scm (p.to_scm ()),
77 if (name != SCM_UNSPECIFIED)
79 return ly_text2molecule (name);
82 Molecule mol = lookup_l ()->text ("", p.str ().left_str (1).upper_str (), paper_l ());
85 We want the smaller size, even if we're big ourselves.
89 Molecule acc = paper_l ()->lookup_l (-3)->afm_find
90 (String ("accidentals-") + to_str (p.accidental_i_));
91 // urg, howto get a good superscript_y?
92 Real super_y = lookup_l ()->text ("", "x", paper_l ()).extent
93 ()[Y_AXIS].length () / 2;
94 super_y += -acc.extent ()[Y_AXIS][MIN];
95 acc.translate_axis (super_y, Y_AXIS);
96 mol.add_at_edge (X_AXIS, RIGHT, acc, 0.0);
103 diff_pitch (Musical_pitch tonic, Musical_pitch p)
105 Musical_pitch diff (p.notename_i_ - tonic.notename_i_,
106 p.accidental_i_ - tonic.accidental_i_,
107 p.octave_i_ - tonic.octave_i_);
109 while (diff.notename_i_ >= 7)
111 diff.notename_i_ -= 7;
114 while (diff.notename_i_ < 0)
116 diff.notename_i_ += 7;
120 diff.accidental_i_ -= (tonic.semitone_pitch () + diff.semitone_pitch ())
121 - p.semitone_pitch ();
130 Chord_name::user_chord_name (Array<Musical_pitch> pitch_arr, Chord_mol* name_p) const
132 Array<Musical_pitch> chord_type = pitch_arr;
133 Chord::rebuild_transpose (&chord_type, diff_pitch (pitch_arr[0], Musical_pitch (0)), false);
136 for (int i= chord_type.size (); i--; )
137 chord = gh_cons (chord_type[i].to_scm (), chord);
140 SCM name = scm_eval (gh_list (ly_symbol2scm ("user-chord-name"),
141 ly_quote_scm (chord),
143 if (gh_pair_p (name))
145 name_p->modifier_mol = ly_text2molecule (gh_car (name));
146 name_p->addition_mol = ly_text2molecule (gh_cdr (name));
153 Chord_name::banter (Array<Musical_pitch> pitch_arr, Chord_mol* name_p) const
155 Array<Musical_pitch> add_arr;
156 Array<Musical_pitch> sub_arr;
157 Chord::find_additions_and_subtractions (pitch_arr, &add_arr, &sub_arr);
159 Array<Musical_pitch> scale;
160 for (int i=0; i < 7; i++)
161 scale.push (Musical_pitch (i));
163 Musical_pitch tonic = pitch_arr[0];
164 Chord::rebuild_transpose (&scale, tonic, true);
167 Does chord include this step? -1 if flat
170 for (int i=0; i<16; i++)
176 for (int i = 0; i < add_arr.size (); i++)
178 Musical_pitch p = add_arr[i];
179 int step = Chord::step_i (tonic, p);
180 int accidental = p.accidental_i_ - scale[(step - 1) % 7].accidental_i_;
181 if ((step < 16) && (has[step] != -1))
182 has[step] = accidental == -1 ? -1 : 1;
183 // only from guile table ?
184 if ((step == 3) && (accidental == -1))
190 || ((i == add_arr.size () - 1) && (step > 5))))
194 if ((step == 7) && (accidental == 1))
200 add_str += to_str (step);
202 add_str += accidental < 0 ? "-" : "+";
207 for (int i = 0; i < sub_arr.size (); i++)
209 Musical_pitch p = sub_arr[i];
210 int step = Chord::step_i (tonic, p);
212 if additions include 2 or 4, assume sus2/4 and don't display 'no3'
214 if (!((step == 3) && (has[2] || has[4])))
216 add_str += sep_str + "no" + to_str (step);
221 if (mod_str.length_i ())
222 name_p->modifier_mol.add_at_edge (X_AXIS, RIGHT,
223 lookup_l ()->text ("roman", mod_str, paper_l ()), 0);
224 if (add_str.length_i ())
226 if (!name_p->addition_mol.empty_b ())
227 add_str = "/" + add_str;
228 name_p->addition_mol.add_at_edge (X_AXIS, RIGHT,
229 lookup_l ()->text ("script", add_str, paper_l ()), 0);
235 fix silly to-and-fro scm conversions
238 Chord_name::do_brew_molecule () const
240 Array<Musical_pitch> pitch_arr;
242 for (SCM s = get_elt_property ("pitches"); s != SCM_EOL; s = gh_cdr (s))
243 pitch_arr.push (Musical_pitch (gh_car (s)));
245 Musical_pitch tonic = pitch_arr[0];
248 name.tonic_mol = pitch2molecule (tonic);
251 if user has explicitely listed chord name, use that
255 maybe we should check all sub-lists of pitches, not
256 just full list and base triad?
258 if (!user_chord_name (pitch_arr, &name))
261 else, check if user has listed base triad
262 use user base name and add banter for remaining part
264 if ((pitch_arr.size () > 2)
265 && user_chord_name (pitch_arr.slice (0, 3), &name))
267 Array<Musical_pitch> base = Chord::base_arr (tonic);
268 base.concat (pitch_arr.slice (3, pitch_arr.size ()));
269 banter (base, &name);
272 else, use pure banter
276 banter (pitch_arr, &name);
280 SCM s = get_elt_property ("inversion");
281 if (s != SCM_UNDEFINED)
283 name.inversion_mol = lookup_l ()->text ("", "/", paper_l ());
286 Molecule mol = pitch2molecule (p);
287 name.inversion_mol.add_at_edge (X_AXIS, RIGHT, mol, 0);
290 s = get_elt_property ("bass");
291 if (s != SCM_UNDEFINED)
293 name.bass_mol = lookup_l ()->text ("", "/", paper_l ());
295 Molecule mol = pitch2molecule (p);
296 name.bass_mol.add_at_edge (X_AXIS, RIGHT, mol, 0);
299 // urg, howto get a good superscript_y?
300 Real super_y = lookup_l ()->text ("", "x", paper_l ()).extent
301 ()[Y_AXIS].length () / 2;
302 if (!name.addition_mol.empty_b ())
303 name.addition_mol.translate (Offset (0, super_y));
306 mol.add_at_edge (X_AXIS, RIGHT, name.tonic_mol, 0);
308 if (!name.modifier_mol.empty_b ())
309 mol.add_at_edge (X_AXIS, RIGHT, name.modifier_mol, 0);
310 if (!name.addition_mol.empty_b ())
311 mol.add_at_edge (X_AXIS, RIGHT, name.addition_mol, 0);
312 if (!name.inversion_mol.empty_b ())
313 mol.add_at_edge (X_AXIS, RIGHT, name.inversion_mol, 0);
314 if (!name.bass_mol.empty_b ())
315 mol.add_at_edge (X_AXIS, RIGHT, name.bass_mol, 0);
317 s = get_elt_property ("word-space");
319 mol.dim_.interval_a_[X_AXIS][RIGHT] += gh_scm2double (s)
320 * staff_symbol_referencer (this).staff_space ();