[Top][All Lists]
[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
}