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