2 chord-name.cc -- implement Chord_name
4 source file of the GNU LilyPond music typesetter
6 (c) 1999 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 "lily-guile.icc"
19 TODO: move text lookup out of Chord_name
23 word is roman text or styled text:
28 Chord_name::ly_word2molecule (SCM scm
) const
33 style
= ly_scm2string (gh_car (scm
));
36 String text
= ly_scm2string (scm
);
37 return lookup_l ()->text (style
, text
, paper_l ());
41 scm is word or list of words:
46 Chord_name::ly_text2molecule (SCM scm
) const
51 while (gh_cdr (scm
) != SCM_EOL
)
53 mol
.add_at_edge (X_AXIS
, RIGHT
, ly_word2molecule (gh_car (scm
)), 0);
58 mol
.add_at_edge (X_AXIS
, RIGHT
, ly_word2molecule (scm
), 0);
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
)),
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.
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);
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;
98 while (diff
.notename_i_
< 0)
100 diff
.notename_i_
+= 7;
104 diff
.accidental_i_
-= (tonic
.semitone_pitch () + diff
.semitone_pitch ())
105 - p
.semitone_pitch ();
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);
121 for (int i
= chord_type
.size (); i
--; )
122 chord
= gh_cons (to_scm (chord_type
[i
]), chord
);
124 SCM chord
= array_to_scm (chord_type
);
127 SCM name
= scm_eval (gh_list (ly_symbol2scm ("user-chord-name"),
128 ly_quote_scm (chord
),
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
));
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
157 for (int i
=0; i
<16; i
++)
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))
177 || ((i
== add_arr
.size () - 1) && (step
> 5))))
181 if ((step
== 7) && (accidental
== 1))
187 add_str
+= to_str (step
);
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
);
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);
222 fix silly to-and-fro scm conversions
225 Chord_name::do_brew_molecule () const
227 Array
<Musical_pitch
> pitch_arr
;
228 scm_to_array (get_elt_property ("pitches"), &pitch_arr
);
229 Musical_pitch tonic
= pitch_arr
[0];
232 name
.tonic_mol
= pitch2molecule (tonic
);
235 if user has explicitely listed chord name, use that
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
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 ());
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 ());
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
));
290 mol
.add_at_edge (X_AXIS
, RIGHT
, name
.tonic_mol
, 0);
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);