Werner LEMBERG <[EMAIL PROTECTED]> writes: >> Your post just reminded me that I've written a version of \parallelMusic >> with relative mode after a request by Werner (and I forgot about it >> during holidays). > > Aaah! Is this mature enough that you can send it to the list? > > Werner
Here is a patch introducing a \parallelRelativeMusic function, but I'm not sure if it is really convenient. At each new bar, you have to specify the absolute octave of the first note: \version "2.9.5" \parallelMusic #'(A B) { c'4 d' e' c' | c4 g, c2 | c'4 d' e' c' | c4 g, c2 | } %% <==> \parallelRelativeMusic #'(C D) { c'4 d e c | c4 g c2 | c'4 d e c | c4 g c2 | } << \new Staff { \A \C } \new Staff { \clef bass \B \D } >> May you try it and see whether it fits your needs? nicolas
Index: ly/music-functions-init.ly =================================================================== RCS file: /cvsroot/lilypond/lilypond/ly/music-functions-init.ly,v retrieving revision 1.57 diff -u -r1.57 music-functions-init.ly --- ly/music-functions-init.ly 6 May 2006 00:21:04 -0000 1.57 +++ ly/music-functions-init.ly 13 May 2006 11:59:04 -0000 @@ -319,42 +319,48 @@ (list chain-grob-member-functions `(,cons 0 0)) (check-slope-callbacks comp)))))) - -parallelMusic = -#(define-music-function (parser location voice-ids music) (list? ly:music?) - "Define parallel music sequences, separated by '|' (bar check signs), -and assign them to the identifiers provided in @var{voice-ids}. - [EMAIL PROTECTED]: a list of music identifiers (symbols containing only letters) - [EMAIL PROTECTED]: a music sequence, containing BarChecks as limiting expressions. - -Example: - \\parallelMusic #'(A B C) { - c c | d d | e e | - d d | e e | f f | - } -<==> - A = { c c | d d | } - B = { d d | e e | } - C = { e e | f f | } -" - (let* ((voices (apply circular-list (make-list (length voice-ids) (list)))) - (current-voices voices) - (current-sequence (list))) +%% Parallel music utilities +#(use-modules (ice-9 optargs)) % for lambda* +#(define (relativize-music! music root-pitch) + (music-map + (let ((previous-pitch root-pitch)) + (lambda (m) + (if (eq? (ly:music-property m 'name) 'NoteEvent) + (begin + (if (ly:pitch? previous-pitch) + ;; set octave relative to the previous note + (let* ((entered-pitch (ly:music-property m 'pitch)) + (pitch-note (ly:pitch-notename entered-pitch)) + (prev-pitch-note (ly:pitch-notename previous-pitch))) + (set! (ly:music-property m 'pitch) + (ly:make-pitch (+ (ly:pitch-octave previous-pitch) + (1+ (ly:pitch-octave entered-pitch)) + (cond ((>= (- pitch-note prev-pitch-note) 4) -1) + ((<= (- pitch-note prev-pitch-note) -4) +1) + (else 0))) + pitch-note + (ly:pitch-alteration entered-pitch))))) + (set! previous-pitch (ly:music-property m 'pitch)))) + m)) + music)) + +#(define (parallel-music parser location sequence-ids music relative?) + (let* ((sequences (apply circular-list (make-list (length sequence-ids) (list)))) + (current-sequences sequences) + (current-sequence (list))) ;; ;; utilities (define (push-music m) "Push the music expression into the current sequence" (set! current-sequence (cons m current-sequence))) - (define (change-voice) - "Stores the previously built sequence into the current voice and - change to the following voice." - (list-set! current-voices 0 (cons (make-music 'SequentialMusic + (define (change-sequence) + "Stores the previously built sequence into the current sequence and + change to the following sequence." + (list-set! current-sequences 0 (cons (make-music 'SequentialMusic 'elements (reverse! current-sequence)) - (car current-voices))) + (car current-sequences))) (set! current-sequence (list)) - (set! current-voices (cdr current-voices))) + (set! current-sequences (cdr current-sequences))) (define (bar-check? m) "Checks whether m is a bar check." (eq? (ly:music-property m 'name) 'BarCheck)) @@ -368,48 +374,91 @@ (ly:music-property music 'elements))))) (and (not (null? origins)) (car origins))))))) ;; - ;; first, split the music and fill in voices + ;; first, split the music and fill in the sequences (map-in-order (lambda (m) (push-music m) - (if (bar-check? m) (change-voice))) + (if (bar-check? m) (change-sequence))) (ly:music-property music 'elements)) - (if (not (null? current-sequence)) (change-voice)) - ;; un-circularize `voices' and reorder the voices - (set! voices (map-in-order (lambda (dummy seqs) + (if (not (null? current-sequence)) (change-sequence)) + ;; un-circularize `sequences' and reorder the seqs + (set! sequences (map-in-order (lambda (dummy seqs) (reverse! seqs)) - voice-ids voices)) + sequence-ids sequences)) ;; - ;; set origin location of each sequence in each voice + ;; If in relative mode, set octaves accordingly + (if relative? + (for-each (lambda (seqs) + (for-each (lambda (seq) + (relativize-music! seq #f)) + seqs)) + sequences)) + ;; + ;; set origin location of each sequence ;; for better type error tracking - (for-each (lambda (voice) + (for-each (lambda (sequence) (for-each (lambda (seq) (set! (ly:music-property seq 'origin) (or (music-origin seq) location))) - voice)) - voices) + sequence)) + sequences) ;; ;; check sequence length - (apply for-each (lambda (. seqs) + (apply for-each (lambda* (#:rest seqs) (let ((moment-reference (ly:music-length (car seqs)))) (for-each (lambda (seq moment) (if (not (equal? moment moment-reference)) (ly:music-message seq "Bars in parallel music don't have the same length"))) seqs (map-in-order ly:music-length seqs)))) - voices) + sequences) ;; - ;; bind voice identifiers to the voices - (map (lambda (voice-id voice) - (ly:parser-define! parser voice-id + ;; bind sequence identifiers to the sequences + (map (lambda (sequence-id sequence) + (ly:parser-define! parser sequence-id (make-music 'SequentialMusic 'origin location - 'elements voice))) - voice-ids voices)) + 'elements sequence))) + sequence-ids sequences)) ;; Return an empty sequence. this function is actually a "void" function. (make-music 'SequentialMusic 'void #t)) +parallelMusic = +#(define-music-function (parser location sequence-ids music) (list? ly:music?) + "Define parallel music sequences, separated by '|' (bar check signs), +and assign them to the identifiers provided in @var{sequence-ids}. + [EMAIL PROTECTED]: a list of music identifiers (symbols containing only letters) [EMAIL PROTECTED]: a music sequence, containing BarChecks as limiting expressions. +Example: + \\parallelMusic #'(A B C) { + c c | d d | e e | + d d | e e | f f | + } +<==> + A = { c c | d d | } + B = { d d | e e | } + C = { e e | f f | } +" + (parallel-music parser location sequence-ids music #f)) + +parallelRelativeMusic = +#(define-music-function (parser location sequence-ids music) (list? ly:music?) + "Same as \parallelMusic, but in relative mode: in each block, the first +note is entered in absolute pitch, the following ones in relative mode. + +Example: + \\parallelRelativeMusic #'(A B C) { + c'' c | d' d | e e | + d'' d | e' e | f f | + } +<==> + A = { c'' c'' | d'' d'' | } + B = { d' d' | e' e' | } + C = { e e | f f | } +" + (parallel-music parser location sequence-ids music #t)) %% this is a stub. Write your own to suit the spacing tweak output. spacingTweaks =
_______________________________________________ lilypond-devel mailing list lilypond-devel@gnu.org http://lists.gnu.org/mailman/listinfo/lilypond-devel