2 chord.cc -- implement Chord
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2000 Jan Nieuwenhuizen <janneke@gnu.org>
10 #include "musical-request.hh"
13 #include "music-list.hh"
14 #include "musical-request.hh"
19 zijn ze er al in scheme, maar heten ze anders? */
22 /* Remove doubles from (sorted) list */
27 for (SCM i = list; gh_pair_p (i); i = gh_cdr (i))
29 if (!gh_pair_p (gh_cdr (i))
30 || !gh_equal_p (gh_car (i), gh_cadr (i)))
31 unique = gh_cons (gh_car (i), unique);
33 return gh_reverse (unique);
36 /* Hmm, rewrite this using ly_split_list? */
38 ly_delete1 (SCM s, SCM list)
40 SCM removed = SCM_EOL;
41 for (SCM i = list; gh_pair_p (i); i = gh_cdr (i))
43 if (!gh_equal_p (gh_car (i), s))
44 removed = gh_cons (gh_car (i), removed);
46 return gh_reverse (removed);
52 return gh_car (scm_last_pair (list));
57 ly_snoc (SCM s, SCM list)
59 return gh_append2 (list, gh_list (s, SCM_UNDEFINED));
63 /* Split list at member s, removing s.
64 Return (BEFORE . AFTER) */
66 ly_split_list (SCM s, SCM list)
70 for (; gh_pair_p (after);)
72 SCM i = gh_car (after);
73 after = gh_cdr (after);
74 if (gh_equal_p (i, s))
76 before = gh_cons (i, before);
78 return gh_cons (gh_reverse (before), after);
82 /* Construct from list of pitches and requests:
84 (PITCHES . (INVERSION . BASS))
87 Note, the pitches here, are all inclusive.
88 We must identify tonic, filter-out (and maybe detect) inversion and bass. */
91 Chord::pitches_and_requests_to_chord (SCM pitches,
95 bool find_inversion_b)
97 pitches = scm_sort_list (pitches, Pitch::less_p_proc);
99 if (bass_req != SCM_EOL)
101 assert (unsmob_pitch (gh_car (pitches))->notename_i_
102 == unsmob_pitch (bass_req)->notename_i_);
103 pitches = gh_cdr (pitches);
106 if (inversion_req != SCM_EOL)
108 assert (unsmob_pitch (gh_car (pitches))->notename_i_
109 == unsmob_pitch (inversion_req)->notename_i_);
111 assert (tonic_req != SCM_EOL);
113 SCM tonic = member_notename (tonic_req, pitches);
114 if (tonic != SCM_EOL)
115 pitches = add_above_tonic (gh_car (pitches), gh_cdr (pitches));
117 else if (find_inversion_b)
119 SCM tonic = (tonic_req != SCM_EOL)
120 ? member_notename (pitches, tonic_req)
121 : guess_tonic (pitches);
123 if (tonic != SCM_EOL)
124 pitches = add_above_tonic (gh_car (pitches), gh_cdr (pitches));
127 if (tonic_req != SCM_EOL)
128 assert (unsmob_pitch (gh_car (pitches))->notename_i_
129 == unsmob_pitch (tonic_req)->notename_i_);
131 return gh_cons (pitches, gh_cons (inversion_req, bass_req));
136 do something smarter.
140 Chord::base_pitches (SCM tonic)
144 SCM major = Pitch (0, 2, 0).smobbed_copy ();
145 SCM minor = Pitch (0, 2, -1).smobbed_copy ();
147 base = gh_cons (tonic, base);
148 base = gh_cons (Pitch::transpose (gh_car (base), major), base);
149 base = gh_cons (Pitch::transpose (gh_car (base), minor), base);
151 return gh_reverse (base);
155 Chord::transpose_pitches (SCM tonic, SCM pitches)
158 hoe doe je lambda in C?
160 SCM transposed = SCM_EOL;
161 for (SCM i = pitches; gh_pair_p (i); i = gh_cdr (i))
163 transposed = gh_cons (Pitch::transpose (tonic, gh_car (i)),
166 return gh_reverse (transposed);
170 burp, in SCM duw je gewoon een (if (= (step x) 7) (...)) door pitches
173 If step == 0, lower all.
176 Chord::lower_step (SCM tonic, SCM pitches, SCM step)
178 SCM lowered = SCM_EOL;
179 for (SCM i = pitches; gh_pair_p (i); i = gh_cdr (i))
182 if (gh_equal_p (step_scm (tonic, gh_car (i)), step)
183 || gh_scm2int (step) == 0)
185 p = Pitch::transpose (p, Pitch (0, 0, -1).smobbed_copy ());
187 lowered = gh_cons (p, lowered);
189 return gh_reverse (lowered);
192 /* Return member that has same notename, disregarding octave or alterations */
194 Chord::member_notename (SCM p, SCM pitches)
196 /* If there's an exact match, make sure to return that */
197 SCM member = gh_member (p, pitches);
198 if (member == SCM_BOOL_F)
200 for (SCM i = pitches; gh_pair_p (i); i = gh_cdr (i))
203 Urg, eindelijk gevonden: () != #f, kan maar niet aan wennen.
204 Anders kon iets korter...
206 if (unsmob_pitch (p)->notename_i_
207 == unsmob_pitch (gh_car (i))->notename_i_)
217 /* Return member that has same notename and alteration, disregarding octave */
219 Chord::member_pitch (SCM p, SCM pitches)
221 /* If there's an exact match, make sure to return that */
222 SCM member = gh_member (p, pitches);
223 if (member == SCM_BOOL_F)
225 for (SCM i = pitches; gh_pair_p (i); i = gh_cdr (i))
227 if (unsmob_pitch (p)->notename_i_
228 == unsmob_pitch (gh_car (i))->notename_i_
229 && unsmob_pitch (p)->alteration_i_
230 == unsmob_pitch (gh_car (i))->alteration_i_)
243 Chord::step_i (Pitch tonic, Pitch p)
245 int i = p.notename_i_ - tonic.notename_i_
246 + (p.octave_i () - tonic.octave_i () ) * 7;
254 Chord::step_scm (SCM tonic, SCM p)
256 return gh_int2scm (step_i (*unsmob_pitch (tonic), *unsmob_pitch (p)));
260 Assuming that PITCHES is a chord, with tonic (CAR PITCHES), find
261 missing thirds, only considering notenames. Eg, for
271 Chord::missing_thirds (SCM pitches)
273 SCM thirds = SCM_EOL;
275 /* is the third c-e, d-f, etc. small or large? */
276 int minormajor_a[] = {0, -1, -1, 0, 0, -1, -1};
277 for (int i=0; i < 7; i++)
278 thirds = gh_cons (Pitch (0, 2, minormajor_a[i]).smobbed_copy (),
280 thirds = scm_vector (gh_reverse (thirds));
282 SCM tonic = gh_car (pitches);
284 SCM missing = SCM_EOL;
286 for (SCM i = pitches; gh_pair_p (i);)
289 int step = gh_scm2int (step_scm (tonic, p));
291 if (unsmob_pitch (last)->notename_i_ == unsmob_pitch (p)->notename_i_)
293 int third = (unsmob_pitch (last)->notename_i_
294 - unsmob_pitch (tonic)-> notename_i_ + 7) % 7;
295 last = Pitch::transpose (last, scm_vector_ref (thirds, gh_int2scm (third)));
298 if (step > gh_scm2int (step_scm (tonic, last)))
300 while (step > gh_scm2int (step_scm (tonic, last)))
302 missing = gh_cons (last, missing);
303 int third = (unsmob_pitch (last)->notename_i_
304 - unsmob_pitch (tonic)->notename_i_ + 7) % 7;
305 last = Pitch::transpose (last, scm_vector_ref (thirds,
306 gh_int2scm (third)));
315 return lower_step (tonic, missing, gh_int2scm (7));
321 (PITCHES . (INVERSION . BASS))
323 into full list of pitches.
326 - delete INVERSION and add as lowest note of PITCHES
327 - add BASS as lowest note of PITCHES */
330 Chord::to_pitches (SCM chord)
332 SCM pitches = gh_car (chord);
333 SCM modifiers = gh_cdr (chord);
334 SCM inversion = gh_car (modifiers);
335 SCM bass = gh_cdr (modifiers);
337 if (inversion != SCM_EOL)
339 /* If inversion requested, check first if the note is part of chord */
340 SCM s = member_pitch (inversion, pitches);
343 /* Then, delete and add as base note, ie: the inversion */
344 scm_delete (s, pitches);
345 pitches = add_below_tonic (s, pitches);
348 warning (_f ("invalid inversion pitch: not part of chord: %s",
349 unsmob_pitch (inversion)->str ()));
352 /* Bass is easy, just add if requested */
354 pitches = add_below_tonic (bass, pitches);
360 This routine tries to guess tonic in a possibly inversed chord, ie
361 <e g c'> should produce: C.
362 This is only used for chords that are entered as simultaneous notes,
363 chords entered in \chord mode are fully defined.
367 Chord::guess_tonic (SCM pitches)
369 return gh_car (scm_sort_list (pitches, Pitch::less_p_proc));
372 /* Return PITCHES with PITCH added not as lowest note */
374 Chord::add_above_tonic (SCM pitch, SCM pitches)
376 /* Should we maybe first make sure that PITCH is below tonic? */
377 if (pitches != SCM_EOL)
378 while (Pitch::less_p (pitch, gh_car (pitches)) == SCM_BOOL_T)
379 pitch = Pitch::transpose (pitch, Pitch (1, 0, 0).smobbed_copy ());
381 pitches = gh_cons (pitch, pitches);
382 return scm_sort_list (pitches, Pitch::less_p_proc);
385 /* Return PITCHES with PITCH added as lowest note */
387 Chord::add_below_tonic (SCM pitch, SCM pitches)
389 if (pitches != SCM_EOL)
390 while (Pitch::less_p (gh_car (pitches), pitch) == SCM_BOOL_T)
391 pitch = Pitch::transpose (pitch, Pitch (-1, 0, 0).smobbed_copy ());
392 return gh_cons (pitch, pitches);
400 Construct from parser output:
402 (PITCHES . (INVERSION . BASS))
404 PITCHES is the plain chord, it does not include bass or inversion
406 Part of Chord:: namespace for now, because we do lots of
407 chord-manipulating stuff. */
410 Chord::tonic_add_sub_inversion_bass_to_scm (SCM tonic, SCM add, SCM sub,
411 SCM inversion, SCM bass)
413 /* urg: catch dim modifier: 3rd, 5th, 7th, .. should be lowered */
415 for (SCM i = add; gh_pair_p (i); i = gh_cdr (i))
417 Pitch* p = unsmob_pitch (gh_car (i));
418 if (p->octave_i () == -100)
424 add = transpose_pitches (tonic, add);
425 add = lower_step (tonic, add, gh_int2scm (7));
426 add = scm_sort_list (add, Pitch::less_p_proc);
427 add = ly_unique (add);
429 sub = transpose_pitches (tonic, sub);
430 sub = lower_step (tonic, sub, gh_int2scm (7));
431 sub = scm_sort_list (sub, Pitch::less_p_proc);
433 /* default chord includes upto 5: <1, 3, 5> */
434 add = gh_cons (tonic, add);
437 SCM fifth = ly_last (base_pitches (tonic));
438 int highest_step = gh_scm2int (step_scm (tonic, ly_last (tmp)));
439 if (highest_step < 5)
440 tmp = ly_snoc (fifth, tmp);
442 add = lower_step (tonic, add, gh_int2scm (5));
444 /* find missing thirds */
445 SCM missing = missing_thirds (tmp);
446 if (highest_step < 5)
447 missing = ly_snoc (fifth, missing);
449 /* if dim modifier is given: lower all missing */
451 missing = lower_step (tonic, missing, gh_int2scm (0));
453 /* if additions include any 3, don't add third */
454 SCM third = gh_cadr (base_pitches (tonic));
455 if (member_notename (third, add) != SCM_BOOL_F)
456 missing = scm_delete (third, missing);
458 /* if additions include any 4, assume sus4 and don't add third implicitely
459 C-sus (4) = c f g (1 4 5) */
460 SCM sus = Pitch::transpose (tonic, Pitch (0, 3, 0).smobbed_copy ());
461 if (member_notename (sus, add) != SCM_BOOL_F)
462 missing = scm_delete (third, missing);
464 /* if additions include some 5, don't add fifth */
465 if (member_notename (fifth, add) != SCM_BOOL_F)
466 missing = scm_delete (fifth, missing);
468 /* complete the list of thirds to be added */
469 add = gh_append2 (missing, add);
470 add = scm_sort_list (add, Pitch::less_p_proc);
472 SCM pitches = SCM_EOL;
473 /* Add all that aren't subtracted */
474 for (SCM i = add; gh_pair_p (i); i = gh_cdr (i))
477 SCM s = member_notename (p, sub);
479 sub = scm_delete (s, sub);
481 pitches = gh_cons (p, pitches);
483 pitches = scm_sort_list (pitches, Pitch::less_p_proc);
485 for (SCM i = sub; gh_pair_p (i); i = gh_cdr (i))
486 warning (_f ("invalid subtraction: not part of chord: %s",
487 unsmob_pitch (gh_car (i))->str ()));
489 return gh_cons (pitches, gh_cons (inversion, bass));
494 --Het lijkt me dat dit in het paarse gedeelte moet.
496 Zo-en-zo, lijktme dat je ipv. Inversion_req een (inversion . #t) aan
497 de betreffende Noot_req kan hangen
501 Chord::get_chord (SCM tonic, SCM add, SCM sub, SCM inversion, SCM bass, SCM dur)
503 SCM chord = tonic_add_sub_inversion_bass_to_scm (tonic, add, sub,
506 Tonic_req* t = new Tonic_req;
507 t->set_mus_property ("pitch", tonic);
508 SCM l = gh_cons (t->self_scm (), SCM_EOL);
510 SCM modifiers = gh_cdr (chord);
511 inversion = gh_car (modifiers);
512 bass = gh_cdr (modifiers);
515 Should add (inversion . #t) to the pitch that is an inversion
517 if (inversion != SCM_EOL)
519 Inversion_req* i = new Inversion_req;
520 i->set_mus_property ("pitch", inversion);
521 l = gh_cons (i->self_scm (), l);
522 scm_unprotect_object (i->self_scm ());
526 Should add (base . #t) to the pitch that is an added base
530 Bass_req* b = new Bass_req;
531 b->set_mus_property ("pitch", bass);
533 l = gh_cons (b->self_scm (), l);
534 scm_unprotect_object (b->self_scm ());
537 SCM pitches = Chord::to_pitches (chord);
538 for (SCM i = pitches; gh_pair_p (i); i = gh_cdr (i))
540 Note_req* n = new Note_req;
541 n->set_mus_property ("pitch", gh_car (i));
542 n->set_mus_property ("duration", dur);
543 l = gh_cons (n->self_scm (), l);
545 scm_unprotect_object (n->self_scm ());
548 Simultaneous_music*v = new Request_chord (l);