lilypond-devel
[Top][All Lists]
Advanced

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

Re: Transposing in modes??


From: Nicolas Sceaux
Subject: Re: Transposing in modes??
Date: Fri, 17 Feb 2006 14:48:49 +0100
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (darwin)

Johannes Schindelin <address@hidden> writes:

> I always wanted to learn how to transform music with scheme, so I 
> implemented half of it. If some of you experts could look at it and tell 
> me what could be done more elegantly (Scheme is not my native language), 
> and especially what needs to be done to make this easy to use, that would 
> be super!

Here's how I'd do it, using a Common Lisp-like loop macro by Heinrich
Taube <http://nicolas.sceaux.free.fr/loop-guile.scm>. Using vectors is
not a bad thing. Neither is iterating (vs. recursing), IMHO loop is
eleguant and clearer. (hardly tested)

nicolas

#(begin
(load-from-path "loop-guile.scm")

(define (scale-semitones scale)
  "Get a vector of semitones for a given scale"
  (let ((semitones '(("ionian"     . #(0 2 4 5 7 9 11))
                     ("dorian"     . #(0 2 3 5 7 9 10))
                     ("phrygian"   . #(0 1 3 5 7 8 10))
                     ("lydian"     . #(0 2 4 6 7 9 11))
                     ("mixolydian" . #(0 2 4 5 7 9 10))
                     ("aeolian"    . #(0 2 3 5 7 8 10))
                     ("locrian"    . #(0 1 3 5 6 8 10)))))
    (let ((result (assoc scale semitones)))
      (if result
          (cdr result)
          (error "scale unknown: " scale)))))

(define (transpositions key-pitch source-scale target-scale)
  "Return the tranposition vector for transposing from source-scale
to target-scale. key-pitch is supposed to be a ly:pitch."
  (loop for source across (scale-semitones source-scale)
        for target across (scale-semitones target-scale)
        with transp-vector = (make-vector 12 #f)
        with key-offset = (ly:pitch-semitones key-pitch)
        do (vector-set! transp-vector
                        (modulo (+ key-offset source) 12)
                        (ly:make-pitch 0 0 (case (- target source)
                                             ((1) SHARP)
                                             ((-1) FLAT)
                                             (else 0))))
        finally (return transp-vector)))

(define (alter-mode-pitch music transposition-vector)
  (let ((pitch (ly:music-property music 'pitch)))
    (if (ly:pitch? pitch)
        (let ((transpo (vector-ref transposition-vector
                                   (modulo (ly:pitch-semitones pitch) 12))))
          (cond ((not transpo)
                 (display "Warning: Mode mismatch")
                 (display-music pitch))
                (else
                 (set! (ly:music-property music 'pitch)
                       (ly:pitch-transpose pitch transpo)))))))
  music)

(define (chord->pitch chord)
  "Find a pitch in a ChordEvent"
  (loop for event in (ly:music-property chord 'elements)
        if (eqv? (ly:music-property event 'name) 'NoteEvent)
        return (ly:music-property event 'pitch))))

alterMode =
#(def-music-function (parser location scales key music) (list? ly:music? 
ly:music?)
  "Transpose between types of scales"
  (let ((transposition-vector (apply transpositions (chord->pitch key) 
                                     (map-in-order symbol->string scales))))
    (music-map (lambda (m)
                 (alter-mode-pitch m transposition-vector))
               music)))

normalScale = \relative c' { c4 d e f g a b c }

{
 \normalScale \break
 \alterMode #'(ionian phrygian) c \normalScale
}

reply via email to

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