lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Diatonic/modal transposition function (John Mandereau)


From: John Mandereau
Subject: Re: Diatonic/modal transposition function (John Mandereau)
Date: Mon, 29 Dec 2008 21:54:31 +0100

Le lundi 29 décembre 2008 à 10:16 +0100, Stefan Thomas a écrit :
> Dear John,
> I understood now. You have a note 0 in c major and in a minor, which
> is a c.

The most meaningful I think is that c major and a minor define the same
major scale in LilyPond, only the tonic (c or a, respectively) differ.


>  In my opinion it would be better to understand for a musician,
> if You could use the intervall-names.

You're right, and it could simply be done by defining

secondUp = #1
thirdUp = #2
...
seventhUp = #7

secondDown = #1
...
seventhDown = #-7

and using these variables with a backslash in \diatonicTranspose and
\modeTranspose.

However, your remarks also made me think about simplifying the syntax
for saving the typist the effort of computing the degree delta himself.
With the revised snippet below, the functions now take a start pitch and
a final pitch instead of a degree delta; that is, think about the syntax
of these functions of being the same as (chromatic) \transpose, except
you insert additional arguments to specify one (for \diatonicTranspose
or two (for \modeTranspose) modes.  See at the end of the code below for
examples; is this syntax more user-friendly?

#(define (true-quotient n d)
  "Return the true quotient in integer division of n by d, i.e.
return the integer q so that there is a unique integer r that
satisfies  n = qd + r  and  0 <= r < |d|"
  (if (>= n 0)
   (quotient n d)
   (- (quotient n d) 1)))

#(define (ly-pitch->modal-pitch ly-pitch scale tonic-c-diff)
  "Convert ly-pitch to a list (octave degree depresentation) which represents
the modal pitch in scale, with tonic-c-diff as the pitch diff from tonic to
middle C.  scale should be a notename->alteration alist of length 7 which
represents the alteration of each note with C as first pitch of the scale."
  (let* ((normalized-pitch (ly:pitch-transpose ly-pitch tonic-c-diff))
         (notename (ly:pitch-notename normalized-pitch)))
   (list
    (ly:pitch-octave normalized-pitch) ;; octave
    notename ;; degree
    ;; alteration
    (- (ly:pitch-alteration normalized-pitch) (ly:assoc-get notename scale 
0)))))

#(define (degree-transpose modal-pitch modal-pitch-delta scale-length)
"Transpose modal-pitch (octave degree alteration) by modal-pitch-delta assuming
scale-length."
  (let* ((octave (car modal-pitch))
         (degree (cadr modal-pitch))
         (alteration (caddr modal-pitch))
         (octave-delta (car modal-pitch-delta))
         (degree-delta (cadr modal-pitch-delta))
         (alteration-delta (caddr modal-pitch-delta))
         (relative-new-degree (+ degree degree-delta)))
   (list
    (+
     octave
     octave-delta
     (true-quotient relative-new-degree scale-length))
    (modulo relative-new-degree scale-length)
    (+ alteration alteration-delta))))

#(define (modal-pitch->ly-pitch modal-pitch scale c-tonic-diff)
  "Convert modal-pitch -- a list (octave degree alteration) -- to a
standard pitch using scale and pitch diff from middle C to tonic.
scale should be a notename->alteration alist of length 7 which represents
the alteration of each note with C as first pitch of the scale."
  (let* ((octave (car modal-pitch))
         (degree (min 6 (cadr modal-pitch)))
         (alteration (caddr modal-pitch))
         (abs-alteration (+ alteration (ly:assoc-get degree scale 0))))
   (ly:pitch-transpose
    (ly:make-pitch octave degree abs-alteration)
    c-tonic-diff)))

#(define (lookup-music-property event type)
  "Return the first music property of the given type found in event,
or #f is no such property is found.  event should be music or a list
of music."
  (if (null? event)
   #f
   (if (list? event)
    (or
     (lookup-music-property (car event) type)
     (lookup-music-property (cdr event) type))
    (let ((p (ly:music-property event 'pitch)))
     (if (not (null? p))
      p
      (let* ((e (ly:music-property event 'element))
             (es (ly:music-property event 'elements))
             (p2 (if (null? e)
                  '()
                  (lookup-music-property e type))))
       (if (not (null? p2))
        p2
        (lookup-music-property es type))))))))

#(define (mode-transpose
          pitch-note1 pitch-note2 tonic-note1 scale1 tonic-note2 scale2 music)
  (let* ((tonic-diff1 (ly:pitch-diff
                       (ly:make-pitch 0 0 0)
                       (lookup-music-property tonic-note1 'pitch)))
         (tonic-diff2 (ly:pitch-diff
                       (lookup-music-property tonic-note2 'pitch)
                       (ly:make-pitch 0 0 0)))
         (modal-pitch-delta (map
                             -
                             (ly-pitch->modal-pitch
                              (lookup-music-property pitch-note2 'pitch)
                              scale2
                              (ly:pitch-negate tonic-diff2))
                             (ly-pitch->modal-pitch
                              (lookup-music-property pitch-note1 'pitch)
                              scale1
                              tonic-diff1))))
   (music-map
    (lambda (event)
     (let ((p (ly:music-property event 'pitch)))
      (if (ly:pitch? p)
       (ly:music-set-property!
        event
        'pitch
        (modal-pitch->ly-pitch
         (degree-transpose
          (ly-pitch->modal-pitch p scale1 tonic-diff1)
          modal-pitch-delta
          7)
         scale2
         tonic-diff2)))
      event))
    music)))

modeTranspose =
#(define-music-function
  (parser location pitch-note1 pitch-note2 tonic-note1 scale1 tonic-note2 
scale2 music)
  (ly:music? ly:music? ly:music? list? ly:music? list? ly:music?)
  "Transpose music diatonicly by the interval between pitch-note1
and pitch-note2, interpreting pitches in scale1 on tonic-note1
and producing pitches in scale2 on tonic-note2."
  (mode-transpose
   pitch-note1 pitch-note2 tonic-note1 scale1 tonic-note2 scale2 music))

diatonicTranspose =
#(define-music-function
  (parser location pitch-note1 pitch-note2 tonic-note scale music)
  (ly:music? ly:music? ly:music? list? ly:music?)
  "Transpose music diatonicly by from pitch-note1 to pitch-note2
in scale on tonic-note."
  (mode-transpose
   pitch-note1 pitch-note2 tonic-note scale tonic-note scale music))

pattern = \relative c' { c2~ c8 d16 e f g a b c4 g e c }

\new Staff {
  \pattern
  \diatonicTranspose c d c \major \pattern % I -> II
  \diatonicTranspose c e c \major \pattern % I -> III
}

% mixing lydian and mixolydian modes
milydian = #`(
  (0 . 0)
  (1 . 0)
  (2 . 0)
  (3 . ,SHARP)
  (4 . 0)
  (5 . 0)
  (6 . ,FLAT))

melodie = \relative c' { \times 2/3 { cis8 d e } f2 }

\new Staff {
  \time 3/4
  \melodie
  \modeTranspose cis d g \milydian d \lydian \melodie
  \modeTranspose cis dis' g \milydian e \lydian \melodie
}

-- 
John Mandereau <address@hidden>





reply via email to

[Prev in Thread] Current Thread [Next in Thread]