Hi Kieren On 02-01-2016 16:22, Kieren MacMillan wrote:
1. How difficult would it be to add a function which produced a row in “traditional format”, i.e., \tonerow #”RI4” would give you [from your example] { a’ gs’ c’’ d’’ ds’’ fs’ f’ e’ cs’’ g’ b’ as' }Not difficult at all! Try the attached files. Open the 12tone-matrix.ly and write at the end of the file:
\writeRow #'RI #3 (don't forget the single quote in the first argument) You can do this in any file, just include this tree lines at the beginning: #(define row '(some row)) \include "12tone-calc.scm" \include"12tone-engravers.ily"Right now the second argument is mandatory. This means that if you don't want any transpositions you need to write #0 as the second argument of \writeRow.
2. Can your code be extended easily/quickly to support arbitrary pitch sets and row counts? For example, I used a 10-tone row drawn from [only] 8 distinct pitch classes in a recent piece, and would love to have tools available to help with similar efforts in the future.Well, that's exactly my intention! In theory it should be very easy to extend it this way. I have little time right now, but I'll keep the list updated in further implementations.
Cheers, Caio
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Pitch manipulations in Scheme % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Creating Transpositions and inversions % Transpositions #(define (transpose ls int mod) (map (lambda (x) (modulo (+ int x) mod)) ls)) % Set first pitch as "0" and maintain interval relations #(define (zero-pset ls mod) (transpose ls (* (car ls) -1) mod)) % Inversion #(define (invert ls mod) (map (lambda (x) (modulo x mod)) ; keep inside modulos (e.g. 12 for 12-tone rows) (map (lambda (y) (+ y (car ls))) ; sum the inverted intervals with the first pitch of the original pitch set (map (lambda (z) (* z -1)) (zero-pset ls mod))))) % invert zeroed pitch set signals % Apply the chosen operation in different ways depending on the number of arguments #(define (pset-op op pset . ls) (cond ((null? ls) (op pset)) ((null? (cdr ls)) (op pset (car ls))) (else (op pset (car ls) (cadr ls))))) % 12 tone specific operations (always inside modulos 12) #(define (12transpose pset n) (transpose pset n 12)) #(define (12invert pset) (invert pset 12)) #(define (12retrograde pset) (reverse pset)) #(define (12retinvert pset) (reverse (invert pset 12))) #(define (get-row pset type transp) (cond ((eqv? type 'O) (pset-op 12transpose pset transp)) ((eqv? type 'R) (12retrograde (pset-op 12transpose pset transp))) ((eqv? type 'I) (12invert (pset-op 12transpose pset transp))) ((eqv? type 'RI) (12retinvert (pset-op 12transpose pset transp))) (else (error "Wrong type of operation. Should be O, R, I or RI")))) % Transpose the original 12 tone row according to the intervals of the inverted form #(define (squareTranspose 12set n) (list-ref (invert (zero-pset 12set 12) 12) n)) %%%%%%%%% Some further pitch manipulations (no used yet) % List all transpositions #(define (all-transpositions pset mod) (let loop ((x pset) (y '())) (if (null? x) (reverse y) (loop (cdr x) (cons (transpose (zero-pset pset) (car x) mod) y))))) % list all transpositions in ascending order #(define (all-transpositions-order pset mod) (let loop ((x pset) (y '()) (z 0)) (if (null? x) (reverse y) (loop (cdr x) (cons (transpose pset z mod) y) (+ z 1))))) % list all inversions #(define (all-inversions pset mod) (let loop ((x (all-transpositions pset mod)) (y '())) (if (null? x) (reverse y) (loop (cdr x) (cons (invert (car x) mod) y))))) % List all inversions in ascending order #(define (all-inversions-order pset mod) (let loop ((x (all-transpositions-order pset mod)) (y '())) (if (null? x) (reverse y) (loop (cdr x) (cons (row-invert (car x) mod) y)))))
\version "2.18.2" % "square" transpositions linked to the defined row #(define (squareNumber n) (squareTranspose row n)) % List the rows that will be written #(define (squareRows n) (pset-op 12transpose row (squareTranspose row n))) % Convert the numbers in the row to Lilypond pitches #(define (number->note n) (cond ((= n 0) (ly:make-pitch 1 0)) ((= n 1) (ly:make-pitch 1 0 1/2)) ((= n 2) (ly:make-pitch 1 1)) ((= n 3) (ly:make-pitch 1 1 1/2)) ((= n 4) (ly:make-pitch 0 2)) ((= n 5) (ly:make-pitch 0 3)) ((= n 6) (ly:make-pitch 0 3 1/2)) ((= n 7) (ly:make-pitch 0 4)) ((= n 8) (ly:make-pitch 0 4 1/2)) ((= n 9) (ly:make-pitch 0 5)) ((= n 10) (ly:make-pitch 0 5 1/2)) ((= n 11) (ly:make-pitch 0 6)) (else (error "Pitch not found")))) % Write elements (markups or note) writeElements = #(define-music-function (parser location sym1 sym2 fn1 ls) (symbol? symbol? procedure? list?) (make-music 'SequentialMusic 'elements (let loop ((ls ls)) (if (null? ls) '() (cons (make-music sym1 ;'LyricEvent / 'NoteEvent sym2 ; 'text / 'pitch (fn1 (car ls)) ; (markup #:concat (#:larger "RI" #:sub (number->string (car ls)))) / (number->note (car ls)) 'duration (ly:make-duration 2)) (loop (cdr ls))))))) % customBarLine by Janek Warchoł % http://stackoverflow.com/questions/18538793/lilypond-markup-text-next-to-barline % changed to write the Retrograde inversion customBarLine = #(define-music-function (parser location n) (number?) #{ \once \override Staff.BarLine #'stencil = #(lambda (grob) (ly:stencil-combine-at-edge (ly:bar-line::print grob) X RIGHT (grob-interpret-markup grob #{ \markup { \whiteout \vcenter \concat { \larger "R" \sub #(number->string (squareNumber n))} } #}) 0))#}) % Write a new Staff with the transposition number: %% - As an instrument name on the left %% - As a custom bar line on the right writeRowStaff = #(define-music-function (parser location n) (number?) #{ \new Staff \with { instrumentName = \markup { \concat { \larger O \sub #(number->string (squareNumber n)) } } } { \writeElements #'NoteEvent #'pitch #(lambda (x) (number->note x)) #(squareRows n) \stopStaff \bar "|" s4 \customBarLine #n } #}) % Write markups with a large string and a subtexted number writeRowMarkups = #(define-music-function (parser location str ls) (string? list?) #{ \writeElements #'LyricEvent #'text #(lambda (x) (markup #:concat (#:larger str #:sub (number->string x)))) #ls #}) % Use writeRowMarkups to write the inversion transpositions markupI = #(define-music-function (parser location) () #{ \writeRowMarkups #"I" #(zero-pset row 12) #}) % Use writeRowMarkups to write the retrograde-inversion transpositions markupRI = #(define-music-function (parser location) () #{ \writeRowMarkups #"RI" #(zero-pset row 12) #}) % Recursive function to write the 12 rows with all the transpositions writeRowRec = #(define-music-function (parser location n) (number?) (if (= 12 n) #{ #} #{ << \writeRowStaff #n \writeRowRec #(+ n 1) >> #})) writeSquare = \writeRowRec #0 % get individual row writeRow = #(define-music-function (parser location type trans) (symbol? number?) #{ \writeElements #'NoteEvent #'pitch #(lambda (x) (number->note x)) #(get-row row type trans) #})
\version "2.18.2" #(set-global-staff-size 16) % the row should be written as a list of numbers (0 = c, 1 = c-sharp, etc.) #(define row '(6 5 9 3 0 11 10 1 2 4 8 7)) \include "12tone-calc.scm" \include "12tone-engravers.ily" \layout { \context { \Score \override TimeSignature.stencil = ##f \override Stem.stencil = ##f \override BarLine.layer = 1 } \accidentalStyle dodecaphonic } \paper { left-margin = 3\cm right-margin = 2\cm indent = 1.5\cm line-width = 16\cm tagline = "" ragged-last = ##f } \score { \new StaffGroup << \time 1/4 \set Timing.defaultBarType = "!" \set StaffGroup.systemStartDelimiter = #'SystemStartBar %Write indications of Inversions \new Lyrics { \markupI } %Write all Rows plus indications of transpositions \writeSquare %Write indications of Retrogrades of Inversions \new Lyrics { \markupRI } >> }
_______________________________________________ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user