2 chord.cc -- implement Chord
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2002 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)->notename_
85 == unsmob_pitch (ly_car (i))->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)->notename_
108 == unsmob_pitch (ly_car (i))->notename_
109 && unsmob_pitch (p)->alteration_
110 == unsmob_pitch (ly_car (i))->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)->notename_
127 - unsmob_pitch (tonic)->notename_
128 + (unsmob_pitch (p)->octave_
129 - unsmob_pitch (tonic)->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)->notename_ == unsmob_pitch (p)->notename_)
170 int third = (unsmob_pitch (last)->notename_
171 - unsmob_pitch (tonic)-> 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)->notename_
181 - unsmob_pitch (tonic)->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)
248 add = transpose_pitches (tonic, add);
249 add = lower_step (tonic, add, scm_int2num (7));
250 add = scm_sort_list (add, Pitch::less_p_proc);
251 add = ly_unique (add);
253 sub = transpose_pitches (tonic, sub);
254 sub = lower_step (tonic, sub, scm_int2num (7));
255 sub = scm_sort_list (sub, Pitch::less_p_proc);
257 /* default chord includes upto 5: <1, 3, 5> */
258 add = gh_cons (tonic, add);
261 SCM fifth = ly_last (base_pitches (tonic));
262 int highest_step = gh_scm2int (step_scm (tonic, ly_last (tmp)));
263 if (highest_step < 5)
264 tmp = ly_snoc (fifth, tmp);
267 add = lower_step (tonic, add, scm_int2num (5));
268 add = lower_step (tonic, add, scm_int2num (7));
271 /* find missing thirds */
272 SCM missing = missing_thirds (tmp);
273 if (highest_step < 5)
274 missing = ly_snoc (fifth, missing);
276 /* if dim modifier is given: lower all missing */
278 missing = lower_step (tonic, missing, scm_int2num (0));
280 /* if additions include any 3, don't add third */
281 SCM third = ly_cadr (base_pitches (tonic));
282 if (member_notename (third, add) != SCM_BOOL_F)
283 missing = scm_delete (third, missing);
285 /* if additions include any 4, assume sus4 and don't add third implicitely
286 C-sus (4) = c f g (1 4 5) */
287 SCM sus = ly_pitch_transpose (tonic, Pitch (0, 3, 0).smobbed_copy ());
288 if (member_notename (sus, add) != SCM_BOOL_F)
289 missing = scm_delete (third, missing);
291 /* if additions include some 5, don't add fifth */
292 if (member_notename (fifth, add) != SCM_BOOL_F)
293 missing = scm_delete (fifth, missing);
295 /* complete the list of thirds to be added */
296 add = gh_append2 (missing, add);
297 add = scm_sort_list (add, Pitch::less_p_proc);
299 SCM pitches = SCM_EOL;
300 /* Add all that aren't subtracted */
301 for (SCM i = add; gh_pair_p (i); i = ly_cdr (i))
304 SCM s = member_notename (p, sub);
306 sub = scm_delete (s, sub);
308 pitches = gh_cons (p, pitches);
310 pitches = scm_sort_list (pitches, Pitch::less_p_proc);
312 for (SCM i = sub; gh_pair_p (i); i = ly_cdr (i))
313 warning (_f ("invalid subtraction: not part of chord: %s",
314 unsmob_pitch (ly_car (i))->string ()));
320 /* --Het lijkt me dat dit in het paarse gedeelte moet. */
322 Chord::get_chord (SCM tonic, SCM add, SCM sub, SCM inversion, SCM bass, SCM dur)
324 SCM pitches = tonic_add_sub_to_pitches (tonic, add, sub);
326 if (inversion != SCM_EOL)
328 /* If inversion requested, check first if the note is part of chord */
329 SCM s = member_pitch (inversion, pitches);
332 /* Then, delete and add as base note, ie: the inversion */
333 pitches = scm_delete (s, pitches);
334 Music * n = make_music_by_name (ly_symbol2scm ("NoteEvent"));
335 n->set_mus_property ("pitch", ly_car (add_below_tonic (s, pitches)));
336 n->set_mus_property ("duration", dur);
337 n->set_mus_property ("inversion", SCM_BOOL_T);
338 list = gh_cons (n->self_scm (), list);
339 scm_gc_unprotect_object (n->self_scm ());
342 warning (_f ("invalid inversion pitch: not part of chord: %s",
343 unsmob_pitch (inversion)->string ()));
346 /* Bass is easy, just add if requested */
349 Music * n = make_music_by_name (ly_symbol2scm ("NoteEvent"));
350 n->set_mus_property ("pitch", ly_car (add_below_tonic (bass, pitches)));
351 n->set_mus_property ("duration", dur);
352 n->set_mus_property ("bass", SCM_BOOL_T);
353 list = gh_cons (n->self_scm (), list);
354 scm_gc_unprotect_object (n->self_scm ());
357 for (SCM i = pitches; gh_pair_p (i); i = ly_cdr (i))
359 Music * n = make_music_by_name(ly_symbol2scm ("NoteEvent"));
360 n->set_mus_property ("pitch", ly_car (i));
361 n->set_mus_property ("duration", dur);
362 list = gh_cons (n->self_scm (), list);
363 scm_gc_unprotect_object (n->self_scm ());
366 Music * v = make_music_by_name(ly_symbol2scm ("EventChord"));
367 v->set_mus_property ("elements", list);