2 chord.cc -- implement Chord
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2001 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_remove_member (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
);
51 ly_snoc (SCM s
, SCM list
)
53 return gh_append2 (list
, gh_list (s
, SCM_UNDEFINED
));
57 /* Split list at member s, removing s.
58 Return (BEFORE . AFTER) */
60 ly_split_list (SCM s
, SCM list
)
64 for (; gh_pair_p (after
);)
66 SCM i
= gh_car (after
);
67 after
= gh_cdr (after
);
68 if (gh_equal_p (i
, s
))
70 before
= gh_cons (i
, before
);
72 return gh_cons (gh_reverse (before
), after
);
81 Chord::base_pitches (SCM tonic
)
85 SCM major
= Pitch (0, 2, 0).smobbed_copy ();
86 SCM minor
= Pitch (0, 2, -1).smobbed_copy ();
88 base
= gh_cons (tonic
, base
);
89 base
= gh_cons (Pitch::transpose (gh_car (base
), major
), base
);
90 base
= gh_cons (Pitch::transpose (gh_car (base
), minor
), base
);
92 return gh_reverse (base
);
96 Chord::transpose_pitches (SCM tonic
, SCM pitches
)
99 hoe doe je lambda in C?
101 SCM transposed
= SCM_EOL
;
102 for (SCM i
= pitches
; gh_pair_p (i
); i
= gh_cdr (i
))
104 transposed
= gh_cons (Pitch::transpose (tonic
, gh_car (i
)),
107 return gh_reverse (transposed
);
111 burp, in SCM duw je gewoon een (if (= (step x) 7) (...)) door pitches
114 If step == 0, lower all.
117 Chord::lower_step (SCM tonic
, SCM pitches
, SCM step
)
119 SCM lowered
= SCM_EOL
;
120 for (SCM i
= pitches
; gh_pair_p (i
); i
= gh_cdr (i
))
123 if (gh_equal_p (step_scm (tonic
, gh_car (i
)), step
)
124 || gh_scm2int (step
) == 0)
126 p
= Pitch::transpose (p
, Pitch (0, 0, -1).smobbed_copy ());
128 lowered
= gh_cons (p
, lowered
);
130 return gh_reverse (lowered
);
133 /* Return member that has same notename, disregarding octave or alterations */
135 Chord::member_notename (SCM p
, SCM pitches
)
137 /* If there's an exact match, make sure to return that */
138 SCM member
= gh_member (p
, pitches
);
139 if (member
== SCM_BOOL_F
)
141 for (SCM i
= pitches
; gh_pair_p (i
); i
= gh_cdr (i
))
144 Urg, eindelijk gevonden: () != #f, kan maar niet aan wennen.
145 Anders kon iets korter...
147 if (unsmob_pitch (p
)->notename_i_
148 == unsmob_pitch (gh_car (i
))->notename_i_
)
156 member
= gh_car (member
);
160 /* Return member that has same notename and alteration, disregarding octave */
162 Chord::member_pitch (SCM p
, SCM pitches
)
164 /* If there's an exact match, make sure to return that */
165 SCM member
= gh_member (p
, pitches
);
166 if (member
== SCM_BOOL_F
)
168 for (SCM i
= pitches
; gh_pair_p (i
); i
= gh_cdr (i
))
170 if (unsmob_pitch (p
)->notename_i_
171 == unsmob_pitch (gh_car (i
))->notename_i_
172 && unsmob_pitch (p
)->alteration_i_
173 == unsmob_pitch (gh_car (i
))->alteration_i_
)
181 member
= gh_car (member
);
186 Chord::step_scm (SCM tonic
, SCM p
)
188 /* De Pitch intervaas is nog beetje sleutelgat? */
189 int i
= unsmob_pitch (p
)->notename_i_
190 - unsmob_pitch (tonic
)->notename_i_
191 + (unsmob_pitch (p
)->octave_i_
192 - unsmob_pitch (tonic
)->octave_i_
) * 7;
196 return gh_int2scm (i
);
200 Assuming that PITCHES is a chord, with tonic (CAR PITCHES), find
201 missing thirds, only considering notenames. Eg, for
211 Chord::missing_thirds (SCM pitches
)
213 SCM thirds
= SCM_EOL
;
215 /* is the third c-e, d-f, etc. small or large? */
216 int minormajor_a
[] = {0, -1, -1, 0, 0, -1, -1};
217 for (int i
=0; i
< 7; i
++)
218 thirds
= gh_cons (Pitch (0, 2, minormajor_a
[i
]).smobbed_copy (),
220 thirds
= scm_vector (gh_reverse (thirds
));
222 SCM tonic
= gh_car (pitches
);
224 SCM missing
= SCM_EOL
;
226 for (SCM i
= pitches
; gh_pair_p (i
);)
229 int step
= gh_scm2int (step_scm (tonic
, p
));
231 if (unsmob_pitch (last
)->notename_i_
== unsmob_pitch (p
)->notename_i_
)
233 int third
= (unsmob_pitch (last
)->notename_i_
234 - unsmob_pitch (tonic
)-> notename_i_
+ 7) % 7;
235 last
= Pitch::transpose (last
, scm_vector_ref (thirds
, gh_int2scm (third
)));
238 if (step
> gh_scm2int (step_scm (tonic
, last
)))
240 while (step
> gh_scm2int (step_scm (tonic
, last
)))
242 missing
= gh_cons (last
, missing
);
243 int third
= (unsmob_pitch (last
)->notename_i_
244 - unsmob_pitch (tonic
)->notename_i_
+ 7) % 7;
245 last
= Pitch::transpose (last
, scm_vector_ref (thirds
,
246 gh_int2scm (third
)));
255 return lower_step (tonic
, missing
, gh_int2scm (7));
258 /* Return PITCHES with PITCH added not as lowest note */
260 Chord::add_above_tonic (SCM pitch
, SCM pitches
)
262 /* Should we maybe first make sure that PITCH is below tonic? */
263 if (pitches
!= SCM_EOL
)
264 while (Pitch::less_p (pitch
, gh_car (pitches
)) == SCM_BOOL_T
)
265 pitch
= Pitch::transpose (pitch
, Pitch (1, 0, 0).smobbed_copy ());
267 pitches
= gh_cons (pitch
, pitches
);
268 return scm_sort_list (pitches
, Pitch::less_p_proc
);
271 /* Return PITCHES with PITCH added as lowest note */
273 Chord::add_below_tonic (SCM pitch
, SCM pitches
)
275 if (pitches
!= SCM_EOL
)
276 while (Pitch::less_p (gh_car (pitches
), pitch
) == SCM_BOOL_T
)
277 pitch
= Pitch::transpose (pitch
, Pitch (-1, 0, 0).smobbed_copy ());
278 return gh_cons (pitch
, pitches
);
286 Construct from parser output:
288 PITCHES is the plain chord, it does not include bass or inversion
290 Part of Chord:: namespace for now, because we do lots of
291 chord-manipulating stuff.
294 Chord::tonic_add_sub_to_pitches (SCM tonic
, SCM add
, SCM sub
)
296 /* urg: catch dim modifier: 3rd, 5th, 7th, .. should be lowered */
298 for (SCM i
= add
; gh_pair_p (i
); i
= gh_cdr (i
))
300 Pitch
* p
= unsmob_pitch (gh_car (i
));
301 if (p
->octave_i () == -100)
307 add
= transpose_pitches (tonic
, add
);
308 add
= lower_step (tonic
, add
, gh_int2scm (7));
309 add
= scm_sort_list (add
, Pitch::less_p_proc
);
310 add
= ly_unique (add
);
312 sub
= transpose_pitches (tonic
, sub
);
313 sub
= lower_step (tonic
, sub
, gh_int2scm (7));
314 sub
= scm_sort_list (sub
, Pitch::less_p_proc
);
316 /* default chord includes upto 5: <1, 3, 5> */
317 add
= gh_cons (tonic
, add
);
320 SCM fifth
= ly_last (base_pitches (tonic
));
321 int highest_step
= gh_scm2int (step_scm (tonic
, ly_last (tmp
)));
322 if (highest_step
< 5)
323 tmp
= ly_snoc (fifth
, tmp
);
325 add
= lower_step (tonic
, add
, gh_int2scm (5));
327 /* find missing thirds */
328 SCM missing
= missing_thirds (tmp
);
329 if (highest_step
< 5)
330 missing
= ly_snoc (fifth
, missing
);
332 /* if dim modifier is given: lower all missing */
334 missing
= lower_step (tonic
, missing
, gh_int2scm (0));
336 /* if additions include any 3, don't add third */
337 SCM third
= gh_cadr (base_pitches (tonic
));
338 if (member_notename (third
, add
) != SCM_BOOL_F
)
339 missing
= scm_delete (third
, missing
);
341 /* if additions include any 4, assume sus4 and don't add third implicitely
342 C-sus (4) = c f g (1 4 5) */
343 SCM sus
= Pitch::transpose (tonic
, Pitch (0, 3, 0).smobbed_copy ());
344 if (member_notename (sus
, add
) != SCM_BOOL_F
)
345 missing
= scm_delete (third
, missing
);
347 /* if additions include some 5, don't add fifth */
348 if (member_notename (fifth
, add
) != SCM_BOOL_F
)
349 missing
= scm_delete (fifth
, missing
);
351 /* complete the list of thirds to be added */
352 add
= gh_append2 (missing
, add
);
353 add
= scm_sort_list (add
, Pitch::less_p_proc
);
355 SCM pitches
= SCM_EOL
;
356 /* Add all that aren't subtracted */
357 for (SCM i
= add
; gh_pair_p (i
); i
= gh_cdr (i
))
360 SCM s
= member_notename (p
, sub
);
362 sub
= scm_delete (s
, sub
);
364 pitches
= gh_cons (p
, pitches
);
366 pitches
= scm_sort_list (pitches
, Pitch::less_p_proc
);
368 for (SCM i
= sub
; gh_pair_p (i
); i
= gh_cdr (i
))
369 warning (_f ("invalid subtraction: not part of chord: %s",
370 unsmob_pitch (gh_car (i
))->str ()));
376 /* --Het lijkt me dat dit in het paarse gedeelte moet. */
378 Chord::get_chord (SCM tonic
, SCM add
, SCM sub
, SCM inversion
, SCM bass
, SCM dur
)
380 SCM pitches
= tonic_add_sub_to_pitches (tonic
, add
, sub
);
382 if (inversion
!= SCM_EOL
)
384 /* If inversion requested, check first if the note is part of chord */
385 SCM s
= member_pitch (inversion
, pitches
);
388 /* Then, delete and add as base note, ie: the inversion */
389 pitches
= scm_delete (s
, pitches
);
390 Note_req
* n
= new Note_req
;
391 n
->set_mus_property ("pitch", gh_car (add_below_tonic (s
, pitches
)));
392 n
->set_mus_property ("duration", dur
);
393 n
->set_mus_property ("inversion", SCM_BOOL_T
);
394 list
= gh_cons (n
->self_scm (), list
);
395 scm_unprotect_object (n
->self_scm ());
398 warning (_f ("invalid inversion pitch: not part of chord: %s",
399 unsmob_pitch (inversion
)->str ()));
402 /* Bass is easy, just add if requested */
405 Note_req
* n
= new Note_req
;
406 n
->set_mus_property ("pitch", gh_car (add_below_tonic (bass
, pitches
)));
407 n
->set_mus_property ("duration", dur
);
408 n
->set_mus_property ("bass", SCM_BOOL_T
);
409 list
= gh_cons (n
->self_scm (), list
);
410 scm_unprotect_object (n
->self_scm ());
413 for (SCM i
= pitches
; gh_pair_p (i
); i
= gh_cdr (i
))
415 Note_req
* n
= new Note_req
;
416 n
->set_mus_property ("pitch", gh_car (i
));
417 n
->set_mus_property ("duration", dur
);
418 list
= gh_cons (n
->self_scm (), list
);
419 scm_unprotect_object (n
->self_scm ());
422 Simultaneous_music
*v
= new Request_chord (SCM_EOL
);
423 v
->set_mus_property ("elements", list
);