Ancient Voices of Code / PROG Rock / Program Music
(require (submod "lisp15.rkt" LISP15)) (define (do-file in out) (call-with-input-file in (λ (in) (call-with-output-file out #:exists 'replace (λ (out) (lily (musicalize-file in pentatonic-pitcher) out #t)))))) (do-file "lispset" "musicalized-lispset.ly") (do-file "reduce" "musicalized-reduce.ly")
1 Data structures for music
(module Music racket (provide <provisions/music>) (require) <music>)
As the input is musicalized, the result is built up as a tree structure. The simplest kinds of nodes are notes and rests.
I have based the representation of notes on Lilypond, to make output easier.
A note is a combination of pitches (single notes are chords with one pitch), their duration, and any “post-events” (this is Lilypond terminology), which are usually articulations and dynamics. Elements of post-events are symbols, such as ’staccato (Lilypond -.) or ’mf (Lilypond \mf). We will discuss pitches later.
The duration of a note is conveyed by a “log” and a number of dots (usually 0). The log corresponds to typical note value terminology, so that 16 means a sixteenth note, 2 a half note. Whole notes have a log of 1, and longer durations can be had by setting log to 1/2, etc. The dots function as augmentation dots do in conventional notation: a dots of 1 adds half of the duration according to the log; a dots of 2 adds half of the duration, plus half of that half, for 1.75 the duration according to the log; a dots of 3 effectively multiplies the duration by 1.875, and so on.
Rests are notes that don’t have pitches.
(struct-out Note)
In a music tree, a sequence of notes is a list of Note or Rest objects. Nested lists will be flattened in the output.
Durations other than those based on powers of two have to be expressed using tuplets.
(struct Tuplet (ratio music))
Music should be divided into measures. There need not be a meter; use 0 for the numerator and denominator in that case.
(struct Measure (numerator denominator music label))
We support two voices.
(struct Polyphony (voice-1 voice-2))
(struct-out Tuplet) (struct-out Polyphony) (struct-out Measure)
We will often need to traverse music.
(define (map-notes f music) (match music [(list ms ...) (flatten (map (λ (m) (map-notes f m)) ms))] [(Note _ _ _ _) (f music)] [(Tuplet ratio inner) (Tuplet ratio (map-notes f inner))] [(Polyphony voice-1 voice-2) (Polyphony (map-notes f voice-1) (map-notes f voice-2))])) (define (extract-notes music) (match music [(list ms ...) (flatten (map extract-notes ms))] [(Note _ _ _ _) (list music)] [(Tuplet _ m) (extract-notes m)] [(Polyphony voice-1 voice-2) (append (extract-notes voice-1) (extract-notes voice-2))]))
map-notes
(define (add-post-event! note event) (set-Note-post-events! note (cons event (Note-post-events note)))) (define (add-pitch! note pitch) (set-Note-pitches! note (cons pitch (Note-pitches note))))
add-post-event! add-pitch!
1.1 Pitches
Pitches are combinations of integers and an alteration. The integer represents the basic pitch, with 0 meaning C0 (c,,, in Lilypond). For fun, we use a base-31 system, so that some enharmonic pitches are available. To add an octave, add 31.
The alteration is supposed to be used for microtonal stuff.
(struct Pitch (number alteration)) (define pitch-classes '(c deses cis des cisis d eeses dis es disis e fes eis f eisis fis ges fisis g aeses gis aes gisis a beses ais bes aisis b ces bis)) (define pitch-vector (apply vector pitch-classes)) (define pitch-hash (make-hash (let loop ([ps pitch-classes] [i 0]) (if (null? ps) '() (cons (cons (first ps) i) (loop (rest ps) (+ i 1))))))) (define (pitch-class->integer pitch-class) (hash-ref pitch-hash pitch-class)) (define (integer->pitch-class integer) (vector-ref pitch-vector integer)) (define (pitch-class-of pitch) (vector-ref pitch-vector (modulo (Pitch-number pitch) 31))) (define (octave-of pitch) (quotient (Pitch-number pitch) 31)) (define (make-pitch pitch-class octave [alteration 0]) (Pitch (+ (hash-ref pitch-hash pitch-class) (* 31 octave)) alteration))
(struct-out Pitch) pitch-class->integer integer->pitch-class pitch-class-of octave-of make-pitch
The major advantage of integers over a symbolic representation is that operations on pitches are easier.
(define (add-interval pitch 31tones) (Pitch (+ (Pitch-number pitch) 31tones) (Pitch-alteration pitch)))
(define (pitch< p1 p2) (match* (p1 p2) [((Pitch n1 _) (Pitch n2 _)) (< n1 n2)])) (define (pitch= p1 p2) (match* (p1 p2) [((Pitch n1 a1) (Pitch n2 a2)) (and (= n1 n2) (= a1 a2))]))
We do our own transposition, so that we can clamp the results into range before outputting Lilypond.
(define (transpose music amount) (map-notes (λ (note) (match note [(Note pitches log dots post-events) (Note (map (λ (p) (add-interval p amount)) pitches) log dots post-events)])) music))
And speaking of clamping:
(define (clamp music lower upper) (map-notes (λ (note) (match note [(Note pitches log dots post-events) (Note (map (λ (p) (cond [(pitch< p lower)])) pitches) log dots post-events)]))))
This function adds a post-event to the first and last note in some music, unless the music consists of only one note.
(define (add-event-first-last! m e1 e2) (let ([l (extract-notes m)]) (add-post-event! (first l) e1) (add-post-event! (last l) e2)) m) (define (add-event-first! m e) (let ([l (extract-notes m)]) (add-post-event! (first l) e)) m)
add-interval clamp transpose add-event-first-last! add-event-first!
Here are some utility functions for generating music.
(define (increase-dynamic dynamic) (if (eqv? dynamic 'ffff) 'ffff (cadr (member dynamic '(pppp ppp pp p mp mf f ff fff ffff))))) (define (decrease-dynamic dynamic) (if (eqv? dynamic 'pppp) 'pppp (cadr (member dynamic '(ffff fff ff f mf mp p pp ppp pppp))))) (define (nearest-power-of-two n) (let loop ([i 0]) (if (>= (expt 2 i) n) (expt 2 (- i 1)) (loop (+ i 1)))))
increase-dynamic decrease-dynamic nearest-power-of-two
2 Lilypond output
(module Output racket (provide <provisions/output>) (require <requirements/output>) <output>)
The conventions for representing music are illustrated by the output procedures, which turn the internal data structures into Lilypond input. Humans aren’t supposed to read the result, but for debugging purposes we keep it tidy.
(define (output-music m [out (current-output-port)]) (define (go m indentation start-of-line? space? meter) (define (easy m) (go m indentation start-of-line? space? meter)) <output-pitch> <output-value> <output-post-events> (define (output c) <annoying-output-stuff>) (define (output-string s) (map output (string->list s))) (match m [(list ms ...) (output #\newline) (map (λ (m) (easy m)) ms) (when (> (count Note? ms) 5) (output-string "\n\\allowBreak "))] <measure-cases> <note-cases> <tuplet-cases> <polyphony-case> [else (displayln m)])) (go m 2 #t #f #f))
(submod "music.rkt" Music)
output-music
Here we try to avoid extraneous whitespace, although I haven’t got it exactly right yet…
(cond [(char=? c #\newline) (if start-of-line? (void) (begin (set! start-of-line? #t) (set! space? #f) (display c out) (for ([_ (in-range indentation)]) (display #\space out))))] [(char=? c #\space) (if space? (void) (begin (set! space? #t) (set! start-of-line? #f) (display c out)))] [else (display c out) (set! start-of-line? #f) (set! space? #f)])
… namely when the following code is run.
[(Polyphony voice-1 voice-2) (output-string "\n<<") (set! indentation (+ indentation 2)) (output-string "\n{\n") (go voice-1 (+ indentation 4) #f #f meter) (output-string "\n}\n\\\\\n{\n") (go voice-2 (+ indentation 4) #f #f meter) (output-string "\n}\n") (set! indentation (- indentation 2)) (output-string ">>\n")]
We simplify a trivial case of pointless tuplets. However, things like a series of dotted notes inside a triplet are left alone.
[(Tuplet 1 music) (easy music)] [(Tuplet ratio music) (output-string (format "\n\\tuplet ~A {" ratio)) (go music (+ indentation 2) #f #f meter) (output-string "\n}\n")]
An empty measure can be used to output a \mark.
[(Measure _ _ '() label) (output-string (format "\\mark \"~A\"\n" (escape label)))] [(Measure 0 0 m label) (output-string (format "\\mark \"~A\"\n" (escape label))) (cond [(not meter) (easy m) (output-string "\\bar \"||\"\n")] [else (set! meter #f) (output-string "\\cadenzaOn\n") (easy m)])] [(Measure n d m label) (output-string (format "\\mark \"~A\"\n" label)) (when (not meter) (output-string "\\cadenzaOff\n")) (output-string (format "\\time ~A/~A~%" n d)) (easy m)]
(define (escape text) (string-replace text "\"" "\\\""))
Duplicate pitches in chords are removed before output.
[(Note '() log dots post-events) (output #\r) (output-value log dots) (output-post-events post-events)] [(Note (list pitches ...) log dots post-events) (define pruned (remove-duplicates pitches = #:key Pitch-number)) (define l (length pruned)) (cond [(null? (rest pruned)) (output-pitch (first pruned))] [else (output #\<) (map (λ (p) (output-pitch p) (set! l (- l 1)) (unless (< l 1) (output #\space))) pruned) (output #\>)]) (output-value log dots) (output-post-events post-events) (output #\space)]
(define (output-pitch pitch) (output-string (symbol->string (pitch-class-of pitch))) (let* ([octave (- (octave-of pitch) 3)] [c (if (< octave 0) #\, #\')]) (for ([_ (in-range octave)]) (output c))))
(define (output-post-events post-events) (map (λ (e) (output-string (case e [(staccato) "-."] [(marcato) "-^"] [(slur-begin) "-("] [(slur-end) "-)"] [(accent) "->"] [(crescendo-begin) "\\<"] [(crescendo-end) "\\!"] [(diminuendo-begin) "\\>"] [(diminuendo-end) "\\!"] [(sustain-begin) "\\sustainOn"] [(sustain-end) "\\sustainOff"] [(beam-begin) "-["] [(beam-end) "-]"] [(pppp ppp pp p mp mf f ff fff ffff fz rfz sf) (format "\\~A" e)] [else (display e) (error "what?")]))) post-events) (output #\space))
3 Stochastic LISP 1.5 musicalization
(module LISP15 racket (provide <provisions/l15>) (require <requirements/l15>) <l15>)
In order to generate variety in the musical output, the musicalizer passes around some state:
log is the current “default” duration; notes generally get their log field from this value
dots is the current number of dots
octave is the octave in which pitches will be generated
dynamic is the current dynamic level
setq-parity is #t if an even number of SETQ forms have been encountered in the course of processing a function
tonic is the current key center
mode is the name of the scale from which notes are drawn, when generating tonal music
pitcher is a procedure called to turn strings into pitches
Sometimes the state is varied by creating a new structure to pass down to recursive calls. However, some fields need to exist across levels of recursion; for example, even if a dynamics change happens deep within the call stack, it will still affect subsequent music generated by outer calls. Thus the fields dynamic, setq-parity, tonic, and mode are kept in mutable boxes.
Another aspect of the state is the depth parameter, which tracks the syntactic nesting of function calls (reset every LAMBDA).
Both depth and setq-parity are somewhat random; these specific values were chosen because they vary quickly and unpredictably. As calls become more nested, the rhythmic subdivision (i.e., log) generally increases, based on depth. Part of the translation of SETQ adds dynamics, whose precise nature depends upon the setq-parity.
(struct State (log dots octave dynamic setq-parity tonic mode pitcher)) (define depth (make-parameter 0)) (define (default-state pitcher) (State 8 0 4 (box 'mf) (box #f) (box 'a) (box 'major) pitcher)) (define (make-state state #:log [log (State-log state)] #:dots [dots (State-dots state)] #:octave [octave (State-octave state)] #:dynamic [dynamic (State-dynamic state)] #:setq-parity [setq-parity (State-setq-parity state)] #:tonic [tonic (State-tonic state)] #:mode [mode (State-mode state)] #:pitcher [pitcher (State-pitcher state)]) (State log dots octave dynamic setq-parity tonic mode pitcher)) (define-syntax-rule (with-state e (field ...) body ...) (match e [(State field ...) body ...]))
Here are some ways of turning strings into pitches. The character set in character-code is ordered numerically according to the IBM machines LISP 1.5 ran on, with the exception of the last dozen, added to support REDUCE (they are in a random order).
(define (character-code c) (string-find "0123456789=\"+abcdefghi.)-jklmnopqr$* /stuvwxyz,(|&;~:<>!'?" (make-string 1 (char-downcase c)))) (define (atonal-pitcher text state) (map (λ (c) (add-interval (make-pitch (unbox (State-tonic state)) (State-octave state)) (modulo (character-code c) 31))) (string->list text)))
For tonal music, we need to choose intervals from a certain scale. To spice the output up a bit, an octave displacement (relative to the octave field of the state) is also added depending on the specific character.
(define (make-scale-selector . r) (let loop ([pairs '()] [items r]) (if (null? items) (λ (code state) (define intervals (cdr (assoc (unbox (State-mode state)) pairs))) (list-ref intervals (modulo code (length intervals)))) (loop (cons (cons (first items) (second items)) pairs) (rest (rest items)))))) (define major-intervals '(0 5 10 13 18 23 28)) (define minor-intervals '(0 5 8 13 15 20 26)) (define major-pentatonic-intervals '(0 5 10 18 23)) (define minor-pentatonic-intervals '(0 8 13 15 26)) (define (octave-displacement code) (cond [(<= 0 code 24) -1] [(<= 24 code 42) 0] [else 1])) (define (make-scale-pitcher . r) (λ (text state) (map (λ (c) (define code (character-code c)) (add-interval (make-pitch (unbox (State-tonic state)) (+ (State-octave state) (octave-displacement code))) ((apply make-scale-selector r) code state))) (string->list text)))) (define pentatonic-pitcher (make-scale-pitcher 'major major-pentatonic-intervals 'minor minor-pentatonic-intervals)) (define tonal-pitcher (make-scale-pitcher 'major major-intervals 'minor minor-intervals))
atonal-pitcher tonal-pitcher pentatonic-pitcher
The general entry point to this LISP 1.5 musicalizer is musicalize-file. It pretends to be EVALQUOTE, collecting doublets and rewriting them into normal s-expressions. (However, both halves of the doublet are treated as evaluated.) The Overlord monitor is not simulated, so Overlord cards should be expunged from the input.
(define (musicalize-file in pitcher) (parameterize ([read-case-sensitive #f]) (let loop ([forms '()]) (let* ([operator (read in)] [operands (read in)]) (if (eof-object? operator) (musicalize-top-level (reverse forms) pitcher) (loop (cons (cons operator operands) forms)))))))
musicalize-file
Expressions that act as “declarations” are ignored, though comments are transferred to the score.
(define (musicalize-top-level forms pitcher) (let ([state (default-state pitcher)]) (map (λ (form) (match form [`(define (,things ...)) (map (λ (thing) (match thing [`(,name ,e) (Measure 0 0 (musicalize-expression e (make-state state)) (symbol->string name))])) things)] [`(comment ,stuff ...) (Measure 0 0 '() (~a stuff))] [`(special ,stuff ...) '()] [_ (Measure 0 0 (musicalize-expression form state) (~a form))])) forms)))
Like a compiler, the musicalizer traverses the code mostly in evaluation order.
(define (musicalize-expression e state) (with-state state (log dots octave dynamic setq-parity tonic mode pitcher) (match e <musicalize-atomic/constants> <musicalize-prog> <musicalize-functionals> <musicalize-setq> <musicalize-cond> <musicalize-application> <musicalize-built-ins> [`(,h . ,t) (musicalize-constant e state)])))
[(? symbol?) (musicalize-symbol e state)] [(? number?) (musicalize-constant e state)] ['() (Note '() log dots '())] [`',thing (musicalize-constant thing state)]
Most of the pitches in the output come from musicalize-symbol.
(define (musicalize-symbol s state) (with-state state (log dots octave dynamic setq-parity tonic mode pitcher) (if (eqv? s 'nil) (Note '() log dots '()) (let* ([text (symbol->string s)] [l (string-length text)] [pitches (pitcher text state)]) (if (and (>= l 1) (<= (State-log state) 8) (<= l 5)) (list (Note pitches log dots '())) (list (let ([i 0]) (map (λ (p) (set! i (+ i 1)) (Note (list p) (* log 2) dots (cond [(and (> l 1) (= i 1)) '(beam-begin)] [(and (> l 1) (= i l)) '(beam-end)] [else '()]))) pitches))))))))
(define (musicalize-constant c state) (with-state state (log dots octave dynamic setq-parity tonic mode pitcher) (match c [(? exact-integer?) (Note (list (make-pitch (integer->pitch-class (modulo c 31)) 4)) log dots '())] [(? number?) (Note (list (make-pitch (integer->pitch-class (modulo (exact-floor c) 31)) 4)) log (+ dots 1) '())] [(? symbol?) (musicalize-symbol c (make-state state #:octave 4))] [(? null?) (Note '() log dots '())] [`(,h . ,t) (list (musicalize-constant h state) (musicalize-constant t state))])))
The FUNCTION operator creates a sort of pseudo-closure, by storing the association list along with the lambda expression. Musically, I represent the environment capture with the sustain pedal.
[`(function ,e) (add-event-first-last! (musicalize-expression e state) 'sustain-begin 'sustain-end)] [`(lambda (,vs ...) ,e) (let* ([count (length vs)] [ratio (cond [(= count 1) 3/2] [(odd? count) (/ count (nearest-power-of-two count))] [else 1])]) (parameterize ([depth 0]) (cond [(= count 1) (musicalize-expression e state)] [(even? count) (musicalize-expression e state)] [else (Tuplet ratio (musicalize-expression e state))])))]
[`(setq ,v ,e) (define text (symbol->string v)) (define size (string-length text)) (set-box! (State-setq-parity state) (not (unbox setq-parity))) (let loop ([d (unbox dynamic)] [i size]) (if (= i 0) (list (musicalize-symbol v state) (add-event-first-last! (musicalize-expression e state) (if (unbox setq-parity) 'crescendo-begin 'diminuendo-begin) d)) (loop ((if (unbox setq-parity) increase-dynamic decrease-dynamic) d) (- i 1))))]
LISP 1.5 code uses PROG with great frequency, so we should try to wring as much musical interest out of it as possible. To this end, we take PROG as a gateway to polyphony. First, the body of the PROG, if it has any tags, is split up according to those tags; thus the body of
(PROG (V W) |
(COND ((AND OFL* (OR *FORT (NOT *NAT))) (GO D))) |
(TERPRI*) |
A (SETQ V U) |
(PRINC Y) |
(PRINC **BLANK) |
B (COND ((NULL V) (GO C))) |
(PRINC (CAR V)) |
(PRINC **BLANK) |
(SETQ V (CDR V)) |
(GO B) |
C (COND (X (TERPRI))) |
(COND ((NULL OFL*) (RETURN NIL)) (W (RETURN (WRS OFL*)))) |
D (WRS NIL) |
(SETQ W T) |
(GO A)) |
(LPRIW, from REDUCE) yields the items ((COND …) (TERPRI*)), (A (SETQ V U) (PRINC Y) (PRINC …)), etc. Then these groups are split into two parts, whence come the two voices in the music. This procedure is quite janky.
[`(return ,e) (musicalize-expression e (make-state state #:log (/ log 2) #:tonic (box 'a)))] [`(go ,tag) (set-box! tonic (pitch-class-of (add-interval (make-pitch (unbox tonic) 0) 5))) (add-event-first! (musicalize-symbol tag state) (increase-dynamic (unbox dynamic)))] [`(prog (,vs ...) ,body ...) (let* ([variable-count (length vs)] [ratio (if (>= variable-count 3) (/ variable-count (- variable-count 1)) 3/2)]) <prog/preprocess> <prog/go> <prog/final>)]
(define (preprocess-body body) (define fake-tag (gensym)) (if (zero? (count symbol? body)) (list (list* fake-tag #f body)) (let loop ([xs (list* fake-tag #f body)]) (match xs [(list* (? symbol? x) (? (negate symbol?) a) ... more) (cons (cons x a) (loop more))] ['() '()])))) (define-values (tag-count stuff) (let ([pairs (preprocess-body body)]) (cond [(and (null? (rest pairs)) (not (symbol-interned? (car (first pairs))))) (values 0 (cdr (first pairs)))] [(eqv? (first (cdr (first pairs))) #f) (values (- (length pairs) 1) (rest pairs))] [else (values (length pairs) pairs)])))
(define (go-one pair) (let ([name (car pair)] [expressions (cdr pair)]) (if name (list (musicalize-symbol name (make-state state #:log (* log 2))) (map (λ (e) (musicalize-expression e state)) expressions)) (map (λ (e) (musicalize-expression e state)) expressions)))) (define (go pairs n) (define-values (upper lower) (split-at pairs (/ n 2))) (Polyphony (map go-one upper) (transpose (map go-one lower) -62)))
(Tuplet ratio (cond [(zero? tag-count) (map (λ (e) (musicalize-expression e state)) (rest (rest stuff)))] [(odd? tag-count) (cons (go-one (first stuff)) (if (null? (rest stuff)) '() (list (go (rest stuff) (- tag-count 1)))))] [else (go stuff tag-count)]))
The test part of a COND clause is raised an octave from the surrounding music.
[`(cond ((,test ,result))) (list (add-event-first! (musicalize-expression test (make-state state #:dynamic (increase-dynamic (unbox dynamic)))) (increase-dynamic dynamic)) (musicalize-expression result state))] [`(cond ((,tests ,results) ...)) (define count (length tests)) (define (clause c) (list (musicalize-expression (first c) (make-state state #:octave (+ octave 1) #:tonic (box (pitch-class-of (add-interval (make-pitch (unbox tonic) 0) 7))))) (musicalize-expression (second c) state))) (define (go clauses count) (define-values (upper lower) (split-at clauses (/ count 2))) (map clause clauses)) (Tuplet (if (odd? count) (/ count (nearest-power-of-two count)) (/ (+ count 1) count)) (if (odd? count) (list (clause (first tests) (first results)) (go (map list (rest tests) (rest results)) (- count 1))) (go (map list tests results) count)))]
[`(,operator ,operands ...) (parameterize ([depth (+ (depth) 1)]) (let* ([state (make-state state #:log (cond [(zero? (modulo (depth) 5)) (* log 2)] [(and (zero? (modulo (depth) 9)) (>= log 32)) (/ log 2)] [(zero? (modulo (depth) 7)) (/ log 2)] [else log]))] [music (append (map (λ (o) (musicalize-expression o state)) operands) (list (musicalize-expression operator state)))]) (cond [(zero? (modulo (depth) 7)) (Tuplet (/ (depth) (nearest-power-of-two (depth))) music)] [else music])))]
Some built-in functions are handled specially.
[`(not ,e) (musicalize-expression e (make-state state #:mode (box 'minor)))] [`(cons ,e1 ,e2) (list (musicalize-expression e1 state) (musicalize-expression e2 (make-state state #:dots (min 3 (+ dots 1)))))]
(submod "music.rkt" Music)
(define (lily measures out [score? #t]) (fprintf out "\\version \"2.25.26\"\n\n%#(set-default-paper-size \"a1\")\n\n#(define (naturalize-pitch p)\n (let ((o (ly:pitch-octave p))\n (a (* 4 (ly:pitch-alteration p)))\n (n (ly:pitch-notename p)))\n (cond\n ((and (> a 1) (or (eqv? n 6) (eqv? n 2)))\n (set! a (- a 2))\n (set! n (+ n 1)))\n ((and (< a -1) (or (eqv? n 0) (eqv? n 3)))\n (set! a (+ a 2))\n (set! n (- n 1))))\n (cond\n ((> a 2) (set! a (- a 4)) (set! n (+ n 1)))\n ((< a -2) (set! a (+ a 4)) (set! n (- n 1))))\n (if (< n 0) (begin (set! o (- o 1)) (set! n (+ n 7))))\n (if (> n 6) (begin (set! o (+ o 1)) (set! n (- n 7))))\n (ly:make-pitch o n (/ a 4))))\n\n#(define (naturalize music)\n (let ((es (ly:music-property music 'elements))\n (e (ly:music-property music 'element))\n (p (ly:music-property music 'pitch)))\n (if (pair? es)\n (ly:music-set-property!\n music 'elements\n (map naturalize es)))\n (if (ly:music? e)\n (ly:music-set-property!\n music 'element\n (naturalize e)))\n (if (ly:pitch? p)\n (begin\n (set! p (naturalize-pitch p))\n (ly:music-set-property! music 'pitch p)))\n music))\n\nnaturalizeMusic =\n#(define-music-function (m)\n (ly:music?)\n (naturalize m))\n\nmusic = \\naturalizeMusic {\n~A\n}\n\n\\score {\n ~A\n <<\n \\new PianoStaff \\autoChange {\n \\tempo 4 = 60\n \\cadenzaOn\n \\music\n }\n >>\n \n \\midi { }\n}\n" (let ([out (open-output-string)]) (output-music measures out) (get-output-string out)) (if score? " \\layout {\n \\set Score.measureBarType = \"\"\n \\accidentalStyle Staff.dodecaphonic\n \\context {\n \\Voice\n \\remove Forbid_line_break_engraver\n \\override TupletBracket.bracket-visibility = ##t\n \\override TupletNumber.text = #tuplet-number::calc-fraction-text\n \\override Beam.breakable = ##t\n }\n \\context {\n \\Score\n \\override SpacingSpanner.uniform-stretching = ##t\n %proportionalNotationDuration = #1/8\n }\n }" "")))
(submod "output.rkt" Output)
lily