Hi, About enharmonicity:
2011/6/20 Benkő Pál <benko....@gmail.com>: > > with an algebraic pitch representation the test and adjustment would > look like as follows: > two pitches are enharmonic iff their interval is in the subspace spanned > by the enharmonic interval (default: diminished second) and the scale > period (default: pure octave). to make it a bit more difficult, the > scale period coefficient must be integer, while the enharmonic interval > coefficient may be rational. the scale period coefficient also gives the > necessary adjustment. > Enharmonicity is just an equivalence relation respecting the abelian group structure of intervals/transpositions. You can represent it by a quotient map or by its kernel. Your approach is representing the kernel, via its generators. This is complicated. A much simpler idea is to represent the quotient map, which is a particularly simple kind of function. I am attaching a modified version of your code which expresses the idea. I believe that the code can get even cleaner, but I am leaving that work to you (or someone else), since I have a very low fluency in Lisp. Explaining the code: {enharmonic-class} corresponds to the quotient map. {et12-class} and {et31-class} are examples. The important thing is that these procedures return the same value for enharmonic equivalent pitches modulo octave. {enharmonic-octaves} is used in the octave adjustment. It is supposed to receive a pitch which is enharmonic to an integer number of octaves, and return that number. Note how {enharmonic} became trivial. This means that {enharmonic-from} reduces to a dictionary look-up. I leave to someone else to reimplement this in the best possible way. Hope it helps. If you have any questions, please ask. Regards, Felipe
\version "2.15.3" #(define (extract-pitch-sequence music) "Recurse through @var{music}, extracting pitches. Returns a list of pitch objects, e.g @code{'((ly:make-pitch 0 2 0) (ly:make-pitch 0 4 0) ... )} Typically used to construct a scale for input to transposer-factory (see). " (let ((elements (ly:music-property music 'elements)) (element (ly:music-property music 'element)) (pitch (ly:music-property music 'pitch))) (cond ((ly:pitch? pitch) pitch) ((pair? elements) (map (lambda (x) (extract-pitch-sequence x)) elements)) ((ly:music? element) (extract-pitch-sequence element))))) #(define (enharmonic pitch0 pitch1 enharmonic-class) "Whether two pitches are enharmonic." (equal? (enharmonic-class pitch0) (enharmonic-class pitch1))) %TODO: implement this with a dictionary. #(define (enharmonic-from scale pitch enharmonic-class enharmonic-octaves) "The first enharmonic equivalent of pitch from scale." (if (pair? scale) (let ((pitch1 (caar scale))) (if (enharmonic pitch pitch1 enharmonic-class) ; adjust octave of pitch1 (ly:pitch-transpose pitch1 (ly:make-pitch (enharmonic-octaves (ly:pitch-diff pitch pitch1)) 0 0)) (enharmonic-from (cdr scale) pitch enharmonic-class enharmonic-octaves))) pitch)) #(define (enharmonize-pitch pitch scale enharmonic-class enharmonic-octaves) (let ((p (ly:music-property pitch 'pitch))) (if (ly:pitch? p) (ly:music-set-property! pitch 'pitch (enharmonic-from scale p enharmonic-class enharmonic-octaves))) pitch)) #(define (enharmonize scale music enharmonic-class enharmonic-octaves) "Replaces pitches in music by their enharmonic counterpart in scale." (let ((s (extract-pitch-sequence scale))) (music-map (lambda (x) (enharmonize-pitch x s enharmonic-class enharmonic-octaves)) music))) enharmonizeMusic = #(define-music-function (parser location scale music enharmonic-class enharmonic-octaves) (ly:music? ly:music? procedure? procedure?) (_i "Replace pitches in @var{music} by their enharmonic counterpart in @var{scale}.") (enharmonize scale music enharmonic-class enharmonic-octaves)) #(define (frac x) (- x (floor x))) #(define (alg-alteration pitch) "Second coefficient of an algebraic pitch representation modulo octave," " the first one being (ly:pitch-notename pitch)" (+ (ly:pitch-alteration pitch) (if (> (ly:pitch-notename pitch) 2) -1/2 0))) #(define (et12-value pitch) "Auxiliary." (* 1/6 (+ (ly:pitch-notename pitch) (alg-alteration pitch)))) #(define (et12-class pitch) "pitch modulo octave in ET12, represented as a fraction of the octave" (frac (et12-value pitch))) #(define (et12-octaves pitch) "If pitch is equivalent to an integer number of octaves in ET12," " returns that value. Otherwise, return value is unspecified." (+ (ly:pitch-octave pitch) (et12-value pitch))) #(define (et31-value pitch) "Auxiliary." (+ (* 5/31 (ly:pitch-notename pitch)) (* 4/31 (alg-alteration pitch)))) #(define (et31-class pitch) "pitch modulo octave in ET31, represented as a fraction of the octave" (frac (et31-value pitch))) #(define (et31-octaves pitch) "If pitch is equivalent to an integer number of octaves in ET31," " returns that value. Otherwise, return value is unspecified." (+ (ly:pitch-octave pitch) (et31-value pitch))) esMinor = { es f ges as bes ces des } mus = { dis' feses' c'' aisis' } mu = { bisis' feses' } { \key es \minor \mus \enharmonizeMusic \esMinor \mus #et12-class #et12-octaves \enharmonizeMusic \esMinor \transpose es es' \mus #et12-class #et12-octaves \enharmonizeMusic \esMinor \transpose es' es \mus #et12-class #et12-octaves % example for 31-step equal temperament \mu \enharmonizeMusic { deses cis des cisis eses dis es disis } \mu #et31-class #et31-octaves }
_______________________________________________ lilypond-devel mailing list lilypond-devel@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-devel