2 chord.cc -- implement Chord
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2003 Jan Nieuwenhuizen <janneke@gnu.org>
13 #include "music-list.hh"
18 Chord::base_pitches (SCM tonic)
22 SCM major = Pitch (0, 2, 0).smobbed_copy ();
23 SCM minor = Pitch (0, 2, -1).smobbed_copy ();
25 base = gh_cons (tonic, base);
26 base = gh_cons (ly_pitch_transpose (ly_car (base), major), base);
27 base = gh_cons (ly_pitch_transpose (ly_car (base), minor), base);
29 return scm_reverse_x (base, SCM_EOL);
33 Chord::transpose_pitches (SCM tonic, SCM pitches)
36 hoe doe je lambda in C?
38 SCM transposed = SCM_EOL;
39 for (SCM i = pitches; gh_pair_p (i); i = ly_cdr (i))
41 transposed = gh_cons (ly_pitch_transpose (tonic, ly_car (i)),
44 return scm_reverse_x (transposed, SCM_EOL);
48 burp, in SCM duw je gewoon een (if (= (step x) 7) (...)) door pitches
51 If step == 0, lower all.
54 Chord::lower_step (SCM tonic, SCM pitches, SCM step)
56 SCM lowered = SCM_EOL;
57 for (SCM i = pitches; gh_pair_p (i); i = ly_cdr (i))
60 if (gh_equal_p (step_scm (tonic, ly_car (i)), step)
61 || gh_scm2int (step) == 0)
63 p = ly_pitch_transpose (p, Pitch (0, 0, -1).smobbed_copy ());
65 lowered = gh_cons (p, lowered);
67 return scm_reverse_x (lowered, SCM_EOL);
70 /* Return member that has same notename, disregarding octave or alterations */
72 Chord::member_notename (SCM p, SCM pitches)
74 /* If there's an exact match, make sure to return that */
75 SCM member = gh_member (p, pitches);
76 if (member == SCM_BOOL_F)
78 for (SCM i = pitches; gh_pair_p (i); i = ly_cdr (i))
81 Urg, eindelijk gevonden: () != #f, kan maar niet aan wennen.
82 Anders kon iets korter...
84 if (unsmob_pitch (p)->get_notename ()
85 == unsmob_pitch (ly_car (i))->get_notename ())
93 member = ly_car (member);
97 /* Return member that has same notename and alteration, disregarding octave */
99 Chord::member_pitch (SCM p, SCM pitches)
101 /* If there's an exact match, make sure to return that */
102 SCM member = gh_member (p, pitches);
103 if (member == SCM_BOOL_F)
105 for (SCM i = pitches; gh_pair_p (i); i = ly_cdr (i))
107 if (unsmob_pitch (p)->get_notename ()
108 == unsmob_pitch (ly_car (i))->get_notename ()
109 && unsmob_pitch (p)->get_alteration()
110 == unsmob_pitch (ly_car (i))->get_alteration())
118 member = ly_car (member);
123 Chord::step_scm (SCM tonic, SCM p)
125 /* De Pitch intervaas is nog beetje sleutelgat? */
126 int i = unsmob_pitch (p)->get_notename ()
127 - unsmob_pitch (tonic)->get_notename ()
128 + (unsmob_pitch (p)->get_octave ()
129 - unsmob_pitch (tonic)->get_octave ()) * 7;
133 return scm_int2num (i);
137 Assuming that PITCHES is a chord, with tonic (CAR PITCHES), find
138 missing thirds, only considering notenames. Eg, for
148 Chord::missing_thirds (SCM pitches)
150 SCM thirds = SCM_EOL;
152 /* is the third c-e, d-f, etc. small or large? */
153 int minormajor_a[] = {0, -1, -1, 0, 0, -1, -1};
154 for (int i=0; i < 7; i++)
155 thirds = gh_cons (Pitch (0, 2, minormajor_a[i]).smobbed_copy (),
157 thirds = scm_vector (scm_reverse_x (thirds, SCM_EOL));
159 SCM tonic = ly_car (pitches);
161 SCM missing = SCM_EOL;
163 for (SCM i = pitches; gh_pair_p (i);)
166 int step = gh_scm2int (step_scm (tonic, p));
168 if (unsmob_pitch (last)->get_notename () == unsmob_pitch (p)->get_notename ())
170 int third = (unsmob_pitch (last)->get_notename ()
171 - unsmob_pitch (tonic)-> get_notename () + 7) % 7;
172 last = ly_pitch_transpose (last, scm_vector_ref (thirds, scm_int2num (third)));
175 if (step > gh_scm2int (step_scm (tonic, last)))
177 while (step > gh_scm2int (step_scm (tonic, last)))
179 missing = gh_cons (last, missing);
180 int third = (unsmob_pitch (last)->get_notename ()
181 - unsmob_pitch (tonic)->get_notename () + 7) % 7;
182 last = ly_pitch_transpose (last, scm_vector_ref (thirds,
183 scm_int2num (third)));
192 return lower_step (tonic, missing, scm_int2num (7));
195 /* Return PITCHES with PITCH added not as lowest note */
197 Chord::add_above_tonic (SCM pitch, SCM pitches)
199 /* Should we maybe first make sure that PITCH is below tonic? */
200 if (pitches != SCM_EOL)
201 while (Pitch::less_p (pitch, ly_car (pitches)) == SCM_BOOL_T)
202 pitch = ly_pitch_transpose (pitch, Pitch (1, 0, 0).smobbed_copy ());
204 pitches = gh_cons (pitch, pitches);
205 return scm_sort_list (pitches, Pitch::less_p_proc);
208 /* Return PITCHES with PITCH added as lowest note */
210 Chord::add_below_tonic (SCM pitch, SCM pitches)
212 if (pitches != SCM_EOL)
213 while (Pitch::less_p (ly_car (pitches), pitch) == SCM_BOOL_T)
214 pitch = ly_pitch_transpose (pitch, Pitch (-1, 0, 0).smobbed_copy ());
215 return gh_cons (pitch, pitches);
223 Construct from parser output:
225 PITCHES is the plain chord, it does not include bass or inversion
227 Part of Chord:: namespace for now, because we do lots of
228 chord-manipulating stuff.
231 Chord::tonic_add_sub_to_pitches (SCM tonic, SCM add, SCM sub)
233 /* urg: catch dim modifier: 3rd, 5th, 7th, .. should be lowered */
235 for (SCM i = add; gh_pair_p (i); i = ly_cdr (i))
237 Pitch* p = unsmob_pitch (ly_car (i));
239 This chord modifier stuff should really be fixed
242 if (p->get_octave () == -100)
245 Pitch t (0, p->get_notename(), p->get_alteration());
246 gh_set_car_x (i, t.smobbed_copy());
251 add = transpose_pitches (tonic, add);
252 add = lower_step (tonic, add, scm_int2num (7));
253 add = scm_sort_list (add, Pitch::less_p_proc);
254 add = ly_unique (add);
256 sub = transpose_pitches (tonic, sub);
257 sub = lower_step (tonic, sub, scm_int2num (7));
258 sub = scm_sort_list (sub, Pitch::less_p_proc);
260 /* default chord includes upto 5: <1, 3, 5> */
261 add = gh_cons (tonic, add);
264 SCM fifth = ly_last (base_pitches (tonic));
265 int highest_step = gh_scm2int (step_scm (tonic, ly_last (tmp)));
266 if (highest_step < 5)
267 tmp = ly_snoc (fifth, tmp);
270 add = lower_step (tonic, add, scm_int2num (5));
271 add = lower_step (tonic, add, scm_int2num (7));
274 /* find missing thirds */
275 SCM missing = missing_thirds (tmp);
276 if (highest_step < 5)
277 missing = ly_snoc (fifth, missing);
279 /* if dim modifier is given: lower all missing */
281 missing = lower_step (tonic, missing, scm_int2num (0));
283 /* if additions include any 3, don't add third */
284 SCM third = ly_cadr (base_pitches (tonic));
285 if (member_notename (third, add) != SCM_BOOL_F)
286 missing = scm_delete (third, missing);
288 /* if additions include any 4, assume sus4 and don't add third implicitely
289 C-sus (4) = c f g (1 4 5) */
290 SCM sus = ly_pitch_transpose (tonic, Pitch (0, 3, 0).smobbed_copy ());
291 if (member_notename (sus, add) != SCM_BOOL_F)
292 missing = scm_delete (third, missing);
294 /* if additions include some 5, don't add fifth */
295 if (member_notename (fifth, add) != SCM_BOOL_F)
296 missing = scm_delete (fifth, missing);
298 /* complete the list of thirds to be added */
299 add = gh_append2 (missing, add);
300 add = scm_sort_list (add, Pitch::less_p_proc);
302 SCM pitches = SCM_EOL;
303 /* Add all that aren't subtracted */
304 for (SCM i = add; gh_pair_p (i); i = ly_cdr (i))
307 SCM s = member_notename (p, sub);
309 sub = scm_delete (s, sub);
311 pitches = gh_cons (p, pitches);
313 pitches = scm_sort_list (pitches, Pitch::less_p_proc);
315 for (SCM i = sub; gh_pair_p (i); i = ly_cdr (i))
316 warning (_f ("invalid subtraction: not part of chord: %s",
317 unsmob_pitch (ly_car (i))->string ()));
323 /* --Het lijkt me dat dit in het paarse gedeelte moet. */
325 Chord::get_chord (SCM tonic, SCM add, SCM sub, SCM inversion, SCM bass, SCM dur)
327 SCM pitches = tonic_add_sub_to_pitches (tonic, add, sub);
329 if (inversion != SCM_EOL)
331 /* If inversion requested, check first if the note is part of chord */
332 SCM s = member_pitch (inversion, pitches);
335 /* Then, delete and add as base note, ie: the inversion */
336 pitches = scm_delete (s, pitches);
337 Music * n = make_music_by_name (ly_symbol2scm ("NoteEvent"));
338 n->set_mus_property ("pitch", ly_car (add_below_tonic (s, pitches)));
339 n->set_mus_property ("duration", dur);
340 n->set_mus_property ("inversion", SCM_BOOL_T);
341 list = gh_cons (n->self_scm (), list);
342 scm_gc_unprotect_object (n->self_scm ());
345 warning (_f ("invalid inversion pitch: not part of chord: %s",
346 unsmob_pitch (inversion)->string ()));
349 /* Bass is easy, just add if requested */
352 Music * n = make_music_by_name (ly_symbol2scm ("NoteEvent"));
353 n->set_mus_property ("pitch", ly_car (add_below_tonic (bass, pitches)));
354 n->set_mus_property ("duration", dur);
355 n->set_mus_property ("bass", SCM_BOOL_T);
356 list = gh_cons (n->self_scm (), list);
357 scm_gc_unprotect_object (n->self_scm ());
360 for (SCM i = pitches; gh_pair_p (i); i = ly_cdr (i))
362 Music * n = make_music_by_name(ly_symbol2scm ("NoteEvent"));
363 n->set_mus_property ("pitch", ly_car (i));
364 n->set_mus_property ("duration", dur);
365 list = gh_cons (n->self_scm (), list);
366 scm_gc_unprotect_object (n->self_scm ());
369 Music * v = make_music_by_name(ly_symbol2scm ("EventChord"));
370 v->set_mus_property ("elements", list);