(set-xml-accept-only-string-valued-attributes-in 'midi #f)
(define (ensure-all-abstime-in! operation message-list)
(let ((delta-time-messages
(traverse-and-collect-all-from-ast
message-list
(lambda (x) (and (ast? x) (equal? (ast-element-name x) "NoteOn") (ast-attribute x 'deltaTime #f)))
id-1)))
(if (> (length delta-time-messages) 0)
(laml-error "Only absTime mode is supported by" operation))))
(define (ensure-all-deltatime-in! operation message-list)
(let ((delta-time-messages
(traverse-and-collect-all-from-ast
message-list
(lambda (x) (and (ast? x) (equal? (ast-element-name x) "NoteOn") (ast-attribute x 'absTime #f)))
id-1)))
(if (> (length delta-time-messages) 0)
(laml-error "Only deltaTime mode is supported by" operation))))
(define (fuzzy-drums message-list)
(map fuzzy-drum-1
message-list
(append (cdr message-list) (list #f))
(cons #f (butlast message-list))))
(define (fuzzy-drum-1 this-mes next-mes prev-mes)
(cond ((drum-message? this-mes)
(fuzzy-drum-message this-mes next-mes prev-mes))
(else this-mes)))
(define (fuzzy-drum-message this-mes next-mes prev-mes)
(let ((window-size (if (and this-mes next-mes prev-mes)
(max (- (as-number (ast-attribute next-mes 'absTime)) (as-number (ast-attribute this-mes 'absTime)))
(- (as-number (ast-attribute this-mes 'absTime)) (as-number (ast-attribute prev-mes 'absTime))))
0)))
(cond
((delete-message? this-mes) '())
((change-message-velocity? this-mes)
(copy-ast-mutate-attributes this-mes 'velocity (as-int-string (between 0 127 (+ (as-number (ast-attribute this-mes 'velocity)) (delta-velocity))))))
((move-message? this-mes)
(copy-ast-mutate-attributes this-mes 'absTime (as-int-string (+ (as-number (ast-attribute this-mes 'absTime)) (delta-move window-size)))))
(else this-mes))))
(define (drum-message? mes)
(or (equal? "9" (ast-attribute mes 'channel))
(equal? "10" (ast-attribute mes 'channel))))
(define delete-frequency 5)
(define move-frequency 5)
(define velocity-change-frequency 20)
(define velocity-max-change 40)
(define (delete-message? mes)
(let ((r (random 100)))
(< r delete-frequency)))
(define move-r 0)
(define (move-message? mes)
(let ((r (random 100)))
(if (< r move-frequency)
(begin (set! move-r r) #t)
(begin (set! move-r 0) #f))))
(define (delta-move window-size)
(if (even? move-r)
(- (to-int (* (/ move-r 100) window-size)))
(+ (to-int (* (/ move-r 100) window-size)))))
(define vel-r 0)
(define (change-message-velocity? mes)
(let ((r (random 100)))
(if (< r velocity-change-frequency)
(begin (set! vel-r r) #t)
(begin (set! vel-r 0) #f))))
(define (delta-velocity)
(to-int
(if (even? vel-r)
(- (* (/ vel-r 100) velocity-max-change))
(+ (* (/ vel-r 100) velocity-max-change)))))
(define (NoteOn? x)
(and (ast? x) (equal? (ast-element-name x) "NoteOn")))
(define (NoteOnCh? channels)
(lambda (x)
(if (NoteOn? x)
(let ((ch (ast-attribute x 'channel #f)))
(if ch
(member (as-number ch) channels)
#f))
#f)))
(define (Meta? x . optional-parameter-list)
(let ((type-1 (optional-parameter 1 optional-parameter-list "*")))
(and (ast? x) (equal? (ast-element-name x) "Meta")
(if (equal? type-1 "*")
#t
(= type-1 (as-number (ast-attribute x 'type #f)))))))
(define (ProgramChange? x . optional-parameter-list)
(let ((channel (optional-parameter 1 optional-parameter-list #t)))
(and (ast? x)
(cond ((and (boolean? channel) channel)
(equal? (ast-element-name x) "ProgramChange"))
((and (number? channel) (>= channel 1) (<= channel 16))
(and (equal? (ast-element-name x) "ProgramChange")
(= channel (as-number (ast-attribute x 'channel)))))
((and (string? channel) (>= (as-number channel) 1) (<= (as-number channel) 16))
(and (equal? (ast-element-name x) "ProgramChange")
(equal? channel (as-number (ast-attribute x 'channel)))))
(else #f)))))
(define (SysEx? x . optional-parameter-list)
(let ((sys-ex-hex-string (optional-parameter 1 optional-parameter-list #f)))
(if (ast? x)
(cond ((not sys-ex-hex-string) (equal? (ast-element-name x) "SysEx"))
(sys-ex-hex-string (and (equal? (ast-element-name x) "SysEx") (equal? (ast-text x) sys-ex-hex-string)))
(else #f))
#f)))
(define (ControlChange? x . optional-parameter-list)
(let* ((control (optional-parameter 1 optional-parameter-list #t))
(channel (optional-parameter 2 optional-parameter-list #t))
(control-nr (if (and (boolean? control) control) #t (as-number control)))
(channel-nr (if (and (boolean? channel) channel) #t (as-number channel))))
(and (ast? x)
(cond ((and (boolean? control) control (boolean? channel) channel)
(equal? (ast-element-name x) "ControlChange"))
((and (boolean? control) control (number? channel-nr))
(and (equal? (ast-element-name x) "ControlChange") (= (as-number (ast-attribute x 'channel)) channel-nr)))
((and (number? control-nr) (boolean? channel) channel)
(and (equal? (ast-element-name x) "ControlChange") (= (as-number (ast-attribute x 'control)) control-nr)))
((and (number? control-nr) (number? channel-nr))
(and (equal? (ast-element-name x) "ControlChange")
(= (as-number (ast-attribute x 'control)) control-nr) (= (as-number (ast-attribute x 'channel)) channel-nr)))
(else #f)))))
(define (PitchBendChange? x . optional-parameter-list)
(let* ((channel (optional-parameter 1 optional-parameter-list #f)))
(if channel
(and (ast? x) (equal? (ast-element-name x) "PitchBendChange") (= (as-number channel) (as-number (ast-attribute x 'channel -1))))
(and (ast? x) (equal? (ast-element-name x) "PitchBendChange")))))
(define (drum-NoteOn? x)
(and (NoteOn? x) (or (equal? (ast-attribute x 'channel) "9") (equal? (ast-attribute x 'channel) "10"))))
(define (midi-null-event-message? x)
(and (ast? x) (equal? (ast-element-name x) "Meta")
(equal? (ast-attribute x 'type) "1")))
(define (channel-message? x)
(if (ast? x)
(let ((ch (ast-attribute x 'channel #f)))
(if ch #t #f))
#f))
(define (non-channel-message? x)
(if (ast? x)
(let ((ch (ast-attribute x 'channel #f)))
(if ch #f #t))
#f))
(define (midi attribute-name mes)
(let ((attribute-name-symbol (as-symbol attribute-name)))
(if (ast? mes)
(let ((attr-val (ast-attribute mes attribute-name-symbol #f)))
(if (and attr-val
(member attribute-name-symbol '(deltaTime absTime channel note velocity duration value number pressure strum-length control type)))
(as-number attr-val)
attr-val))
#f)))
(define delta-merge
(xml-in-laml-positional-abstraction 1 0
(lambda (other-message-list contents attributes)
(delta-merge-two-lists contents other-message-list))))
(define (delta-merge-two-lists message-list-1 message-list-2)
(delta-merge-two-lists-1 message-list-1 0 message-list-2 0 '()))
(define (delta-merge-lists . list-of-message-lists)
(if (null? list-of-message-lists)
'()
(let ((first-list (first list-of-message-lists))
(rest-list-of-message-lists (cdr list-of-message-lists)))
(delta-merge-two-lists first-list (apply delta-merge-lists rest-list-of-message-lists)))))
(define (delta-merge-two-lists-1 message-list-1 subtraction-1 message-list-2 subtraction-2 res)
(cond ((and (null? message-list-1)
(null? message-list-2)) (reverse res))
((null? message-list-1)
(append (reverse res)
(let* ((ast (car message-list-2))
(delta-time (as-number (ast-attribute ast 'deltaTime)))
(effective-delta-time (- delta-time subtraction-2)))
(cons (copy-ast-mutate-attributes ast 'deltaTime effective-delta-time) (cdr message-list-2)))))
((null? message-list-2)
(append (reverse res)
(let* ((ast (car message-list-1))
(delta-time (as-number (ast-attribute ast 'deltaTime)))
(effective-delta-time (- delta-time subtraction-1)))
(cons (copy-ast-mutate-attributes ast 'deltaTime effective-delta-time) (cdr message-list-1)))))
((not (ast? (car message-list-1))) (delta-merge-two-lists-1 (cdr message-list-1) subtraction-1 message-list-2 subtraction-2 res))
((not (ast? (car message-list-2))) (delta-merge-two-lists-1 message-list-1 subtraction-1 (cdr message-list-2) subtraction-2 res))
(else
(let* ((ast-1 (car message-list-1))
(ast-2 (car message-list-2))
(delta-time-1 (as-number (ast-attribute ast-1 'deltaTime)))
(delta-time-2 (as-number (ast-attribute ast-2 'deltaTime)))
(effective-delta-time-1 (- delta-time-1 subtraction-1))
(effective-delta-time-2 (- delta-time-2 subtraction-2)))
(if (< effective-delta-time-1 effective-delta-time-2)
(delta-merge-two-lists-1 (cdr message-list-1) 0 message-list-2 (+ subtraction-2 effective-delta-time-1)
(cons (copy-ast-mutate-attributes ast-1 'deltaTime effective-delta-time-1) res))
(delta-merge-two-lists-1 message-list-1 (+ subtraction-1 effective-delta-time-2) (cdr message-list-2) 0
(cons (copy-ast-mutate-attributes ast-2 'deltaTime effective-delta-time-2) res))
)))))
(define abs-merge
(xml-in-laml-positional-abstraction 1 0
(lambda (other-message-list contents attributes)
(abs-merge-two-lists contents other-message-list))))
(define (abs-merge-two-lists message-list-1 message-list-2)
(abs-merge-two-lists-1 message-list-1 message-list-2 '()))
(define (abs-merge-two-lists-1 message-list-1 message-list-2 res)
(cond ((and (null? message-list-1)
(null? message-list-2)) (reverse res))
((null? message-list-1) (append (reverse res) message-list-2))
((null? message-list-2) (append (reverse res) message-list-1))
((not (ast? (car message-list-1))) (abs-merge-two-lists-1 (cdr message-list-1) message-list-2 res))
((not (ast? (car message-list-2))) (abs-merge-two-lists-1 message-list-1 (cdr message-list-2) res))
(else
(let* ((ast-1 (car message-list-1))
(ast-2 (car message-list-2))
(abs-time-1 (as-number (ast-attribute ast-1 'absTime)))
(abs-time-2 (as-number (ast-attribute ast-2 'absTime))))
(if (<= abs-time-1 abs-time-2)
(abs-merge-two-lists-1 (cdr message-list-1) message-list-2
(cons (car message-list-1) res))
(abs-merge-two-lists-1 message-list-1 (cdr message-list-2)
(cons (car message-list-2) res))
)))))
(define abs-time-reverse
(xml-in-laml-positional-abstraction 0 0
(lambda (contents attributes)
(abs-time-reverse-1 contents))))
(define (abs-time-reverse-1 messages)
(let ((rev-messages (reverse messages)))
(map (lambda (m mr)
(copy-ast-mutate-attributes m 'absTime (midi 'absTime mr)))
messages rev-messages)))
(define delta-abs-merge
(xml-in-laml-positional-abstraction 1 0
(lambda (delta-message-list contents attributes)
(delta-abs-merge-two-lists delta-message-list contents))))
(define (delta-abs-merge-two-lists delta-message-list abs-message-list)
(let* ((first-abs-time (as-number (ast-attribute (first abs-message-list) 'absTime)))
(delta-to-abs-message-list (delta-time-list-to-abs-time-list delta-message-list first-abs-time)))
(abs-merge-two-lists delta-to-abs-message-list abs-message-list)))
(define (delta-time-list-to-abs-time-list delta-message-list first-abs-time)
(if (null? delta-message-list)
'()
(let* ((first-delta-mes (first delta-message-list))
(next-abs-time (+ first-abs-time (as-number (ast-attribute first-delta-mes 'deltaTime)))))
(cons (single-message-ast-delta-to-abs-time first-delta-mes next-abs-time)
(delta-time-list-to-abs-time-list (cdr delta-message-list) next-abs-time)))))
(define transform-messages
(xml-in-laml-positional-abstraction 2 0
(lambda (filter-fn transformation-fn contents attributes)
(transform-messages-1 filter-fn transformation-fn contents ))))
(define (transform-messages-1 filter-fn transformation-fn message-list)
(map
(lambda (mes-ast)
(if (and (ast? mes-ast) (filter-fn mes-ast))
(transformation-fn mes-ast)
mes-ast))
message-list))
(define filter-messages
(xml-in-laml-positional-abstraction 1 0
(lambda (pred-fn contents attributes)
(filter-messages-1 pred-fn contents ))))
(define (filter-messages-1 pred-fn message-list)
(filter
(lambda (x)
(if (ast? x)
(pred-fn x)
#t))
message-list))
(define filter-messages-keep-residual-and-accumulate!
(xml-in-laml-positional-abstraction 3 0
(lambda (pred-fn abs-target-file-path abs-merge-file-path contents attributes)
(filter-messages-keep-residual-and-accumulate-1! pred-fn abs-target-file-path abs-merge-file-path contents))))
(define (filter-messages-keep-residual-and-accumulate-1! pred-fn abs-target-file-path abs-merge-file-path message-list)
(filter-messages-keep-residual-and-accumulate-2 pred-fn abs-target-file-path abs-merge-file-path message-list '() '()))
(define (filter-messages-keep-residual-and-accumulate-2 pred-fn abs-target-file-path abs-merge-file-path message-list result-list residual-list)
(cond ((null? message-list)
(let ((merge-list (if (and abs-merge-file-path (file-exists? abs-merge-file-path))
(file-read abs-merge-file-path)
'())))
(file-write (append merge-list (map compact-midi-laml-ast (reverse residual-list))) abs-target-file-path)
(reverse result-list)
)
)
((and (ast? (car message-list)) (pred-fn (car message-list)))
(filter-messages-keep-residual-and-accumulate-2 pred-fn abs-target-file-path abs-merge-file-path (cdr message-list) (cons (car message-list) result-list) residual-list))
((and (ast? (car message-list)) (not (pred-fn (car message-list))))
(filter-messages-keep-residual-and-accumulate-2 pred-fn abs-target-file-path abs-merge-file-path (cdr message-list) result-list (cons (car message-list) residual-list)))
(else
(filter-messages-keep-residual-and-accumulate-2 pred-fn abs-target-file-path abs-merge-file-path (cdr message-list) result-list residual-list))))
(define filter-messages-keep-residual-and-reprocess!
(xml-in-laml-positional-abstraction 3 0
(lambda (pred-fn abs-target-file-path abs-merge-file-path contents attributes)
(filter-messages-keep-residual-and-reprocess-1! pred-fn abs-target-file-path abs-merge-file-path contents))))
(define (filter-messages-keep-residual-and-reprocess-1! pred-fn abs-target-file-path abs-merge-file-path message-list)
(let ((merge-list (if (and abs-merge-file-path (file-exists? abs-merge-file-path))
(map uncompact-midi-laml-entry (file-read abs-merge-file-path))
'())))
(filter-messages-keep-residual-and-reprocess-2 pred-fn abs-target-file-path (abs-merge-two-lists message-list merge-list) '() '())))
(define (filter-messages-keep-residual-and-reprocess-2 pred-fn abs-target-file-path message-list result-list residual-list)
(cond ((null? message-list)
(file-write (map compact-midi-laml-ast (reverse residual-list)) abs-target-file-path)
(reverse result-list)
)
((and (ast? (car message-list)) (pred-fn (car message-list)))
(filter-messages-keep-residual-and-reprocess-2 pred-fn abs-target-file-path (cdr message-list) (cons (car message-list) result-list) residual-list))
((and (ast? (car message-list)) (not (pred-fn (car message-list))))
(filter-messages-keep-residual-and-reprocess-2 pred-fn abs-target-file-path (cdr message-list) result-list (cons (car message-list) residual-list)))
(else
(filter-messages-keep-residual-and-reprocess-2 pred-fn abs-target-file-path (cdr message-list) result-list residual-list))))
(define transform-attribute
(xml-in-laml-positional-abstraction
3 0
(lambda (ast-predicate attribute-name transformation-fn contents attributes)
(transform-attribute-1 ast-predicate attribute-name transformation-fn contents))))
(define (transform-attribute-1 ast-predicate attribute-name transformation-fn message-list)
(map
(lambda (x)
(if (and (ast? x) (ast-predicate x))
(let* ((mes-ast x)
(attribute-value (ast-attribute mes-ast attribute-name #f))
)
(if attribute-value
(copy-ast-mutate-attributes mes-ast attribute-name (as-int-string (transformation-fn (as-number attribute-value))))
mes-ast))
x))
message-list))
(define scale-attribute-by-factor
(xml-in-laml-positional-abstraction
3 0
(lambda (ast-predicate attribute-name factor contents attributes)
(scale-attribute-by-factor-1 ast-predicate attribute-name factor contents))))
(define (scale-attribute-by-factor-1 ast-predicate attribute-name factor messages)
(transform-attribute-1 ast-predicate attribute-name (lambda (value) (* factor value)) messages))
(define randomize-attribute
(xml-in-laml-positional-abstraction 7 0
(lambda (pred attribute-name channel-list lower-number upper-number min-attribute-value max-attribute-value cont attr)
(randomize-attribute-1 pred attribute-name channel-list lower-number upper-number min-attribute-value max-attribute-value cont))))
(define (randomize-attribute-1 pred attribute-name channel-list lower-number upper-number min-attribute-value max-attribute-value message-list)
(map
(lambda (mes-ast)
(if (and (ast? mes-ast) (pred mes-ast))
(let ((channel (ast-attribute mes-ast 'channel #f)))
(if (and channel (memv (as-number channel) channel-list))
(let ((attr-value (as-number (ast-attribute mes-ast attribute-name #f)))
(random-number (random-real-number-between lower-number upper-number))
)
(if attr-value
(copy-ast-mutate-attributes mes-ast attribute-name
(if (and min-attribute-value max-attribute-value)
(between min-attribute-value max-attribute-value (to-int (* random-number attr-value)))
(to-int (* random-number attr-value))))
mes-ast))
mes-ast))
mes-ast))
message-list))
(define random-real-number-between
(let ((seed (- (power 2 31) 1)))
(random-seed seed)
(lambda (a b)
(let* ((lgt (- b a))
(r (exact->inexact (/ (random seed) seed)))
(rl (* r lgt))
(rla (+ a rl)))
rla))))
(define (abs-time-sequence? message-list)
(cond ((null? message-list) #f)
((ast? (first message-list))
(has-ast-attribute? (car message-list) 'absTime))
(else (abs-time-sequence? (cdr message-list)))))
(define (delta-time-sequence? message-list)
(cond ((null? message-list) #f)
((ast? (first message-list))
(has-ast-attribute? (car message-list) 'deltaTime))
(else (delta-time-sequence? (cdr message-list)))))
(define (assert-abs-time messages)
(if (not (abs-time-sequence? messages))
(laml-error "In this context, you must use absTime sequences.")))
(define (assert-delta-time messages)
(if (not (delta-time-sequence? messages))
(laml-error "In this context, you must use deltaTime sequences.")))
(define replicate
(xml-in-laml-positional-abstraction 1 0
(lambda (n cont attr)
(replicate-1 n cont))))
(define (replicate-1 n message-list)
(cond ((= n 0) '())
(else (append message-list (replicate-1 (- n 1) message-list)))))
(define scale-attribute
(xml-in-laml-positional-abstraction 2 0
(lambda (attribute-name scaling-function contents attributes)
(scale-attribute-1 attribute-name scaling-function contents ))))
(define (scale-attribute-1 attribute-name f contents)
(let* ((attr-name (as-symbol attribute-name))
(noteon-contents (filter (lambda (x) (and (ast? x) (equal? "NoteOn" (ast-element-name x)))) contents))
(number-of-noteon-messages (length noteon-contents))
(number-list (consequtive-numbering-by-predicate NoteOn? contents 1 0))
)
(map
(lambda (mes-ast i)
(if (and (ast? mes-ast) (equal? "NoteOn" (ast-element-name mes-ast)))
(let ((attr-value (ast-attribute mes-ast attr-name #f)))
(if attr-value
(let* ((attr-val-number (as-number attr-value))
(max-i number-of-noteon-messages)
(scaled-attr-value (* attr-val-number (f (/ i max-i))))
)
(copy-ast-mutate-attributes mes-ast
(as-symbol attr-name)
(as-int-string scaled-attr-value)))
mes-ast))
mes-ast)
)
contents
number-list)))
(define scale-attribute-of-channel
(xml-in-laml-positional-abstraction 3 0
(lambda (ch attribute-name scaling-function contents attributes)
(scale-attribute-of-channel-1 ch attribute-name scaling-function contents ))))
(define (scale-attribute-of-channel-1 ch attribute-name f contents)
(let* ((attr-name (as-symbol attribute-name))
(noteon-contents (filter (lambda (x) (and (ast? x) (equal? "NoteOn" (ast-element-name x)) (= ch (as-number (ast-attribute x 'channel))))) contents))
(number-of-noteon-messages (length noteon-contents))
(number-list (consequtive-numbering-by-predicate
(lambda (x) (and (NoteOn? x) (= ch (as-number (ast-attribute x 'channel)))))
contents 1 0))
)
(map
(lambda (mes-ast i)
(if (and (ast? mes-ast) (equal? "NoteOn" (ast-element-name mes-ast)))
(let ((attr-value (ast-attribute mes-ast attr-name #f)))
(if (and attr-value (= ch (as-number (ast-attribute mes-ast 'channel))))
(let* ((attr-val-number (as-number attr-value))
(max-i number-of-noteon-messages)
(scaled-attr-value (* attr-val-number (f (/ i max-i))))
)
(copy-ast-mutate-attributes mes-ast
(as-symbol attr-name)
(as-int-string scaled-attr-value)))
mes-ast))
mes-ast)
)
contents
number-list)))
(define scale-attribute-by-predicate
(xml-in-laml-positional-abstraction 4 0
(lambda (ch-list attribute-name scaling-function note-value-predicate contents attributes)
(let ((domaining (defaulted-get-prop 'domaining attributes 'relative-position)))
(scale-attribute-by-predicate-1 ch-list attribute-name scaling-function note-value-predicate (as-symbol domaining) (filter ast? contents))))))
(define (scale-attribute-by-predicate-1 ch-list attribute-name f note-value-predicate domaining contents)
(if (and (delta-time-sequence? contents) (eq? domaining 'abs-time-domain-scaling))
(laml-error "abs-time-domain-scaling can only be sued in pure absTime mode"))
(let* ((attr-name (as-symbol attribute-name))
(noteon-contents (filter (lambda (x) (and (ast? x) (equal? "NoteOn" (ast-element-name x)) (note-value-predicate (as-number (ast-attribute x 'note))))) contents))
(number-of-noteon-messages (length noteon-contents))
(number-list (consequtive-numbering-by-predicate
(lambda (x) (NoteOn? x) (note-value-predicate (as-number (ast-attribute x 'note))))
contents 1 0))
(t-start (if (eq? domaining 'abs-time-domain-scaling)
(as-number (ast-attribute (first contents) 'absTime))
0))
(t-end (if (eq? domaining 'abs-time-domain-scaling)
(as-number (ast-attribute (last contents) 'absTime))
0))
)
(map
(lambda (mes-ast i)
(if (and (ast? mes-ast) (equal? "NoteOn" (ast-element-name mes-ast)) (note-value-predicate (as-number (ast-attribute mes-ast 'note))))
(let ((attr-value (ast-attribute mes-ast attr-name #f)))
(if (and attr-value (member (as-number (ast-attribute mes-ast 'channel)) ch-list))
(let* ((attr-val-number (as-number attr-value))
(max-i number-of-noteon-messages)
(scaled-attr-value
(cond ((eq? domaining 'abs-time-domain-scaling)
(let ((t-cur (as-number (ast-attribute mes-ast 'absTime))))
(* attr-val-number (f (/ (- t-cur t-start) (- t-end t-start)))))
)
((eq? domaining 'relative-position)
(* attr-val-number (f (/ i max-i)))
)
(else (laml-error "scale-attribute-by-predicate-1: Unknown domaining" domaining))
))
)
(copy-ast-mutate-attributes mes-ast
(as-symbol attr-name)
(as-int-string scaled-attr-value)))
mes-ast))
mes-ast)
)
contents
number-list)))
(define (consequtive-numbering-by-predicate pred lst first-val missing-value)
(consequtive-numbering-by-predicate-1 pred lst 1 missing-value '()))
(define (consequtive-numbering-by-predicate-1 pred lst first-val missing-value res)
(cond ((null? lst) (reverse res))
((pred (car lst)) (consequtive-numbering-by-predicate-1 pred (cdr lst) (+ first-val 1) missing-value (cons first-val res)))
(else (consequtive-numbering-by-predicate-1 pred (cdr lst) first-val missing-value (cons missing-value res)))))
(define enforce-attribute-value
(xml-in-laml-positional-abstraction 3 0
(lambda (form-name attribute-name attribute-value contents attributes)
(enforce-attribute-value-1 form-name attribute-name attribute-value contents))))
(define (enforce-attribute-value-1 form-name attribute-name attribute-value message-list)
(map (lambda (x)
(if (and (ast? x) (equal? (ast-element-name x) (as-string form-name)))
(copy-ast-mutate-attributes x (as-symbol attribute-name) (as-string attribute-value))
x)
)
message-list)
)
(define insert-leading-and-trailing-beats
(xml-in-laml-positional-abstraction 1 0
(lambda (ch contents attributes)
(let ((ppqn (defaulted-get-prop 'ppqn attributes #f))
(n (defaulted-get-prop 'n attributes #f))
(m (defaulted-get-prop 'm attributes #f)))
(insert-leading-and-trailing-beats-1
ch
(if ppqn (as-number ppqn) 1920)
(if n (as-number n) 4)
(if m (as-number n) 4)
contents)))))
(define (insert-leading-and-trailing-beats-1 ch ppqn n m messages)
(let* ((messages-only-ast (filter ast? messages))
(end-of-track-message (last messages-only-ast))
(before-end-of-track-messages (butlast messages-only-ast)))
(if (not (and (equal? (ast-element-name end-of-track-message) "Meta") (= 47 (midi 'type end-of-track-message))))
(laml-error "insert-leading-and-trailing-beats-1 ch messages: Last message is not a Meta end of track message."))
(let* ((first-mes-abs-time (midi 'absTime (first before-end-of-track-messages)))
(end-of-track-time (midi 'absTime end-of-track-message))
(last-bar (quotient end-of-track-time (* ppqn n)))
(trailing-insert-abs-time (* (+ last-bar 1) (* ppqn n)))
(end-of-track-abs-time (+ trailing-insert-abs-time (* ppqn n 2))))
(append
(map (lambda (at)
(NoteOn 'absTime at 'channel ch 'note "37" 'velocity "127" 'duration "100")
)
(list first-mes-abs-time (+ first-mes-abs-time (* 1 ppqn)) (+ first-mes-abs-time (* 2 ppqn)) (+ first-mes-abs-time (* 3 ppqn))))
(time-displace (* 2 n ppqn) before-end-of-track-messages)
(map (lambda (at)
(NoteOn 'absTime at 'channel ch 'note "37" 'velocity "127" 'duration "100")
)
(list trailing-insert-abs-time (+ trailing-insert-abs-time (* 1 ppqn)) (+ trailing-insert-abs-time (* 2 ppqn)) (+ trailing-insert-abs-time (* 3 ppqn))))
(list
(Meta 'absTime end-of-track-abs-time 'info "End of track" 'type "47" ""))))))
(define thin-out-messages-abs-time
(xml-in-laml-positional-abstraction 2 0
(lambda (channel-list abs-time-pred contents attributes)
(thin-out-messages-abs-time-1 channel-list abs-time-pred contents))))
(define (thin-out-messages-abs-time-1 channel-list abs-time-pred message-list)
(filter-messages-1
(lambda (mes-ast)
(let ((ch (ast-attribute mes-ast 'channel #f))
(delta-time? (ast-attribute mes-ast 'deltaTime #f))
)
(if delta-time? (laml-error "thin-out-message-abs-time: Encountered a deltaTime message. Can only be applied in pure absTime mode."))
(if ch
(if (member (as-number ch) channel-list)
(abs-time-pred (as-number (ast-attribute mes-ast 'absTime)))
#t)
#t)))
message-list))
(define thin-out-messages-delta-time
(xml-in-laml-positional-abstraction 3 0
(lambda (channel-list abs-time-pred start-time contents attributes)
(thin-out-messages-delta-time-1 channel-list abs-time-pred start-time contents))))
(define (thin-out-messages-delta-time-1 channel-list abs-time-pred start-time message-list)
(thin-out-messages-delta-time-2 channel-list abs-time-pred start-time 0 message-list '()))
(define (thin-out-messages-delta-time-2 channel-list abs-time-pred previous-abs-time accumulated-deltas message-list result-list)
(cond ((null? message-list) (reverse result-list))
((ast? (car message-list))
(let* ((mes-ast (car message-list))
(ch (ast-attribute mes-ast 'channel #f))
(abs-time? (ast-attribute mes-ast 'absTime #f)))
(if abs-time? (laml-error "thin-out-message-delta-time: Encountered an absTime message. Can only be applied in deltaTime mode."))
(let* ((delta-time (as-number (ast-attribute mes-ast 'deltaTime)))
(new-abs-time (+ previous-abs-time delta-time))
)
(if (and ch
(member (as-number ch) channel-list)
(abs-time-pred new-abs-time)
)
(let ((delta-modifier-mes-ast (copy-ast-mutate-attributes mes-ast 'deltaTime (+ delta-time accumulated-deltas))))
(thin-out-messages-delta-time-2 channel-list abs-time-pred new-abs-time 0 (cdr message-list) (cons delta-modifier-mes-ast result-list)))
(thin-out-messages-delta-time-2 channel-list abs-time-pred new-abs-time (+ accumulated-deltas delta-time) (cdr message-list) result-list)))))
(else (thin-out-messages-delta-time-2 channel-list abs-time-pred previous-abs-time accumulated-deltas (cdr message-list) result-list))))
(define (keep-beat n . optional-parameter-list)
(let ((displacement (optional-parameter 1 optional-parameter-list 0))
(ppqn (optional-parameter 2 optional-parameter-list 1920))
)
(lambda (abs-time)
(= (remainder
(- abs-time displacement)
(to-int (* ppqn (expt 2 (- 2 (round (log2 n))))))
)
0))))
(define (log2 x)
(* (/ 1 (log 2)) (log x)))
(define marker-channel
(xml-in-laml-positional-abstraction 2 0
(lambda (channel marker-letter contents attributes)
(if (ast? marker-letter) (laml-error "Be sure to supply maker-letter as second argument to marker-channel"))
(eliminate-program-change-1 channel
(eliminate-control-change-1 channel #t
(marker-channel-1 channel marker-letter contents ))))))
(define (marker-channel-1 channel marker-letter message-list)
(let ((numbering (consequtive-numbering-by-predicate
(lambda (x) (and (NoteOn? x) (= channel (as-number (ast-attribute x 'channel)))))
message-list 1 0))
)
(append
(list
((treat-marking channel marker-letter) (car message-list) (car numbering))
(Meta 'deltaTime "0"
'type "6"
(string-append marker-letter "-" "0" " " "**"))
)
(map2 (treat-marking channel marker-letter)
(cdr message-list)
(cdr numbering)))
)
)
(define (treat-marking channel marker-letter)
(lambda (mes n)
(if (and (NoteOn? mes) (= channel (as-number (ast-attribute mes 'channel))))
(let ((abs-time (ast-attribute mes 'absTime #f))
(delta-time (ast-attribute mes 'deltaTime #f)))
(Meta (if abs-time 'absTime 'deltaTime) (time-of-message mes)
'type "6"
(string-append marker-letter "-" (as-string n) " " (star-marking-of (marker-level-of-note-on mes)))))
mes)
))
(define (marker-level-of-note-on noteon-ast)
(let* ((note-attr (as-number (ast-attribute noteon-ast 'note)))
(level-number (remainder note-attr 12)))
(cond ((= level-number 0) 0)
((= level-number 1) 0)
((= level-number 2) 1)
((= level-number 3) 1)
((= level-number 4) 2)
((= level-number 5) 3)
((= level-number 6) 3)
((= level-number 7) 4)
((= level-number 8) 4)
((= level-number 9) 5)
((= level-number 10) 5)
((= level-number 11) 6)
)))
(define (star-marking-of level)
(make-string level #\*))
(define marker-silence
(xml-in-laml-positional-abstraction 2 0
(lambda (silence-ticks marker-letter contents attributes)
(marker-silence-1 silence-ticks marker-letter contents ))))
(define (marker-silence-1 silence-ticks marker-letter messages)
(let ((next-marker-number 0)
(first-mes (car messages))
(in-between-messages (butlast (cdr messages)))
(last-mes (last (cdr messages)))
)
(assert-abs-time messages)
(append (list (Meta 'absTime (time-of-message first-mes)
'type "6"
(string-append marker-letter "-" "0" " ")))
(map-n-bites
(bite-while-element-with-accumulation
(lambda (mes sound-frontier-time)
(not (and (> (midi 'absTime mes) sound-frontier-time) (> (- (midi 'absTime mes) sound-frontier-time) silence-ticks))))
(lambda (sound-frontier-time NoteOnMes)
(max sound-frontier-time (+ (midi 'absTime NoteOnMes) (midi 'duration NoteOnMes))))
0
(lambda (x) (not (NoteOn? x))))
(lambda (midi-messages-bite next-marker-number)
(let ((last-mes (last midi-messages-bite)))
(append midi-messages-bite
(list
(Meta 'absTime (time-of-message last-mes)
'type "6"
(string-append marker-letter "-" (as-string next-marker-number) " "))))))
in-between-messages)
(list last-mes))))
(define (take-message-bite-until-silence silence-ticks)
(lambda (messages . rest)
(take-message-bite-until-silence-1 silence-ticks messages #f '())))
(define (take-message-bite-until-silence-1 silence-ticks messages sound-frontier-time res-messages)
(if (null? messages)
(reverse res-messages)
(let ((mes (car messages)))
(cond ((and (boolean? sound-frontier-time) (not sound-frontier-time) (NoteOn? mes))
(take-message-bite-until-silence-1 silence-ticks (cdr messages) (+ (midi 'absTime mes) (midi 'duration mes)) (cons mes res-messages)))
((and (boolean? sound-frontier-time) (not sound-frontier-time) (not (NoteOn? mes)))
(take-message-bite-until-silence-1 silence-ticks (cdr messages) #f (cons mes res-messages)))
((and (NoteOn? mes) (> (midi 'absTime mes) sound-frontier-time) (> (- (midi 'absTime mes) sound-frontier-time) silence-ticks))
(reverse res-messages))
((NoteOn? mes) (take-message-bite-until-silence-1 silence-ticks (cdr messages)
(max sound-frontier-time (+ (midi 'absTime mes) (midi 'duration mes)))
(cons mes res-messages)))
(else
(take-message-bite-until-silence-1 silence-ticks (cdr messages) sound-frontier-time (cons mes res-messages)))))))
(define markup-chords
(xml-in-laml-positional-abstraction 2 0
(lambda (channel marker-letter contents attributes)
(markup-chords-1 channel marker-letter contents))))
(define (markup-chords-1 channel marker-letter messages)
(let ((first-mes (car messages))
(in-between-messages (butlast (cdr messages)))
(last-mes (last (cdr messages)))
(normalized-note-val (lambda (noteon-mes) (remainder (midi 'note noteon-mes) 12)))
)
(assert-abs-time messages)
(append (list (Meta 'absTime (time-of-message first-mes)
'type "6"
(string-append marker-letter "-" "0" " ")))
(step-and-map-n-bites
(bite-while-element-with-accumulation
(lambda (mes prev-chords)
(let ((chord-candidate-list (append prev-chords (list (normalized-note-val mes)))))
(if (< (length chord-candidate-list) 3)
#t
(chord-match? (normalize-chord-list chord-candidate-list)))))
(lambda (chord-candidate-list mes)
(append chord-candidate-list (list (normalized-note-val mes))))
'()
(lambda (x) (not (and (NoteOn? x) (= channel (midi 'channel x)))))
)
(lambda (bite)
(let ((chord-list
(map (lambda (no) (normalized-note-val no))
(filter (lambda (x) (and (NoteOn? x) (= channel (midi 'channel x)))) bite))))
(if (chord-match? (normalize-chord-list chord-list))
(length bite)
-1)))
(lambda (bite i)
(let ((first-mes (first bite))
(last-mes (last bite))
(normalized-chord-list
(normalize-chord-list
(map (lambda (no) (normalized-note-val no))
(filter (lambda (x) (and (NoteOn? x) (= channel (midi 'channel x)))) bite)))))
(append
(list (Meta 'absTime (time-of-message first-mes)
'type "6"
(string-append marker-letter "-" (as-string (- (* i 2) 1))
" " "#" (as-string channel) ": "
"Start of chord: "
(chord-name-of-normalized-note-list normalized-chord-list))))
bite
(list (Meta 'absTime (time-of-message last-mes)
'type "6"
(string-append marker-letter "-" (as-string (* i 2))
" " "#" (as-string channel) ": " "End of chord"))))))
in-between-messages
)
(list last-mes))))
(define map-chords
(xml-in-laml-positional-abstraction 3 0
(lambda (channel max-time-diff f contents attributes)
(map-chords-1 channel max-time-diff f contents))))
(define (map-chords-1 channel max-time-diff f messages)
(let ((normalized-note-val (lambda (noteon-mes) (remainder (midi 'note noteon-mes) 12)))
(relevant-message? (lambda (x) (and (NoteOn? x) (= channel (midi 'channel x)))))
)
(assert-abs-time messages)
(step-and-map-n-bites
(bite-while-element-with-accumulation
(lambda (mes prev-time)
(if prev-time
(if (< (- (time-of-message mes) prev-time) max-time-diff)
#t
#f)
#t))
(lambda (time mes)
(time-of-message mes))
#f
(negate relevant-message?)
)
(lambda (bite)
(let ((chord-list
(map (lambda (no) (normalized-note-val no))
(filter relevant-message? bite))))
(if (chord-match? (normalize-chord-list chord-list))
(length bite)
-1)))
(lambda (bite n)
(let ((normalized-chord-list
(normalize-chord-list
(map (lambda (no) (normalized-note-val no))
(filter relevant-message? bite)))))
(f bite channel n normalized-chord-list (chord-name-of-normalized-note-list normalized-chord-list))))
messages)))
(define (map-chords-1-old channel f messages)
(let ((normalized-note-val (lambda (noteon-mes) (remainder (midi 'note noteon-mes) 12)))
(relevant-message? (lambda (x) (and (NoteOn? x) (= channel (midi 'channel x)))))
)
(assert-abs-time messages)
(step-and-map-n-bites
(bite-while-element-with-accumulation
(lambda (mes prev-chords)
(let ((chord-candidate-list (append prev-chords (list (normalized-note-val mes)))))
(if (< (length chord-candidate-list) 3)
#t
(chord-match? (normalize-chord-list chord-candidate-list)))))
(lambda (chord-candidate-list mes)
(append chord-candidate-list (list (normalized-note-val mes))))
'()
(negate relevant-message?)
)
(lambda (bite)
(let ((chord-list
(map (lambda (no) (normalized-note-val no))
(filter relevant-message? bite))))
(if (chord-match? (normalize-chord-list chord-list))
(length bite)
-1)))
(lambda (bite n)
(let ((normalized-chord-list
(normalize-chord-list
(map (lambda (no) (normalized-note-val no))
(filter relevant-message? bite)))))
(f bite channel n normalized-chord-list (chord-name-of-normalized-note-list normalized-chord-list))))
messages)))
(define (chord-marker bite channel n chord-formula chord-name)
(let ((first-mes (first bite))
(last-mes (last bite))
(marker-letter "C")
)
(append
(list (midi-marker-abs-time
(+ (time-of-message first-mes) 1)
(string-append
"#" (as-string channel) ": "
"Start of chord: " chord-name)
(- (* n 2) 1)
marker-letter)
)
bite
(list (midi-marker-abs-time
(- (time-of-message last-mes) 1)
(string-append
"#" (as-string channel) ": "
"End of chord")
(* n 2)
marker-letter)))))
(define map-sustain-intervals
(xml-in-laml-positional-abstraction 2 0
(lambda (channel f contents attributes)
(map-sustain-intervals-1 channel f contents))))
(define (map-sustain-intervals-1 channel f messages)
(let ((cc-val-comparator (make-comparator
(lambda (cc1 cc2) (< (midi 'value cc1) (midi 'value cc2)))
(lambda (cc1 cc2) (> (midi 'value cc1) (midi 'value cc2)))))
(noice-fn (lambda (x) (not (ControlChange? x 64 channel)))))
(map-n-bites
(bite-while-monotone
cc-val-comparator
noice-fn)
(lambda (messages bite-number)
(f messages bite-number
(cond ((increasing-list-with-noice? cc-val-comparator noice-fn messages) 'increasing)
((decreasing-list-with-noice? cc-val-comparator noice-fn messages) 'decreasing)
(else 'constant))))
messages)))
(define map-bars
(xml-in-laml-positional-abstraction 3 0
(lambda (f ppqn time-signature contents attributes)
(map-bars-1 f ppqn time-signature contents))))
(define (map-bars-1 f ppqn time-signature messages)
(let* ((num (first time-signature))
(denom (second time-signature))
(pulses-per-whole-note (* 4 ppqn))
(ticks-per-bar (to-int (* pulses-per-whole-note (/ (exact->inexact num) (exact->inexact denom)))))
)
(if (null? messages)
'()
(let* ((first-mes (car messages))
(delta-time? (delta-time-message? first-mes))
(abs-time? (abs-time-message? first-mes)))
(cond (abs-time?
(map-bites
(lambda (lst . rest)
(let* ((start-time-first-mes (midi 'absTime (first lst)))
(bar-number (quotient start-time-first-mes ticks-per-bar))
(bar-start-time (* bar-number ticks-per-bar))
(bar-end-time (+ bar-start-time ticks-per-bar))
)
((bite-while-element (lambda (mes) (< (midi 'absTime mes) bar-end-time)) 'sentinel "first") lst)))
(lambda (bite)
(let* ((start-time-first-mes (midi 'absTime (first bite)))
(bar-number (quotient start-time-first-mes ticks-per-bar))
(bar-start-time (* bar-number ticks-per-bar))
(bar-end-time (+ bar-start-time ticks-per-bar))
)
(f bite (+ bar-number 1) bar-start-time (- bar-end-time 1))))
messages)
)
(delta-time?
(map-n-bites
(lambda (lst n)
(let* ((bar-start-time (* (- n 1) ticks-per-bar))
(bar-end-time (+ bar-start-time ticks-per-bar))
)
((bite-while-element-with-accumulation
(lambda (mes absTime) (< (+ absTime (midi 'deltaTime mes)) bar-end-time))
(lambda (absTime mes) (+ absTime (midi 'deltaTime mes)))
bar-start-time
)
lst)))
(lambda (bite n)
(let* ((bar-number (- n 1))
(bar-start-time (* bar-number ticks-per-bar))
(bar-end-time (+ bar-start-time ticks-per-bar))
)
(f bite (+ bar-number 1) bar-start-time (- bar-end-time 1))))
messages)
)
(else (laml-error "map-bars-abs-time-1: Time problem. Should not happen")))))))
(define (n-map f lst noice?)
(map (lambda (el) (if (noice? el) el (f el))) lst))
(define chord-map #f)
(define (chord-name-of chord-entry) (car chord-entry))
(define (chord-notes-of chord-entry) (cdr chord-entry))
(define (do-ensure-chord-map)
(if chord-map
'do-nothing
(set! chord-map
(generate-complete-chord-list basic-chord-list)
)))
(define (normalize-chord-list chord-notes)
(sort-list (remove-duplicates (map (lambda (note-val) (remainder note-val 12)) chord-notes))
<=))
(define (chord-match? normalized-note-list)
(do-ensure-chord-map)
(find-in-list
(lambda (chord-entry)
(equal? normalized-note-list (chord-notes-of chord-entry)))
chord-map))
(define (chord-name-of-normalized-note-list normalized-note-list)
(do-ensure-chord-map)
(let ((search-res (find-in-list
(lambda (chord-entry)
(equal? normalized-note-list (chord-notes-of chord-entry)))
chord-map)))
(if search-res
(chord-name-of search-res)
(list-to-string normalized-note-list ","))))
(define basic-chord-list
'(("major" 0 4 7) ("6" 0 4 7 9) ("7" 0 4 7 10) ("M7" 0 4 7 11) ("Aug" 0 4 8) ("maj 9" 0 2 4 7)
("minor" 0 3 7) ("min6" 0 3 7 9) ("min7" 0 3 7 10)
("dim" 0 3 6) ("dim 6" 0 3 6 9) ("dim 7" 0 3 6 9) ("min 9" 0 2 3 7) ("sus4" 0 5 7) ("sus2" 0 2 7)))
(define extended-chord-list
'(("major" 0 4 7) ("maj 6" 0 4 7 9) ("maj 7" 0 4 7 11) ("maj 9" 0 2 4 7 11) ("maj 11" 0 2 4 5 7 11) ("maj 13" 0 2 4 7 9 11) ("maj b5" 0 4 6) ("maj 7b5" 0 4 6 11) ("maj 9b5" 0 2 4 6 11) ("maj 11b5" 0 2 4 5 6 11)
("maj 13 b5" 0 2 4 6 9 11) ("Aug" 0 4 8) ("maj 7#5" 0 4 8 11) ("maj 9 #5" 0 2 4 8 11) ("maj 11 #5" 0 2 4 5 8 11) ("maj 13 #5" 0 2 4 8 9 11) ("maj/9" 0 2 4 7) ("maj 6/9" 0 2 4 7 9) ("maj 7/6" 0 4 7 9 11)
("maj 7/11" 0 4 5 7 11) ("maj 11/13" 0 2 4 5 7 9 11) ("maj 7b9" 0 1 4 7 11) ("maj 11b9" 0 1 4 5 7 11) ("maj 7#9" 0 3 4 7 11) ("maj 11 #9" 0 3 4 5 7 11) ("maj 9#11" 0 2 4 6 7 11) ("maj 7b5#9" 0 3 4 6 11)
("minor" 0 3 7) ("min6" 0 3 7 9) ("min7" 0 3 7 10) ("min9" 0 2 3 7 10) ("min 11" 0 2 3 5 7 10) ("min 13" 0 2 3 7 9 10) ("diminished" 0 3 6) ("dim 6" 0 3 6 9) ("dim 7" 0 3 6 9) ("minor Major 7" 0 3 7 11)
("min Maj 9" 0 2 3 7 11) ("min Maj 11" 0 2 3 5 7 11) ("min 7 b5 - half dim" 0 3 6 10) ("min9 b5" 0 2 3 6 10) ("min 11b5" 0 2 3 5 6 10) ("min 13 b 5" 0 2 3 6 9 10) ("min 7#5" 0 3 8 10)
("min 9#5" 0 2 3 8 10) ("min 11#5" 0 2 3 5 8 10) ("min/9" 0 2 3 7) ("min 6/9" 0 2 3 7 9) ("min 7/6" 0 3 7 9 10) ("min 7/11" 0 3 5 7 10) ("min 7b 9" 0 1 3 7 10) ("min 7#9" 0 3 3 7 10) ("Dominant 7" 0 4 7 10)
("Dom 9" 0 2 4 7 10) ("Dom 11" 0 2 4 5 7 10) ("Dom 13" 0 2 4 7 9 10) ("Dom 7b5" 0 4 6 10) ("Dom 9b5" 0 2 4 6 10) ("Dom 11b5" 0 2 4 5 6 10) ("Dom 7#5" 0 4 8 10) ("Dom 9#5" 0 2 4 8 10) ("Dom 7/6" 0 4 7 9 10)
("Dom 7/11" 0 4 5 7 10) ("Dom 7b9" 0 1 4 7 10) ("Dom 7#9" 0 3 4 7 10) ("Suspended 4" 0 5 7) ("Sus 6" 0 5 7 9) ("Sus 7" 0 5 7 11) ("Sus 9" 0 2 5 7 11) ("Sus 7b5" 0 5 6 11) ("Sus 7#5" 0 5 8 11)
("Sus/9" 0 2 5 7) ("Sus 6/9" 0 2 5 7 9) ("Maj/4" 0 4 5 7) ("maj 6/4" 0 4 5 7 9) ("maj 7/4" 0 4 5 7 11) ("maj/9/4" 0 2 4 5 7) ("min/4" 0 3 5 7) ("min 6/4" 0 3 5 7 9) ("min 7/4" 0 3 5 7 10) ("dim Sus" 0 5 6)
("dim 6 Sus" 0 5 6 9) ("dim 7 Sus" 0 5 6 9) ("aug Sus" 0 5 8) ("Dom 7 Sus" 0 5 7 10) ("Dom 7/4" 0 4 5 7 11) ("Aug/4" 0 4 5 8)))
(define (generate-complete-chord-list basic-chord-list . optional-parameter-list)
(let ((chord-naming-style (optional-parameter 1 optional-parameter-list 'sharp)))
(let* ((displacements (number-interval 0 11))
(roots-sharp (list "C" "C#" "D" "D#" "E" "F" "F#" "G" "G#" "A" "A#" "B"))
(roots-flat (list "C" "Db" "D" "Eb" "E" "F" "Gb" "G" "Ab" "A" "Bb" "B"))
(roots (if (eq? chord-naming-style 'sharp) roots-sharp roots-flat))
(transpose-chord-formula
(lambda (formula displacement)
(normalize-chord-list (map (lambda (formula-entry) (+ formula-entry displacement)) formula))))
)
(flatten
(map (lambda (displ root)
(map
(lambda (chord-formula)
(let ((chord-name (chord-name-of chord-formula))
(chord-formula (chord-notes-of chord-formula)))
(cons (string-append root " " chord-name)
(transpose-chord-formula chord-formula displ))
)
)
basic-chord-list
)
)
displacements
roots
)))))
(define map-paused-sections
(xml-in-laml-positional-abstraction 3 0
(lambda (f pause-ticks relevance-predicate contents attributes)
(map-paused-sections-1 f pause-ticks relevance-predicate contents))))
(define (map-paused-sections-1 f pause-ticks relevance-predicate messages)
(assert-abs-time messages)
(map-n-bites
(bite-while-element-with-accumulation
(lambda (mes sound-frontier-time)
(not (and (> (midi 'absTime mes) sound-frontier-time) (> (- (midi 'absTime mes) sound-frontier-time) pause-ticks))))
(lambda (sound-frontier-time NoteOnMes)
(max sound-frontier-time (+ (midi 'absTime NoteOnMes) (midi 'duration NoteOnMes))))
0
(lambda (x) (and (ast? x) (or (not (relevance-predicate x)) (not (NoteOn? x)))))
)
(lambda (midi-messages-bite n)
(f n midi-messages-bite))
messages))
(define repeat-messages
(xml-in-laml-positional-abstraction 1 0
(lambda (n contents attributes)
(repeat-messages-1 n contents))))
(define (repeat-messages-1 n flat-message-list)
(if (= n 0)
'()
(append flat-message-list (repeat-messages-1 (- n 1) flat-message-list))))
(define repeat-messages-enforce-periode-length
(xml-in-laml-positional-abstraction 2 0
(lambda (n min-period-length contents attributes)
(repeat-messages-enforce-periode-length-1 n min-period-length contents))))
(define (repeat-messages-enforce-periode-length-1 n min-period-length flat-message-list)
(if (= n 0)
'()
(append (enforce-minimum-message-length min-period-length flat-message-list)
(repeat-messages-enforce-periode-length-1 (- n 1) min-period-length flat-message-list))))
(define surround-by-delta-time-note-list
(xml-in-laml-positional-abstraction 1 0
(lambda (delta-time-note-list contents attributes)
(let ((lgt (length-of-delta-time-midi-list delta-time-note-list)))
(list delta-time-note-list
(time-displace lgt contents)
delta-time-note-list)))))
(define pass-through
(xml-in-laml-abstraction
(lambda (contents attributes)
contents)))
(define map-midi-sections
(xml-in-laml-positional-abstraction 3 0
(lambda (prefix-bite sublist-pred sublist-trans contents attributes)
(map-midi-sections-1 prefix-bite sublist-pred sublist-trans contents))))
(define (map-midi-sections-1 prefix-bite sublist-pred sublist-trans message-list)
(step-and-map-n-bites prefix-bite sublist-pred sublist-trans message-list))
(define time-stretch
(xml-in-laml-positional-abstraction
1 0
(lambda (factor cont attr)
(time-stretch-1 factor cont))))
(define (time-stretch-1 factor message-list)
(map
(lambda (mes-ast)
(if (ast? mes-ast)
(let ((delta-time (ast-attribute mes-ast 'deltaTime #f))
(abs-time (ast-attribute mes-ast 'absTime #f))
(dur (ast-attribute mes-ast 'duration 0))
)
(cond (delta-time
(copy-ast-mutate-attributes mes-ast
'deltaTime (as-int-string (* (as-number delta-time) factor))
'duration (as-int-string (* (as-number dur) factor)) ))
(abs-time
(copy-ast-mutate-attributes mes-ast
'absTime (as-int-string (* (as-number abs-time) factor))
'duration (as-int-string (* (as-number dur) factor)) ))
(else (laml-error "Can only time stretch in deltaTime and absTime mode")) ))
mes-ast))
message-list))
(define time-adapt-to
(xml-in-laml-positional-abstraction
1 0
(lambda (new-length cont attr)
(time-adapt-to-1 new-length cont))))
(define (time-adapt-to-1 new-length message-list)
(let* ((old-length (total-length-of-message-list message-list))
(factor (/ new-length old-length)))
(time-stretch-1 factor message-list)))
(define time-displace
(xml-in-laml-positional-abstraction
1 0
(lambda (amount cont attr)
(time-displace-1 amount cont))))
(define (time-displace-1 amount message-list)
(cond ((null? message-list) '())
((abs-time-message? (first message-list))
(map
(lambda (mes-ast)
(if (ast? mes-ast)
(let ((abs-time (ast-attribute mes-ast 'absTime #f))
(delta-time (ast-attribute mes-ast 'deltaTime #f))
)
(cond (abs-time
(copy-ast-mutate-attributes mes-ast
'absTime (as-int-string (+ (as-number abs-time) amount))))
(delta-time
mes-ast)
(else (laml-error "time-displace: Problems!"))))
mes-ast))
message-list))
((delta-time-message? (first message-list))
(let* ((first-mes (first message-list))
(first-delta-time (ast-attribute first-mes 'deltaTime #f))
(rest-messages (cdr message-list)))
(cons
(copy-ast-mutate-attributes first-mes 'deltaTime (as-int-string (+ (as-number first-delta-time) amount)))
rest-messages)))
(else (laml-error "time-displace-1: First message must reveal time mode."))))
(define time-displace-channels
(xml-in-laml-positional-abstraction
2 0
(lambda (channel-list amount cont attr)
(time-displace-channels-1 channel-list amount cont))))
(define (time-displace-channels-1 ch-list amount message-list)
(map
(lambda (mes-ast)
(if (ast? mes-ast)
(let ((channel (ast-attribute mes-ast 'channel #f)))
(if channel
(let ((channel-num (as-number channel)))
(if (member channel-num ch-list)
(let ((abs-time (ast-attribute mes-ast 'absTime #f))
(delta-time (ast-attribute mes-ast 'deltaTime #f)))
(cond (abs-time
(copy-ast-mutate-attributes mes-ast
'absTime (as-int-string (+ (as-number abs-time) amount))))
(delta-time
mes-ast)
(else (laml-error "time-displace-channels: Problems!"))))
mes-ast))
mes-ast))
mes-ast))
message-list))
(define time-displace-channels-with-scaling
(xml-in-laml-positional-abstraction
3 0
(lambda (channel-list amount scaling-fn cont attr)
(time-displace-channels-with-scaling-1 channel-list amount scaling-fn cont))))
(define (time-displace-channels-with-scaling-1 ch-list amount scaling-fn message-list)
(let* ((number-list (consequtive-numbering-by-predicate (ast-with-channel-pred ch-list) message-list 1 0))
(number-list-count (length (filter (lambda (x) (> x 0)) number-list)))
(max-n number-list-count)
)
(map
(lambda (mes-ast n)
(if (ast? mes-ast)
(let ((channel (ast-attribute mes-ast 'channel #f)))
(if channel
(let ((channel-num (as-number channel)))
(if (member channel-num ch-list)
(let ((abs-time (ast-attribute mes-ast 'absTime #f))
(delta-time (ast-attribute mes-ast 'deltaTime #f))
(scaled-amount (* amount (scaling-fn (/ n max-n))))
)
(if (= n 0) (laml-error "time-displace-channels-with-scaling-1: Should not happen"))
(cond (abs-time
(copy-ast-mutate-attributes mes-ast
'absTime (as-int-string (+ (as-number abs-time) scaled-amount))))
(delta-time
(laml-error "time-displace-channels-with-scaling-1: Only supports absTime"))
(else (laml-error "time-displace-channels: Problems!"))))
mes-ast))
mes-ast))
mes-ast))
message-list
number-list)))
(define (ast-with-channel-pred ch-list)
(lambda (x)
(and (ast? x)
(let ((ch (ast-attribute x 'channel #f)))
(and ch (member (as-number ch) ch-list))))))
(define quantize
(xml-in-laml-positional-abstraction
3 0
(lambda (channel q pulses-per-quarter-note cont attr)
(cond ((abs-time-sequence? cont) (quantize-abs-timing channel q pulses-per-quarter-note cont))
((delta-time-sequence? cont)
(abs-time-message-list-to-delta-timing
(quantize-abs-timing
channel q pulses-per-quarter-note (delta-time-message-list-to-abs-timing cont 0))
0)
)
(else (laml-error "quantize: Problems determining absTime or deltaTime mode of sequence"))))))
(define (quantize-abs-timing c q pulses-per-quarter-note message-list)
(map
(lambda (mes-ast)
(if (and (ast? mes-ast) )
(let ((channel (ast-attribute mes-ast 'channel #f)))
(if (and channel (= (as-number channel) c))
(let ((abs-time (ast-attribute mes-ast 'absTime #f)))
(if (not abs-time)
(laml-error "Can only quantize in absTime mode"))
(let ((time-interval (time-interval-of-note q pulses-per-quarter-note)))
(copy-ast-mutate-attributes mes-ast
'absTime (quantize-int (as-number abs-time) time-interval))))
mes-ast))
mes-ast))
message-list))
(define quantize-channels
(xml-in-laml-positional-abstraction
3 0
(lambda (channel-list q pulses-per-quarter-note cont attr)
(cond ((abs-time-sequence? cont) (quantize-channels-abs-timing channel-list q pulses-per-quarter-note cont))
((delta-time-sequence? cont)
(abs-time-message-list-to-delta-timing
(quantize-channels-abs-timing
channel-list q pulses-per-quarter-note (delta-time-message-list-to-abs-timing cont 0))
0)
)
(else (laml-error "quantize-channels: Problems determining absTime or deltaTime mode of sequence"))))))
(define (quantize-channels-abs-timing c-lst q pulses-per-quarter-note message-list)
(map
(lambda (mes-ast)
(if (and (ast? mes-ast))
(let ((channel (ast-attribute mes-ast 'channel #f)))
(if (and channel (member (as-number channel) c-lst))
(let ((abs-time (ast-attribute mes-ast 'absTime #f)))
(if (not abs-time)
(laml-error "Can only quantize in absTime mode"))
(let ((time-interval (time-interval-of-note q pulses-per-quarter-note)))
(copy-ast-mutate-attributes mes-ast
'absTime (quantize-int (as-number abs-time) time-interval))))
mes-ast))
mes-ast))
message-list))
(define distribute-even
(xml-in-laml-positional-abstraction
1 0
(lambda (channel cont attr)
(distribute-even-1 channel cont))))
(define (distribute-even-1 channel message-list)
(ensure-all-abstime-in! "distribute-even" message-list)
(let* ((relevante-note-on-list
(filter (lambda (x)
(and (ast? x) (equal? "NoteOn" (ast-element-name x)) (= (as-number (ast-attribute x 'channel #f)) channel)))
message-list))
(number-of-relevant-notes (length relevante-note-on-list ))
)
(if (>= number-of-relevant-notes 3)
(let* ((abs-time-first (as-number (ast-attribute (first relevante-note-on-list) 'absTime #f)))
(abs-time-last (as-number (ast-attribute (last relevante-note-on-list) 'absTime #f)))
(distance (/ (- abs-time-last abs-time-first) (- number-of-relevant-notes 1)))
)
(distribute-even-2 channel message-list distance 0 abs-time-first) )
message-list)))
(define (distribute-even-2 channel message-list distance i start-time)
(cond ((null? message-list) '())
((and (ast? (car message-list)) (equal? "NoteOn" (ast-element-name (car message-list))) (= (as-number (ast-attribute (car message-list) 'channel #f)) channel))
(cons (copy-ast-mutate-attributes (car message-list) 'absTime (as-int-string (to-int (+ (* i distance) start-time))))
(distribute-even-2 channel (cdr message-list) distance (+ i 1) start-time)))
(else (cons (car message-list) (distribute-even-2 channel (cdr message-list) distance i start-time)))))
(define (quantize-int i factor)
(let* ((half-factor (/ factor 2))
(rem (remainder i factor))
(quot (quotient i factor))
(grid-point (* quot factor))
)
(if (<= rem half-factor)
grid-point
(+ grid-point factor))))
(define (time-interval-of-note note-value pulses-per-quarter-note)
(cond ((= 1 note-value) (* 4 pulses-per-quarter-note))
((= 2 note-value) (* 2 pulses-per-quarter-note))
((= 4 note-value) pulses-per-quarter-note)
((= 8 note-value) (/ pulses-per-quarter-note 2))
((= 16 note-value) (/ pulses-per-quarter-note 4))
((= 32 note-value) (/ pulses-per-quarter-note 8))
((= 64 note-value) (/ pulses-per-quarter-note 16))
((= 128 note-value) (/ pulses-per-quarter-note 32))
(else (laml-error "time-interval-of-note: note-value must be a power of 2 in between 1 and 128"))))
(define (calculate-note-in-between note-ast-1 note-ast-2)
(let ((note-val-1 (as-number (ast-attribute note-ast-1 'note)))
(note-val-2 (as-number (ast-attribute note-ast-2 'note)))
(abs-time-1 (as-number (ast-attribute note-ast-1 'absTime #f)))
(abs-time-2 (as-number (ast-attribute note-ast-2 'absTime #f)))
(channel-1 (as-number (ast-attribute note-ast-1 'channel)))
(channel-2 (as-number (ast-attribute note-ast-2 'channel)))
(velocity-1 (as-number (ast-attribute note-ast-1 'velocity)))
(velocity-2 (as-number (ast-attribute note-ast-2 'velocity)))
(duration-1 (as-number (ast-attribute note-ast-1 'duration)))
(duration-2 (as-number (ast-attribute note-ast-2 'duration)))
)
(if (or (not abs-time-1) (not abs-time-2) )
(laml-error "The function interpolate can only be used with asbTime"))
(if (> (abs (- note-val-1 note-val-2)) 1)
(list (NoteOn 'absTime (as-int-string (to-int (+ abs-time-1 (/ (- abs-time-2 abs-time-1) 2))))
'channel channel-1
'note (as-int-string (to-int (+ note-val-1 (/ (- note-val-2 note-val-1) 2))))
'velocity velocity-1
'duration (as-int-string (to-int (/ duration-1 2)))))
'())))
(define same-time-transform
(xml-in-laml-positional-abstraction 2 0
(lambda (channels transformer contents attributes)
(same-time-transform-1 channels transformer contents))))
(define (same-time-transform-1 channels transformer message-list)
(same-time-transform-2 channels transformer message-list '() '()))
(define (same-time-transform-2 channels transformer message-list same-time-lst result-lst)
(if (null? message-list)
(reverse (append same-time-lst result-lst))
(let* ((mes (first message-list))
(absTime? (ast-attribute mes 'absTime #f))
(same-mes (if (not (null? same-time-lst)) (first same-time-lst) #f))
(same-mes-ch (if same-mes (ast-attribute same-mes 'channel #f) #f))
)
(if (not absTime?) (laml-error "Same time transformation must occur in pure abs-time mode."))
(cond
((and same-mes
(ast? mes)
(equal? (ast-attribute same-mes 'absTime) (ast-attribute mes 'absTime))
same-mes-ch (member (as-number same-mes-ch) channels))
(same-time-transform-2 channels transformer (cdr message-list) (cons mes same-time-lst) result-lst))
((and (ast? mes) (>= (length same-time-lst) 2))
(same-time-transform-2 channels transformer (cdr message-list) (list mes)
(append (maybe-transformer transformer (filter (NoteOnCh? channels) same-time-lst)) (filter (negate (NoteOnCh? channels)) same-time-lst) result-lst)))
((and (not (ast? mes)) (>= (length same-time-lst) 2))
(same-time-transform-2 channels transformer (cdr message-list) '()
(append (maybe-transformer transformer (filter (NoteOnCh? channels) same-time-lst)) (filter (negate (NoteOnCh? channels)) same-time-lst) result-lst)))
((and (ast? mes) same-mes (< (length same-time-lst) 2))
(same-time-transform-2 channels transformer (cdr message-list) (list mes) (append same-time-lst result-lst)))
((and (not (ast? mes)) same-mes (< (length same-time-lst) 2))
(same-time-transform-2 channels transformer (cdr message-list) '() (append same-time-lst result-lst)))
((ast? mes)
(same-time-transform-2 channels transformer (cdr message-list) (list mes) result-lst))
(else
(same-time-transform-2 channels transformer (cdr message-list) same-time-lst result-lst))))))
(define (maybe-transformer transformer lst)
(if (>= (length lst) 2)
(transformer lst)
lst))
(define cut-at-time
(xml-in-laml-positional-abstraction
2 0
(lambda (abs-cut-time channel-list cont attr)
(cut-at-time-1 abs-cut-time channel-list cont))))
(define (cut-at-time-1 abs-cut-time channel-list-0 message-list)
(ensure-all-abstime-in! "cut-at-time-1" message-list)
(let ((channel-list (if (and (boolean? channel-list-0) channel-list-0) (number-interval 1 16) channel-list-0)))
(cut-at-time-2 abs-cut-time channel-list message-list '())))
(define (cut-at-time-2 abs-cut-time channel-list message-list res-lst)
(if (null? message-list)
(reverse res-lst)
(let* ((m (car message-list))
(m-in-relevant-channel (and (channel-message? m) (member (midi 'channel m) channel-list))))
(cond ((and m-in-relevant-channel (not (NoteOn? m)) (> (midi 'absTime m) abs-cut-time))
(cut-at-time-2 abs-cut-time channel-list (cdr message-list) res-lst))
((and m-in-relevant-channel (NoteOn? m) (> (midi 'absTime m) abs-cut-time))
(cut-at-time-2 abs-cut-time channel-list (cdr message-list) res-lst))
((and m-in-relevant-channel (NoteOn? m) (<= (midi 'absTime m) abs-cut-time) (> (+ (midi 'absTime m) (midi 'duration m)) abs-cut-time))
(cut-at-time-2 abs-cut-time channel-list (cdr message-list)
(cons (copy-ast-mutate-attributes m 'duration (- abs-cut-time (midi 'absTime m))) res-lst)))
(else (cut-at-time-2 abs-cut-time channel-list (cdr message-list) (cons m res-lst)))
))))
(define octave
(xml-in-laml-positional-abstraction
2 0
(lambda (ch n cont attr)
(octave-1 ch n cont))))
(define (octave-1 c n message-list)
(map
(lambda (mes-ast)
(if (and (ast? mes-ast) (or (equal? "NoteOn" (ast-element-name mes-ast)) (equal? "NoteOff" (ast-element-name mes-ast))))
(let ((channel (ast-attribute mes-ast 'channel #f)))
(if (and channel (= (as-number channel) c))
(let* ((old-note (as-number (ast-attribute mes-ast 'note)))
(new-note (+ old-note (* 12 n))))
(if (or (> new-note 127) (< new-note 0))
(laml-error "Octave underflow or overflow" (ast-attribute mes-ast 'info) new-note))
(copy-ast-mutate-attributes mes-ast 'note new-note))
mes-ast))
mes-ast))
message-list))
(define interpolate
(xml-in-laml-positional-abstraction
1 0
(lambda (channel cont attr)
(interpolate-1 channel cont #f))))
(define (interpolate-1 ch message-list prev-ast)
(cond ((and (null? message-list) prev-ast) (list prev-ast))
((and (null? message-list) (not prev-ast)) '())
((and (ast? (car message-list))
(equal? "NoteOn" (ast-element-name (car message-list)))
(= (as-number (ast-attribute (car message-list) 'channel #f)) ch))
(if (not prev-ast)
(interpolate-1 ch (cdr message-list) (car message-list))
(let* ((first prev-ast)
(second (car message-list))
(note-in-between-list (calculate-note-in-between first second))
)
(cons
(cons first note-in-between-list)
(interpolate-1 ch (cdr message-list) second)
))))
(else (cons (car message-list)
(interpolate-1 ch (cdr message-list) prev-ast))) ))
(define transpose
(xml-in-laml-positional-abstraction 1 0
(lambda (amount contents attributes)
(transpose-1 amount contents))))
(define (transpose-1 amount message-list)
(map
(lambda (mes-ast)
(if (and (ast? mes-ast) (or (equal? "NoteOn" (ast-element-name mes-ast)) (equal? "NoteOff" (ast-element-name mes-ast))))
(let* ((old-note (as-number (ast-attribute mes-ast 'note)))
(new-note (+ old-note amount)))
(copy-ast-mutate-attributes mes-ast 'note new-note))
mes-ast))
message-list))
(define transpose-channels
(xml-in-laml-positional-abstraction 2 0
(lambda (channel-list amount contents attributes)
(transpose-channels-1 channel-list amount contents))))
(define (transpose-channels-1 ch-list amount message-list)
(map
(lambda (mes-ast)
(if (and (ast? mes-ast) (or (equal? "NoteOn" (ast-element-name mes-ast)) (equal? "NoteOff" (ast-element-name mes-ast))))
(let ((channel (ast-attribute mes-ast 'channel #f)))
(if channel
(if (member (as-number channel) ch-list)
(let* ((old-note (as-number (ast-attribute mes-ast 'note)))
(new-note (+ old-note amount)))
(copy-ast-mutate-attributes mes-ast 'note new-note))
mes-ast)
mes-ast))
mes-ast))
message-list))
(define map-notes-in-channels
(xml-in-laml-positional-abstraction 2 0
(lambda (note-map channel-list contents attributes)
(map-notes-in-channels-1 note-map channel-list contents))))
(define (map-notes-in-channels-1 note-map channel-list message-list)
(let ((note-map-numbers (map (lambda (map-entry)
(let ((source (car map-entry))
(dest (cadr map-entry)))
(list (number-of-note-name (upcase-string (as-string source))) (number-of-note-name (upcase-string (as-string dest))))))
note-map)))
(letrec ((note-mapper (lambda (source-note-value)
(let ((map-res (find-in-list (lambda (entry) (= (first entry) (remainder source-note-value 12))) note-map-numbers)))
(if map-res (+ (* (quotient source-note-value 12) 12) (second map-res)) #f)))))
(map-notes-in-channels-2 note-mapper channel-list message-list '())
)
)
)
(define (map-notes-in-channels-2 note-mapper channel-list message-list res-lst)
(cond ((null? message-list) (reverse res-lst))
(else (let ((message (car message-list)))
(if (ast? message)
(if (NoteOn? message)
(if (member (as-number (ast-attribute message 'channel)) channel-list)
(let* ((target-note-value (note-mapper (as-number (ast-attribute message 'note)))))
(if target-note-value
(map-notes-in-channels-2 note-mapper channel-list (cdr message-list)
(cons (copy-ast-mutate-attributes message 'note target-note-value) res-lst))
(map-notes-in-channels-2 note-mapper channel-list (cdr message-list)
(cons (copy-ast-mutate-attributes message 'velocity "1") res-lst))
)
)
(map-notes-in-channels-2 note-mapper channel-list (cdr message-list) (cons message res-lst)))
(map-notes-in-channels-2 note-mapper channel-list (cdr message-list) (cons message res-lst)))
(map-notes-in-channels-2 note-mapper channel-list (cdr message-list) res-lst)
)
)
)
)
)
(define (fade-out . message-list)
(fade-out-1 message-list))
(define (fade-out-1 message-list)
(let ((lgt (length message-list)))
(map
(lambda (mes-ast i)
(if (equal? (ast-element-name mes-ast) "NoteOn")
(copy-ast-mutate-attributes mes-ast
'velocity (fade-velocity lgt i (as-number (ast-attribute mes-ast 'velocity))))
mes-ast))
message-list
(number-interval 1 lgt))))
(define (fade-out-channels channel-list . message-list)
(fade-out-channel-1 channel-list message-list))
(define (fade-out-channel-1 channel-list message-list)
(let ((lgt (length message-list)))
(map
(lambda (mes-ast i)
(let ((channel (ast-attribute mes-ast 'channel #f)))
(if channel
(let ((channel-num (as-number channel)))
(if (member channel-num channel-list)
(if (equal? (ast-element-name mes-ast) "NoteOn")
(copy-ast-mutate-attributes mes-ast
'velocity (fade-velocity lgt i (as-number (ast-attribute mes-ast 'velocity))))
mes-ast)
mes-ast))
mes-ast)))
message-list
(number-interval 1 lgt))))
(define (fade-velocity n i input-velocity)
(as-int-string (between 0 127 (to-int (/ (* input-velocity (- n i)) n)))))
(define add-to-velocity
(xml-in-laml-positional-abstraction
2 0
(lambda (channel amount cont attr)
(add-to-velocity-1 channel amount cont))))
(define (add-to-velocity-1 channel amount message-list)
(map
(lambda (mes-ast)
(if (and (ast? mes-ast) (equal? (ast-element-name mes-ast) "NoteOn") (= (as-number (ast-attribute mes-ast 'channel)) channel))
(let ((velocity (ast-attribute mes-ast 'velocity #f)))
(cond (velocity
(copy-ast-mutate-attributes mes-ast
'velocity (as-int-string (between 0 127 (+ (as-number velocity) amount)))))
(else (laml-error "Cannot find velocity of NoteOn message. Should not happen"))))
mes-ast))
message-list))
(define eliminate-breaks
(xml-in-laml-positional-abstraction 1 0
(lambda (channel contents attributes)
(eliminate-breaks-1 channel contents))))
(define (eliminate-breaks-1 channel messages)
(let* ((channel-messages (filter (lambda (x) (and (ast? x) (NoteOn? x) (= channel (midi 'channel x)))) messages))
(abs-time-list (map (lambda (noteon-ast) (midi 'absTime noteon-ast)) channel-messages))
(abs-time-diff-list (map2 (lambda (at1 at2) (- at1 at2)) (cdr abs-time-list) abs-time-list)))
(adjust-duration channel messages abs-time-diff-list '())))
(define (adjust-duration channel messages abs-time-diff-list res-messages)
(cond ((null? messages) (reverse res-messages))
((not (ast? (car messages))) (adjust-duration channel (cdr messages) abs-time-diff-list res-messages))
((not (has-ast-attribute? (car messages) 'channel)) (adjust-duration channel (cdr messages) abs-time-diff-list (cons (car messages) res-messages)))
((and (NoteOn? (car messages)) (= channel (midi 'channel (car messages))) (not (null? abs-time-diff-list)))
(adjust-duration channel
(cdr messages)
(cdr abs-time-diff-list)
(cons (copy-ast-mutate-attributes (car messages) 'duration (max (midi 'duration (car messages)) (car abs-time-diff-list)))
res-messages)))
(else (adjust-duration channel (cdr messages) abs-time-diff-list (cons (car messages) res-messages)))))
(define legato-in-channel
(xml-in-laml-positional-abstraction 1 0
(lambda (channel contents attributes)
(let ((time-slack-delta (as-number (defaulted-get-prop 'time-slack-delta attributes 20)))
(strict (as-boolean (defaulted-get-prop 'strict attributes #f)))
(offset (as-number (defaulted-get-prop 'offset attributes 0)))
(max-tie-span (defaulted-get-prop 'max-tie-span attributes #f))
)
(legato-in-channel-1 channel time-slack-delta strict max-tie-span offset contents)))))
(define (legato-in-channel-1 channel time-slack-delta strict max-tie-span offset message-list)
(let ((message-list-1 (filter ast? message-list)))
(cond ((abs-time-sequence? message-list-1)
(legato-in-channel-abs-time channel time-slack-delta strict max-tie-span offset message-list-1 '() 0 '()))
((delta-time-sequence? message-list-1)
(if max-tie-span (laml-error "legato-in-channel-1: max-timespan cannot be used in delta time mode"))
(legato-in-channel-delta-time channel time-slack-delta strict offset message-list-1 '() 0 '() 0))
(else (laml-error "legato-in-channel-1: Either pure absTime or pure deltaTime mode is expected")))))
(define (legato-in-channel-delta-time channel time-slack-delta strict offset message-list pending-message-list t0 res-list tcur)
(cond ((null? message-list)
(append (reverse res-list) (reverse pending-message-list)))
(else (let* ((first-mes (first message-list))
(time-first (+ tcur (as-number (ast-attribute first-mes 'deltaTime)))))
(display-message (length pending-message-list) "note = " (midi 'note first-mes) "time-first = " time-first "t0 = " t0 "tcur = " tcur)
(cond
((and (null? pending-message-list)
(or (not (NoteOn? first-mes))
(and (NoteOn? first-mes) (not (= channel (as-number (ast-attribute first-mes 'channel)))))))
(legato-in-channel-delta-time channel time-slack-delta strict offset (cdr message-list) '() 0 (cons first-mes res-list)
(+ tcur (as-number (ast-attribute first-mes 'deltaTime)))))
((and (null? pending-message-list)
(and (NoteOn? first-mes) (= channel (as-number (ast-attribute first-mes 'channel)))))
(legato-in-channel-delta-time channel time-slack-delta strict offset (cdr message-list) (list first-mes)
time-first res-list (+ tcur (as-number (ast-attribute first-mes 'deltaTime)))))
((and (not (null? pending-message-list))
(or (not (NoteOn? first-mes))
(and (NoteOn? first-mes) (not (= channel (as-number (ast-attribute first-mes 'channel)))))
(and (NoteOn? first-mes) (= channel (as-number (ast-attribute first-mes 'channel))) (<= (- time-first t0) time-slack-delta))))
(legato-in-channel-delta-time channel time-slack-delta strict offset (cdr message-list) (cons first-mes pending-message-list) t0 res-list
(+ tcur (as-number (ast-attribute first-mes 'deltaTime)))))
(else
(legato-in-channel-delta-time channel time-slack-delta strict offset (cdr message-list) (list first-mes)
time-first
(let* ((note-to-modify (last pending-message-list))
(note-now-modified
(copy-ast-mutate-attributes
note-to-modify 'duration (cond (strict (max 0 (+ offset (- time-first t0))))
(else (max 0 (+ offset (max (as-number (ast-attribute note-to-modify 'duration))
(- time-first t0))))))))
(other-pendings-messages (butlast pending-message-list)))
(append (append other-pendings-messages (list note-now-modified)) res-list))
(+ tcur (as-number (ast-attribute first-mes 'deltaTime))))) )))))
(define (legato-in-channel-abs-time channel time-slack-delta strict max-tie-span offset message-list pending-message-list t0 res-list)
(cond ((null? message-list)
(append (reverse res-list) (reverse pending-message-list)))
(else (let* ((first-mes (first message-list))
(time-first (as-number (ast-attribute first-mes 'absTime))))
(display-message (length pending-message-list) " " (midi 'note first-mes))
(cond
((and (null? pending-message-list)
(or (not (NoteOn? first-mes))
(and (NoteOn? first-mes) (not (= channel (as-number (ast-attribute first-mes 'channel)))))))
(legato-in-channel-abs-time channel time-slack-delta strict max-tie-span offset (cdr message-list) '() 0 (cons first-mes res-list)))
((and (null? pending-message-list)
(and (NoteOn? first-mes) (= channel (as-number (ast-attribute first-mes 'channel)))))
(legato-in-channel-abs-time channel time-slack-delta strict max-tie-span offset (cdr message-list) (list first-mes)
(as-number (ast-attribute first-mes 'absTime)) res-list))
((and (not (null? pending-message-list))
(or (not (NoteOn? first-mes))
(and (NoteOn? first-mes) (not (= channel (as-number (ast-attribute first-mes 'channel)))))
(and (NoteOn? first-mes) (= channel (as-number (ast-attribute first-mes 'channel))) (<= (- time-first t0) time-slack-delta))))
(legato-in-channel-abs-time channel time-slack-delta strict max-tie-span offset (cdr message-list) (cons first-mes pending-message-list) t0 res-list))
(else
(legato-in-channel-abs-time channel time-slack-delta strict max-tie-span offset (cdr message-list) (list first-mes)
(as-number (ast-attribute first-mes 'absTime))
(append
(map (lambda (pending-mes)
(if (and (NoteOn? pending-mes) (= channel (as-number (ast-attribute pending-mes 'channel))))
(if (or (not max-tie-span)
(and max-tie-span
(<= (- (as-number (ast-attribute first-mes 'absTime))
(as-number (ast-attribute pending-mes 'absTime)))
(as-number max-tie-span))))
(copy-ast-mutate-attributes pending-mes
'duration
(cond (strict (max 0 (+ offset (- (as-number (ast-attribute first-mes 'absTime))
(as-number (ast-attribute pending-mes 'absTime))))))
(else (max 0 (+ offset (max (as-number (ast-attribute pending-mes 'duration))
(- (as-number (ast-attribute first-mes 'absTime))
(as-number (ast-attribute pending-mes 'absTime)))))))))
pending-mes)
pending-mes))
pending-message-list)
res-list))))))))
(define pan-flow
(xml-in-laml-positional-abstraction 3 0
(lambda (channel pan-from pan-to contents attributes)
(pan-flow-1 channel pan-from pan-to contents))))
(define (pan-flow-1 ch pan-from pan-to message-list)
(let* ((pan-diff (abs (- pan-to pan-from)))
(number-of-note-ons
(length (filter (lambda (x) (and (ast? x) (equal? "NoteOn" (ast-element-name x)) (= ch (as-number (ast-attribute x 'channel -1))))) message-list)))
(pan-step (if (> number-of-note-ons 1)
(if (< pan-from pan-to)
(/ pan-diff (- number-of-note-ons 1))
(- (/ pan-diff (- number-of-note-ons 1))))
#f))
)
(if pan-step
(pan-flow-2 ch pan-from pan-to pan-step 0 message-list)
message-list)))
(define (pan-flow-2 ch pan-from pan-to pan-step i message-list)
(cond ((null? message-list) '())
((and (ast? (car message-list)) (equal? "NoteOn" (ast-element-name (car message-list))))
(let* ((mes-ast (car message-list))
(channel (ast-attribute mes-ast 'channel #f)))
(if (and channel (= (as-number channel) ch))
(cons
(list
(ControlChange 'deltaTime "0" 'channel ch 'control "10" 'value (as-int-string (between 0 127 (to-int (+ pan-from (* i pan-step))))))
mes-ast)
(pan-flow-2 ch pan-from pan-to pan-step (+ i 1) (cdr message-list)))
(cons mes-ast (pan-flow-2 ch pan-from pan-to pan-step i (cdr message-list))))))
(else
(cons (car message-list) (pan-flow-2 ch pan-from pan-to pan-step i (cdr message-list))))))
(define pan-left-right
(xml-in-laml-positional-abstraction 2 0
(lambda (channel pan-level contents attributes)
(pan-left-right-1 channel pan-level contents))))
(define (pan-left-right-1 ch pan-level message-list)
(letrec (
(arc-pan (lambda (pan-value)
(acos (/ (- pan-value 64) 64))))
(pan-fn (lambda (x)
(+ 64 (* 64 (cos x)))))
(interval-of-reals (lambda (lower upper step)
(if (< lower upper)
(cons lower (interval-of-reals (+ lower step) upper step))
'())))
(interval-of-n-reals (lambda (lower upper n)
(let ((step (/ (- upper lower) n)))
(interval-of-reals lower upper step))))
(PI 3.14159)
)
(let* ((number-of-note-ons
(length (filter (lambda (x) (and (ast? x) (equal? "NoteOn" (ast-element-name x)) (= ch (as-number (ast-attribute x 'channel -1))))) message-list)))
(ap (arc-pan pan-level))
(pan-value-list (map (lambda (r) (pan-fn r)) (interval-of-n-reals ap (+ ap (* 2 PI)) number-of-note-ons)))
(pan-message-list
(map (lambda (pan-val)
(ControlChange 'deltaTime "0" 'channel ch 'control "10" 'value (as-int-string (between 0 127 (to-int pan-val)))))
pan-value-list))
)
(pan-left-right-2 ch pan-level pan-message-list message-list))))
(define (pan-left-right-2 ch pan-level pan-message-list message-list)
(cond ((null? message-list) (list
(ControlChange 'deltaTime "0" 'channel ch 'control "10" 'value pan-level)))
((and (ast? (car message-list)) (equal? "NoteOn" (ast-element-name (car message-list))))
(let* ((mes-ast (car message-list))
(channel (ast-attribute mes-ast 'channel #f)))
(if (and channel (= (as-number channel) ch))
(cons
(list
(if (not (null? pan-message-list)) (car pan-message-list) '())
mes-ast)
(pan-left-right-2 ch pan-level (cdr pan-message-list) (cdr message-list)))
(cons mes-ast (pan-left-right-2 ch pan-level pan-message-list (cdr message-list))))))
(else
(cons (car message-list) (pan-left-right-2 ch pan-level pan-message-list (cdr message-list))))))
(define channel-volume-flow
(xml-in-laml-positional-abstraction 3 0
(lambda (channel channel-volume-from channel-volume-to contents attributes)
(channel-volume-flow-1 channel channel-volume-from channel-volume-to contents))))
(define (channel-volume-flow-1 ch channel-volume-from channel-volume-to message-list)
(let* ((channel-volume-diff (abs (- channel-volume-to channel-volume-from)))
(number-of-note-ons
(length (filter (lambda (x) (and (ast? x) (equal? "NoteOn" (ast-element-name x)) (= ch (as-number (ast-attribute x 'channel -1))))) message-list)))
(channel-volume-step (if (> number-of-note-ons 1)
(if (< channel-volume-from channel-volume-to)
(/ channel-volume-diff (- number-of-note-ons 1))
(- (/ channel-volume-diff (- number-of-note-ons 1))))
#f))
)
(if channel-volume-step
(channel-volume-flow-2 ch channel-volume-from channel-volume-to channel-volume-step 0 message-list)
message-list)))
(define (channel-volume-flow-2 ch channel-volume-from channel-volume-to channel-volume-step i message-list)
(cond ((null? message-list) '())
((and (ast? (car message-list)) (equal? "NoteOn" (ast-element-name (car message-list))))
(let* ((mes-ast (car message-list))
(channel (ast-attribute mes-ast 'channel #f)))
(if (and channel (= (as-number channel) ch))
(cons
(list
(ControlChange 'deltaTime "0" 'channel ch 'control "7" 'value (as-int-string (between 0 127 (to-int (+ channel-volume-from (* i channel-volume-step))))))
mes-ast)
(channel-volume-flow-2 ch channel-volume-from channel-volume-to channel-volume-step (+ i 1) (cdr message-list)))
(cons mes-ast (channel-volume-flow-2 ch channel-volume-from channel-volume-to channel-volume-step i (cdr message-list))))))
(else
(cons (car message-list) (channel-volume-flow-2 ch channel-volume-from channel-volume-to channel-volume-step i (cdr message-list))))))
(define no-sustain
(xml-in-laml-positional-abstraction 1 0
(lambda (channel contents attributes)
(no-sustain-1 channel contents))))
(define (no-sustain-1 ch message-list)
(eliminate-control-change-1 ch 64 message-list))
(define eliminate-control-change
(xml-in-laml-positional-abstraction 2 0
(lambda (channel control contents attributes)
(eliminate-control-change-1 channel control contents))))
(define (eliminate-control-change-1 ch cntrl message-list)
(eliminate-midi-null-events
(map
(lambda (mes-ast)
(if (and (ast? mes-ast)
(equal? (ast-element-name mes-ast) "ControlChange")
(if (and (boolean? cntrl) cntrl) #t (= cntrl (as-number (ast-attribute mes-ast 'control))))
(if (and (boolean? ch) ch) #t (= ch (as-number (ast-attribute mes-ast 'channel))))
)
(let ((abs-time (ast-attribute mes-ast 'absTime #f))
(delta-time (ast-attribute mes-ast 'deltaTime #f)))
(cond (abs-time
(midi-null-event-abs-time (ast-attribute mes-ast 'absTime)))
(delta-time
(midi-null-event-delta-time (ast-attribute mes-ast 'deltaTime)))
(else (laml-error "eliminate-control-change-1: Not absTime and not deltaTime. Should not happen"))))
mes-ast)
)
message-list)))
(define eliminate-channel-key-pressure
(xml-in-laml-positional-abstraction 1 0
(lambda (channel contents attributes)
(eliminate-channel-key-pressure-1 channel contents))))
(define (eliminate-channel-key-pressure-1 ch message-list)
(eliminate-midi-null-events
(map
(lambda (mes-ast)
(if (and (ast? mes-ast)
(equal? (ast-element-name mes-ast) "ChannelKeyPressure")
(if (and (boolean? ch) ch) #t (= ch (as-number (ast-attribute mes-ast 'channel))))
)
(let ((abs-time (ast-attribute mes-ast 'absTime #f))
(delta-time (ast-attribute mes-ast 'deltaTime #f)))
(cond (abs-time
(midi-null-event-abs-time (ast-attribute mes-ast 'absTime)))
(delta-time
(midi-null-event-delta-time (ast-attribute mes-ast 'deltaTime)))
(else (laml-error "eliminate-channel-key-pressure-1: Not absTime and not deltaTime. Should not happen"))))
mes-ast)
)
message-list)))
(define eliminate-program-change
(xml-in-laml-positional-abstraction 1 0
(lambda (channel contents attributes)
(eliminate-program-change-1 channel contents))))
(define (eliminate-program-change-1 ch message-list)
(eliminate-midi-null-events
(map
(lambda (mes-ast)
(if (and (ast? mes-ast)
(equal? (ast-element-name mes-ast) "ProgramChange")
(if (and (boolean? ch) ch) #t (= ch (as-number (ast-attribute mes-ast 'channel))))
)
(let ((abs-time (ast-attribute mes-ast 'absTime #f))
(delta-time (ast-attribute mes-ast 'deltaTime #f)))
(cond (abs-time
(midi-null-event-abs-time (ast-attribute mes-ast 'absTime)))
(delta-time
(midi-null-event-delta-time (ast-attribute mes-ast 'deltaTime)))
(else (laml-error "eliminate-program-change-1: Not absTime and not deltaTime. Should not happen"))))
mes-ast)
)
message-list)))
(define eliminate-pitch-bend
(xml-in-laml-positional-abstraction 1 0
(lambda (channel contents attributes)
(eliminate-pitch-bend-1 channel contents))))
(define (eliminate-pitch-bend-1 ch message-list)
(eliminate-midi-null-events
(map
(lambda (mes-ast)
(if (and (ast? mes-ast)
(equal? (ast-element-name mes-ast) "PitchBendChange")
(if (and (boolean? ch) ch) #t (= ch (as-number (ast-attribute mes-ast 'channel))))
)
(let ((abs-time (ast-attribute mes-ast 'absTime #f))
(delta-time (ast-attribute mes-ast 'deltaTime #f)))
(cond (abs-time
(midi-null-event-abs-time (ast-attribute mes-ast 'absTime)))
(delta-time
(midi-null-event-delta-time (ast-attribute mes-ast 'deltaTime)))
(else (laml-error "eliminate-pitch-bend-1: Not absTime and not deltaTime. Should not happen"))))
mes-ast)
)
message-list)))
(define revoice
(xml-in-laml-positional-abstraction 1 0
(lambda (revoice-map contents attributes)
(let ((revoice-file (defaulted-get-prop 'revoice-file attributes #f)))
(revoice-1 revoice-map contents revoice-file)))))
(define (revoice-1 revoice-map contents revoice-file)
(let ((contents-1 (msb-lsb-to-internal-pc-attributes contents '(#t . 0) '(#t . 0) '() )))
(if revoice-file
(let ((file-path (in-startup-directory revoice-file)))
(if (file-exists? file-path) (delete-file file-path))
(write-text-file
(extract-revoice-file-info contents-1)
file-path)))
(revoice-2 revoice-map contents-1)))
(define (extract-revoice-file-info contents)
(string-append "(" CR
(list-to-string
(filter (lambda (x) x)
(map
(lambda (ast)
(if (ProgramChange? ast)
(if (and (ast-internal-attribute ast 'msb) (ast-internal-attribute ast 'lsb))
(let* ((msb (ast-internal-attribute ast 'msb))
(lsb (ast-internal-attribute ast 'lsb))
(pc (midi 'number ast)))
(single-msb-lsb-pc-info-string msb lsb pc))
#f)
#f))
contents)) CR)
CR ")"))
(define (single-msb-lsb-pc-info-string msb lsb pc)
(string-append
" (list " " (list " (as-string msb) " " (as-string lsb) " " (as-string pc) " " (string-it (as-string (find-voice-info-string msb lsb pc))) ")" CR
" (list ) "
")"))
(define (msb-lsb-to-internal-pc-attributes contents previous-msb previous-lsb out-contents)
(cond ((null? contents) (reverse out-contents))
((not (ast? (car contents))) (msb-lsb-to-internal-pc-attributes (cdr contents) previous-msb previous-lsb out-contents))
((ControlChange? (car contents) 0)
(msb-lsb-to-internal-pc-attributes (cdr contents)
(cons (midi 'channel (car contents)) (midi 'value (car contents)))
previous-lsb
out-contents))
((ControlChange? (car contents) 32)
(msb-lsb-to-internal-pc-attributes (cdr contents)
previous-msb
(cons (midi 'channel (car contents)) (midi 'value (car contents)))
out-contents))
((ProgramChange? (car contents))
(let* ((element (car contents))
(channel (midi 'channel element)))
(if #t
(let ((new-element
(make-ast (ast-element-name element) (ast-subtrees element) (ast-attributes element) (ast-kind element) (ast-language element)
(list 'msb (cdr previous-msb) 'lsb (cdr previous-lsb)))))
(msb-lsb-to-internal-pc-attributes (cdr contents) '(#t . 0) '(#t . 0) (cons new-element out-contents)))
(msb-lsb-to-internal-pc-attributes (cdr contents) previous-msb previous-lsb (cons element out-contents)))))
(else (msb-lsb-to-internal-pc-attributes (cdr contents) previous-msb previous-lsb (cons (car contents) out-contents)))))
(define (revoice-2 revoice-map contents)
(map
(lambda (ast)
(if (ProgramChange? ast)
(if (and (ast-internal-attribute ast 'msb) (ast-internal-attribute ast 'lsb))
(let* ((msb (ast-internal-attribute ast 'msb))
(lsb (ast-internal-attribute ast 'lsb))
(pc (midi 'number ast))
(ch (midi 'channel ast))
(res (lookup-revoice-map revoice-map msb lsb pc)))
(if res
(apply voice (cons ch res))
(voice ch 0 0 pc)
))
(let ((pc (midi 'number ast))
(ch (midi 'channel ast)))
(voice ch 0 0 pc)))
ast)
)
contents))
(define (lookup-revoice-map revoice-map msb lsb pc)
(let ((res (find-in-list
(lambda (e)
(let ((from (car e)))
(and (= msb (first from)) (= lsb (second from)) (= pc (third from)))))
revoice-map)))
(if res
(cadr res)
#f)))
(define eliminate-voice-messages
(xml-in-laml-positional-abstraction 0 0
(lambda (contents attributes)
(let ((info-file (defaulted-get-prop 'info-file attributes #f)))
(eliminate-voice-messages-1 info-file contents))
)))
(define (eliminate-voice-messages-1 info-file contents)
(let ((contents-1 (msb-lsb-to-internal-pc-attributes contents '(#t . 0) '(#t . 0) '() )))
(if info-file
(let ((file-path (in-startup-directory info-file)))
(if (file-exists? file-path) (delete-file file-path))
(write-text-file
(make-voices-info-string contents-1)
file-path)))
(map (lambda (ast)
(cond ((ProgramChange? ast)
(cond ((midi 'absTime ast)
(midi-comment-abs-time (midi 'absTime ast)
(string-append "Was ProgramChange" " "
(ast-attribute ast 'channel) " " (as-string (ast-internal-attribute ast 'msb "?")) " "
(as-string (ast-internal-attribute ast 'lsb "?")) " " (ast-attribute ast 'number))))
((midi 'deltaTime ast)
(midi-comment-delta-time (midi 'deltaTime ast)
(string-append "Was ProgramChange" " "
(ast-attribute ast 'channel) " " (as-string (ast-internal-attribute ast 'msb "?")) " "
(as-string (ast-internal-attribute ast 'lsb "?")) " " (ast-attribute ast 'number))))
(else (laml-error "eliminate-voice-messages-1 (A): Should not happen"))))
((SysEx? ast "05 7E 7F 09 01 F7")
(cond ((midi 'absTime ast)
(midi-comment-abs-time (midi 'absTime ast)
(string-append "Was SysEx" " "
(ast-text ast))))
((midi 'deltaTime ast)
(midi-comment-delta-time (midi 'deltaTime ast)
(string-append "Was SysEx" " "
(ast-text ast))))
(else (laml-error "eliminate-voice-messages-1 (B): Should not happen"))))
(else ast)))
contents-1)
)
)
(define (make-voices-info-string messages)
(list-to-string
(map (lambda (lst) (apply make-single-voice-info lst))
(sort-list
(filter pair?
(map
(lambda (ast)
(if (ProgramChange? ast)
(if (and (ast-internal-attribute ast 'msb) (ast-internal-attribute ast 'lsb))
(let* ((ch (midi 'channel ast))
(msb (ast-internal-attribute ast 'msb))
(lsb (ast-internal-attribute ast 'lsb))
(pc (midi 'number ast)))
(list ch msb lsb pc))
#f)
#f))
messages))
(lambda (lst1 lst2) (<= (first lst1) (first lst2)))))
CR))
(define (make-single-voice-info ch msb lsb pc)
(let ((voice-name (find-voice-info-string msb lsb pc)))
(string-append
"Channel: " (as-string ch) CR
(if voice-name voice-name "???") CR
"MSB LSB PC: " (as-string msb) " " (as-string lsb) " " (as-string pc) " " CR
(xs-instrument-how-to msb lsb pc) CR)))
(define (xs-instrument-how-to msb lsb pc)
(let ((bank (cond ((and (= msb 63) (= lsb 0)) "PRE1")
((and (= msb 63) (= lsb 1)) "PRE2")
((and (= msb 63) (= lsb 2)) "PRE3")
((and (= msb 63) (= lsb 3)) "PRE4")
((and (= msb 63) (= lsb 4)) "PRE5")
((and (= msb 63) (= lsb 5)) "PRE6")
((and (= msb 63) (= lsb 6)) "PRE7")
((and (= msb 63) (= lsb 7)) "PRE8")
((and (= msb 63) (= lsb 8)) "USR1")
((and (= msb 63) (= lsb 9)) "USR2")
((and (= msb 63) (= lsb 10)) "USR3")
((and (= msb 0) (= lsb 0)) "GM")
((and (= msb 63) (= lsb 32)) "PRE DRUM")
((and (= msb 63) (= lsb 40)) "USR DRUM")
((and (= msb 127) (= lsb 0)) "GM Drum")
(else "??")))
(number (+ (remainder pc 16) 1))
(letter-number (quotient pc 16)))
(string-append bank " " (as-string (as-char (+ 65 letter-number))) (as-string number))))
(define clean-for-motif
(xml-in-laml-positional-abstraction 0 0
(lambda (contents attributes)
(let ((info-file (defaulted-get-prop 'info-file attributes #f)))
(clean-for-motif-1 info-file contents)))))
(define (clean-for-motif-1 info-file contents)
(let ((contents-1 (eliminate-voice-messages-1 info-file contents)))
(filter
(lambda (x)
(cond ((not (ast? x)) #f)
((and (ControlChange? x) (not (member (midi 'control x) (list 64 84)))) #f)
((and (SysEx? x) (equal? (substring (ast-text x) 3 5) "43") (equal? (substring (ast-text x) 9 11) "4C")) #f)
(else #t)))
contents-1)))
(define clean-for-sectional-playing
(xml-in-laml-positional-abstraction 3 0
(lambda (time-mode time-start include-voice-messages? contents attributes)
(clean-for-sectional-playing-1 time-mode time-start include-voice-messages? contents))))
(define (clean-for-sectional-playing-1 time-mode-0 time-start include-voice-messages? messages)
(let ((time-mode (as-symbol time-mode-0)))
(let* ((suffix-starting-with-note-on
(find-tail-in-list (lambda (mes-ast)
(and (ast? mes-ast) (NoteOn? mes-ast)))
messages))
(prefix-before-starting-note-on
(find-but-tail-in-list (lambda (mes-ast)
(and (ast? mes-ast) (NoteOn? mes-ast)))
messages))
(cleaned-prefix
(if include-voice-messages?
(let* ((voice-messages (filter-messages-1 (lambda (mes-ast)
(or (ProgramChange? mes-ast) (ControlChange? mes-ast 0) (ControlChange? mes-ast 32)))
prefix-before-starting-note-on))
)
(map (lambda (voice-mes-ast)
(if (eq? time-mode 'abs-time)
(copy-ast-mutate-attributes voice-mes-ast 'absTime "0")
(copy-ast-mutate-attributes voice-mes-ast 'deltaTime "0")))
voice-messages))
'()))
)
(if (null? suffix-starting-with-note-on)
cleaned-prefix
(let ((first-time (time-of-message (first suffix-starting-with-note-on))))
(append
cleaned-prefix
(time-displace-1 (- (- first-time time-start))
(cond ((eq? time-mode 'abs-time)
(filter-messages
(lambda (mes-ast)
(not (or (Meta? mes-ast 81) (ProgramChange? mes-ast) (ControlChange? mes-ast 0) (ControlChange? mes-ast 32) (PitchBendChange? mes-ast))))
suffix-starting-with-note-on))
((eq? time-mode 'delta-time)
(transform-messages
(lambda (mes-ast)
(or (Meta? mes-ast 81) (ProgramChange? mes-ast) (ControlChange? mes-ast 0) (ControlChange? mes-ast 32) (PitchBendChange? mes-ast)))
(lambda (mes-ast) (midi-null-event-delta-time (as-number (ast-attribute mes-ast 'deltaTime))))
suffix-starting-with-note-on))
(else (laml-error "clean-for-sectional-playing-1: Should not happen."))))))))))
(define tempo-scale
(xml-in-laml-positional-abstraction 2 0
(lambda (base-tempo scale-fn contents attributes)
(let* ((duration (total-length-of-message-list contents))
(n (defaulted-get-prop 'n attributes (quotient duration 960)))
(last-tempo (defaulted-get-prop 'last-tempo attributes #f)))
(tempo-scale-1 n base-tempo scale-fn last-tempo contents)))))
(define (tempo-scale-1 n base-tempo scale-fn last-tempo contents)
(assert-abs-time contents)
(let ((duration (total-length-of-message-list contents))
)
(delta-abs-merge-two-lists
(if last-tempo
(make-tempo-change-list n duration base-tempo scale-fn (as-number last-tempo))
(make-tempo-change-list n duration base-tempo scale-fn))
contents)))
(define volume-scale
(xml-in-laml-positional-abstraction 3 0
(lambda (ch start-volume scale-fn contents attributes)
(let* ((duration (total-length-of-message-list contents))
(n (defaulted-get-prop 'n attributes (quotient duration 960)))
(end-volume (defaulted-get-prop 'end-volume attributes #f)))
(volume-scale-1 ch n duration start-volume scale-fn end-volume contents)))))
(define (volume-scale-1 ch n duration start-volume scale-fn end-volume contents)
(get-rid-of-delta-times
(delta-abs-merge-two-lists
(if end-volume
(make-volume-change-list ch n duration start-volume scale-fn (as-number end-volume))
(make-volume-change-list ch n duration start-volume scale-fn))
(map ast-copy contents)
)
0)
)
(define volume-scale-multi-channel
(xml-in-laml-positional-abstraction 1 0
(lambda (volume-scale-list contents attributes)
(let* ((duration (total-length-of-message-list contents))
(n (quotient duration 960)))
(volume-scale-multi-channel-1 n duration volume-scale-list contents)))))
(define (volume-scale-multi-channel-1 n duration volume-scale-list contents)
(if (null? volume-scale-list)
contents
(let* ((vol-scale-entry (car volume-scale-list))
(ch (first vol-scale-entry))
(start-vol (second vol-scale-entry))
(scaling-fn (third vol-scale-entry))
(end-vol (if (>= (length vol-scale-entry) 4) (fourth vol-scale-entry) #f)))
(volume-scale-multi-channel-1 n duration (cdr volume-scale-list) (volume-scale-1 ch n duration start-vol scaling-fn end-vol contents)))))
(define insert-lyric
(xml-in-laml-positional-abstraction 1 0
(lambda (lyric-syllable-list contents attributes)
(insert-lyric-1 lyric-syllable-list contents))))
(define (insert-lyric-1 lyric-syllable-list messages)
(insert-lyric-2 lyric-syllable-list messages '())
)
(define (insert-lyric-2 lyric-syllable-list messages res-messages)
(cond ((null? messages) (reverse res-messages))
(else (let ((mes (first messages)))
(cond ((not (ast? mes))
(insert-lyric-2 lyric-syllable-list (cdr messages) res-messages))
((and (Meta? mes 5)
(empty-string? (ast-text mes))
(not (null? lyric-syllable-list)))
(insert-lyric-2 (cdr lyric-syllable-list) (cdr messages)
(cons (Meta 'deltaTime (midi 'deltaTime mes) 'type 5
(as-string (car lyric-syllable-list))) res-messages)))
(else
(insert-lyric-2 lyric-syllable-list (cdr messages) (cons mes res-messages))))))))
(define (smf-to-ppqn target-ppqn context-mode smf-ast)
(let* ((header (ast-subtree smf-ast "MidiHeader"))
(source-ppqn (as-number (ast-attribute header 'pulsesPerQuarterNote)))
(format (as-number (ast-attribute header 'format)))
(mode (ast-attribute header 'mode))
(ct (ast-attribute header 'counterTransposition))
(no-of-tracks (as-number (ast-attribute header 'numberOfTracks)))
(track-list (filter (lambda (x) (and (ast? x) (equal? (ast-element-name x) "MidiTrack"))) (ast-subtrees smf-ast)))
)
(StandardMidiFile (if (eq? context-mode 'nested) (list 'internal:run-action-procedure "false") (list))
(MidiHeader 'format format 'numberOfTracks no-of-tracks 'pulsesPerQuarterNote target-ppqn 'mode mode 'counterTransposition ct)
(map
(lambda (track-ast)
(MidiTrack
(time-stretch-1 (/ target-ppqn source-ppqn) (ast-subtrees track-ast)))
)
track-list))))
(define (smf-to-format-0 context-mode smf-ast . optional-parameters)
(let* ((ppqn-distance-to-end-of-track (optional-parameter 1 optional-parameters 8))
(header (ast-subtree smf-ast "MidiHeader"))
(ppqn (as-number (ast-attribute header 'pulsesPerQuarterNote)))
(format (as-number (ast-attribute header 'format)))
(mode (ast-attribute header 'mode))
(ct (ast-attribute header 'counterTransposition))
(no-of-tracks (as-number (ast-attribute header 'numberOfTracks)))
(track-list (filter (lambda (x) (and (ast? x) (equal? (ast-element-name x) "MidiTrack"))) (ast-subtrees smf-ast)))
(no-end-of-track (lambda (message-list) (filter (lambda (x) (not (and (ast? x) (Meta? x 47)))) message-list)))
)
(if (= format 0)
smf-ast
(cond ((equal? mode "absTime")
(StandardMidiFile (if (eq? context-mode 'nested) (list 'internal:run-action-procedure "false") (list))
(MidiHeader 'format 0 'numberOfTracks 1 'pulsesPerQuarterNote ppqn 'mode "absTime" 'counterTransposition ct)
(MidiTrack
(accumulate-right abs-merge-two-lists '() (map (compose no-end-of-track ast-subtrees) track-list))
(Meta 'deltaTime (* ppqn-distance-to-end-of-track ppqn) 'type "47" ""))))
((equal? mode "deltaTime")
(StandardMidiFile (if (eq? context-mode 'nested) (list 'internal:run-action-procedure "false") (list))
(MidiHeader 'format 0 'numberOfTracks 1 'pulsesPerQuarterNote ppqn 'mode "deltaTime" 'counterTransposition ct)
(MidiTrack
(accumulate-right delta-merge-two-lists '() (map (compose no-end-of-track ast-subtrees) track-list))
(Meta 'deltaTime (* ppqn-distance-to-end-of-track ppqn) 'type "47" ""))))))))
(define (recording-to-motif smf-ast)
(smf-to-format-0 'top-level (smf-to-ppqn 480 'nested smf-ast)))
(define (recording-to-motif-nested smf-ast)
(smf-to-format-0 'nested (smf-to-ppqn 480 'nested smf-ast)))
(define (as-step-recording-on-motif-nested-fixed-timing smf-ast quantification-str)
(let ((quantification (as-number quantification-str)))
(let ((ticks (cond ((= quantification 1) (* 4 480))
((= quantification 2) (* 2 480))
((= quantification 4) 480)
((= quantification 8) 240)
((= quantification 16) 120)
((= quantification 32) 60)
(else (laml-error "as-step-recording-on-motif-nested: Unknown quantification:" quantification)))))
(apply-to-tracks-nested
(lambda mes-lst
(map (lambda (ast)
(if (NoteOn? ast)
(copy-ast-mutate-attributes ast 'deltaTime ticks 'duration ticks)
ast)
)
mes-lst))
()
(recording-to-motif-nested smf-ast)))))
(define (as-step-recording-on-motif-nested-variable-timing smf-ast)
(apply-to-tracks-nested
(lambda mes-lst
(quantize-timing-in-a-step-recording
(map (lambda (ast)
(if (NoteOn? ast)
(quantize-duration-of-note-step-recording ast)
ast)
)
(legato-in-channel-1 1 10 #t #f 0 mes-lst))))
()
(recording-to-motif-nested smf-ast)))
(define (quantize-duration-of-note-step-recording note-ast)
(let* ((recorded-duration (midi 'duration note-ast))
(forced-duration (cond ((<= recorded-duration 300) 120)
((<= recorded-duration 600) 240)
((<= recorded-duration 1200) 480)
((<= recorded-duration 2400) 960)
(else 1920)))
)
(copy-ast-mutate-attributes note-ast 'duration forced-duration)))
(define (quantize-timing-in-a-step-recording event-ast-lst)
(quantize-timing-step-recording-1 event-ast-lst #f '())
)
(define (quantize-timing-step-recording-1 event-ast-lst prev-duration res-lst)
(if (null? event-ast-lst)
(reverse res-lst)
(let ((mes (car event-ast-lst)))
(cond ((and (NoteOn? mes) (not prev-duration))
(quantize-timing-step-recording-1 (cdr event-ast-lst) (midi 'duration mes) (cons (copy-ast-mutate-attributes mes 'deltaTime 480) res-lst)))
((and (NoteOn? mes) prev-duration)
(quantize-timing-step-recording-1 (cdr event-ast-lst) (midi 'duration mes) (cons (copy-ast-mutate-attributes mes 'deltaTime prev-duration) res-lst)))
((ast? mes)
(quantize-timing-step-recording-1 (cdr event-ast-lst) prev-duration (cons mes res-lst)))
(else
(quantize-timing-step-recording-1 (cdr event-ast-lst) prev-duration res-lst))))))
(define (rtm smf-ast)
(apply-to-tracks-top-level eliminate-channel-key-pressure (list #t)
(apply-to-tracks-nested marker-silence (list 2000)
(recording-to-motif-nested smf-ast))))
(define (recording-to-tyros smf-ast)
(smf-to-format-0 'top-level (smf-to-ppqn 1920 'nested smf-ast)))
(define (apply-to-tracks-nested f f-parameter-list ast)
(apply-to-tracks f f-parameter-list ast 'nested)
)
(define (apply-to-tracks-top-level f f-parameter-list ast)
(apply-to-tracks f f-parameter-list ast 'top-level)
)
(define (apply-to-tracks f f-parameter-list ast context-mode)
(cond
((and (equal? "StandardMidiFile" (ast-element-name ast)) (equal? "0" (ast-attribute (ast-subtree ast "MidiHeader") 'format)))
(let* ((track-ast (ast-subtree ast "MidiTrack" 1))
(header-ast (ast-subtree ast "MidiHeader"))
(track-messages (ast-subtrees track-ast)))
(StandardMidiFile (if (eq? context-mode 'nested) (list 'internal:run-action-procedure "false") (list))
header-ast
(MidiTrack
(apply f (append f-parameter-list track-messages))))))
((and (equal? "StandardMidiFile" (ast-element-name ast)) (equal? "1" (ast-attribute (ast-subtree ast "MidiHeader") 'format)))
(let* ((header-ast (ast-subtree ast "MidiHeader"))
(track-ast-list (find-asts ast "MidiTrack"))
)
(StandardMidiFile (if (eq? context-mode 'nested) (list 'internal:run-action-procedure "false") (list))
header-ast
(map (lambda (track-ast)
(MidiTrack
(apply f (append f-parameter-list (ast-subtrees track-ast)))))
track-ast-list))))
((equal? "MidiTrack" (ast-element-name ast))
(let ((track-messages (ast-subtrees ast)))
(MidiTrack
(apply f (append f-parameter-list track-messages)))))
(else (laml-error "Must be called on a StandardMidiFile or MidiTrack ast"))))
(define (make-scale-fn-pol-one-pol shape-start shape-end c d)
(letrec ((f-up (lambda (x) (+ 1 (* c (- x d) (- x (- 1 d))))))
(f-down (lambda (x) (max (- 1 (* c (- x d) (- x (- 1 d)))) 0)))
(f-flat (lambda (x) 1))
)
(lambda (x)
(cond ((< x 0) (error "the input is not supposed to be negative"))
((< x d) ((cond ((eq? shape-start 'up) f-up)
((eq? shape-start 'flat) f-flat)
((eq? shape-start 'down) f-down)
(else (laml-error "shape-start must be one of the symbols up, flat, or down"))) x))
((< x (- 1 d)) 1)
((<= x 1) ((cond ((eq? shape-end 'up) f-up)
((eq? shape-end 'flat) f-flat)
((eq? shape-end 'down) f-down)
(else (laml-error "shape-end must be one of the symbols up, flat, or down"))) x))
(else (error "the input is not supposed to larger than one"))))))
(define (make-scale-fn-pol-one-pol-general shape-start shape-end cs ds ce de)
(letrec ((f-up-s (lambda (x) (+ 1 (* cs (- x ds) (- x (- 1 ds))))))
(f-down-s (lambda (x) (max (- 1 (* cs (- x ds) (- x (- 1 ds)))) 0)))
(f-up-e (lambda (x) (+ 1 (* ce (- x de) (- x (- 1 de))))))
(f-down-e (lambda (x) (max (- 1 (* ce (- x de) (- x (- 1 de)))) 0)))
(f-flat (lambda (x) 1))
)
(lambda (x)
(cond ((< x 0) (error "the input is not supposed to be negative"))
((< x ds) ((cond ((eq? shape-start 'up) f-up-s)
((eq? shape-start 'flat) f-flat)
((eq? shape-start 'down) f-down-s)
(else (laml-error "shape-start must be one of the symbols up, flat, or down"))) x))
((< x (- 1 de)) 1)
((<= x 1) ((cond ((eq? shape-end 'up) f-up-e)
((eq? shape-end 'flat) f-flat)
((eq? shape-end 'down) f-down-e)
(else (laml-error "shape-end must be one of the symbols up, flat, or down"))) x))
(else (error "the input is not supposed to larger than one"))))))
(define (make-scale-function-by-xy-points xy-list)
(letrec ((x-of car)
(y-of cdr)
)
(let ((sorted-xy-list (sort-list
xy-list
(lambda (p1 p2) (<= (x-of p1) (x-of p2))))))
(lambda (x)
(let* ((first-pair-0 (find-in-list (lambda (pair) (> (x-of pair) x)) sorted-xy-list))
(first-pair (if (and (boolean? first-pair-0) (not first-pair-0))
(last sorted-xy-list)
first-pair-0))
(second-pair (element-before first-pair sorted-xy-list id-1 equal?))
(x1 (x-of first-pair))
(y1 (y-of first-pair))
(x2 (x-of second-pair))
(y2 (y-of second-pair)))
(+ y1 (* (/ (- y2 y1) (- x2 x1)) (- x x1))))))))
(define (multiply-scaling-function factor sf)
(lambda (x)
(* factor (sf x))))
(define (add-two-scaling-functions sf1 sf2)
(lambda (x)
(+ (sf1 x) (sf2 x) )))
(define (subtract-two-scaling-functions sf1 sf2)
(lambda (x)
(- (sf1 x) (sf2 x) )))
(define (multiply-two-scaling-functions sf1 sf2)
(lambda (x)
(* (sf1 x) (sf2 x) )))
(define (from-percent-points point-lst)
(map (lambda (point)
(cons (/ (first point) 100)
(/ (second point) 100)))
point-lst))
(define (from-permille-points point-lst)
(map (lambda (point)
(cons (/ (first point) 1000)
(/ (second point) 1000)))
point-lst))
(define pi 3.141592654)
(define sf1
(multiply-scaling-function 2.5
(make-scale-function-by-xy-points
(from-permille-points '((0 -150) (350 -110) (700 0) (760 50) (800 70) (850 60) (900 30) (1000 0)))
)))
(define sf2
(multiply-scaling-function 1.0
(make-scale-function-by-xy-points
(from-permille-points '((0 -250) (500 -150) (750 -75) (800 -50) (900 -10) (1000 0)))
)))
(define sf3
(multiply-scaling-function 1.8
(make-scale-function-by-xy-points
(from-permille-points '((0 0) (33 -50) (66 50) (100 0) (133 -50) (166 50)
(200 0) (233 -50) (266 50) (300 0) (333 -50) (366 50)
(400 0) (433 -40) (466 40) (500 0) (533 -40) (566 40)
(600 0) (633 -30) (666 30) (700 0) (733 -30) (766 30)
(800 0) (833 -25) (866 25) (900 0) (933 -25) (966 25) (1000 0) ))
)))
(define sf4
(make-scale-fn-pol-one-pol 'down 'down 4.5 0.35))
(define sf5
(make-scale-fn-pol-one-pol 'up 'down 5.5 0.25))
(define sf6
(multiply-two-scaling-functions
(make-scale-function-by-xy-points
(from-percent-points '((0 100) (100 0))))
(lambda (x) (sin (* x 15 pi)))
))
(define-syntax midi-context
(syntax-rules ()
((midi-context select midi-message ...)
(call-with-current-continuation
(lambda (select)
(list midi-message ...))))))
(define midi-region-do
(xml-in-laml-positional-abstraction 1 0
(lambda (contextual-continuation contents attributes)
(let* ((ast-contents (filter ast? contents))
(first-mes (if (not (null? ast-contents)) (first ast-contents) #f))
(abs-time (if first-mes (ast-attribute first-mes 'absTime #f) #f)))
(if abs-time
(contextual-continuation (time-displace (- (as-number abs-time)) contents))
(contextual-continuation contents))))))
(define midi-region
(xml-in-laml-abstraction
(lambda (contents attributes)
(let* ((drop (as-boolean (defaulted-get-prop 'drop attributes #f)))
(name (defaulted-get-prop 'name attributes ""))
(sep (if (empty-string? name) "" ":"))
(midi-comment-start (midi-comment (string-append "Midi region start" sep) name ))
(midi-comment-end (midi-comment (string-append "Midi region end" sep) name ))
)
(if (not drop)
(list midi-comment-start contents midi-comment-end)
'())))))
(define midi-null-event-text "Midi null-event")
(define (midi-null-event delta-time . optional-parameter-list)
(let ((info-text (optional-parameter 1 optional-parameter-list midi-null-event-text)))
(Meta 'deltaTime delta-time 'type "1" info-text)))
(define midi-null-event-delta-time midi-null-event)
(define (midi-null-event-abs-time abs-time . optional-parameter-list)
(let ((info-text (optional-parameter 1 optional-parameter-list midi-null-event-text)))
(Meta 'absTime abs-time 'type "1" info-text)))
(define midi-comment
(xml-in-laml-abstraction
(lambda (contents attr)
(Meta 'deltaTime "0" 'type 1 contents))))
(define midi-comment-abs-time
(xml-in-laml-positional-abstraction 1 0
(lambda (abs-time contents attr)
(Meta 'absTime abs-time 'type 1 contents))))
(define midi-comment-delta-time
(xml-in-laml-positional-abstraction 1 0
(lambda (delta-time contents attr)
(Meta 'deltaTime delta-time 'type 1 contents))))
(define (midi-marker marker-txt . optional-parameter-list)
(let ((marker-number (optional-parameter 1 optional-parameter-list 0))
(marker-letter (optional-parameter 2 optional-parameter-list "M"))
)
(Meta 'deltaTime "0" 'type "6" (string-append marker-letter "-" (as-string marker-number) " " marker-txt))))
(define (midi-marker-abs-time abs-time marker-txt . optional-parameter-list)
(let ((marker-number (optional-parameter 1 optional-parameter-list 0))
(marker-letter (optional-parameter 2 optional-parameter-list "M"))
)
(Meta 'absTime (as-string abs-time) 'type "6" (string-append marker-letter "-" (as-string marker-number) " " marker-txt))))
(define (pan c value)
(ControlChange 'deltaTime "0" 'channel c 'control "10" 'value value))
(define (volume c value)
(ControlChange 'deltaTime "0" 'channel c 'control "7" 'value value))
(define (reverb c value)
(ControlChange 'deltaTime "0" 'channel c 'control "91" 'value value))
(define (chorus c value)
(ControlChange 'deltaTime "0" 'channel c 'control "93" 'value value))
(define (dsp-variation-on)
(list
(SysEx 'deltaTime "0" "08 43 10 4C 03 00 02 5B F7")
(SysEx 'deltaTime "0" "08 43 10 4C 03 00 03 05 F7")))
(define (dsp-variation-off)
(list
(SysEx 'deltaTime "0" "08 43 10 4C 03 00 02 28 F7")
(SysEx 'deltaTime "0" "08 43 10 4C 03 00 03 04 F7")))
(define (voice channel msb lsb program-number)
(list
(ControlChange 'deltaTime "0" 'channel channel 'control "0" 'value msb)
(ControlChange 'deltaTime "0" 'channel channel 'control "32" 'value lsb)
(ProgramChange 'deltaTime "0" 'channel channel 'number program-number)
)
)
(define (voice-with-mix channel msb lsb program-number v p r c)
(list
(ControlChange 'deltaTime "0" 'channel channel 'control "0" 'value msb)
(ControlChange 'deltaTime "0" 'channel channel 'control "32" 'value lsb)
(ProgramChange 'deltaTime "0" 'channel channel 'number program-number)
(volume channel v)
(pan channel p)
(reverb channel r)
(chorus channel c)
)
)
(define (gm-voice channel program)
(cond ((number? program)
(voice channel 0 0 program))
((string? program)
(let* ((gm-data-list (file-read (string-append midi-software-dir "data/general-midi-voices.dat")))
(res (find-in-list (lambda (entry) (equal? (downcase-string program)
(downcase-string (get-gm-voice-name entry))))
gm-data-list)))
(if res
(voice channel 0 0 (get-gm-voice-pc res))
(let ((res (find-in-list (lambda (entry) (substring? (downcase-string (get-gm-voice-name entry))
(downcase-string program)))
gm-data-list)))
(if res
(voice channel 0 0 (get-gm-voice-pc res))
(laml-error "gm-voice: Cannot make sense of program: " program))))))
(else (laml-error "gm-voice: The second parameter must be a pc-number of a voice name (a string)"))))
(define (voices-from-file . optional-parameter-list)
(let* ((voice-file (optional-parameter 1 optional-parameter-list (source-filename-without-extension)))
(init-path (file-name-initial-path voice-file))
(voice-file-with-extension (string-append (file-name-proper voice-file) "." "voices"))
(file-path (string-append (if (empty-string? init-path) (startup-directory) init-path) voice-file-with-extension))
(get-msb first) (get-lsb second) (get-pc third) (get-vol fifth) (get-pan sixth) (get-reverb seventh) (get-chorus eighth)
)
(if (file-exists? file-path)
(let* ((voice-structure (file-read file-path)))
(flatten
(filter (lambda (x) x)
(map2 (lambda (e ch)
(if (not (eq? e 'nil))
(if (= (length e) 4)
(voice ch (get-msb e) (get-lsb e) (get-pc e))
(voice-with-mix ch (get-msb e) (get-lsb e) (get-pc e) (get-vol e) (get-pan e) (get-reverb e) (get-chorus e)))
#f))
(cdr voice-structure)
(number-interval 1 16)
))))
(laml-error "voices-from-file: Non-exisisting voice file path: " file-path))))
(define (tempo bpm)
(Meta 'deltaTime "0" 'type "81" (tempo= bpm)))
(define (pitch-bend-range channel range . optional-parameter-list)
(let ((cents (optional-parameter 1 optional-parameter-list 0)))
(list
(ControlChange 'deltaTime "0" 'channel channel 'control "101" 'value "0")
(ControlChange 'deltaTime "0" 'channel channel 'control "100" 'value "0")
(ControlChange 'deltaTime "0" 'channel channel 'control "6" 'value range)
(ControlChange 'deltaTime "0" 'channel channel 'control "38" 'value cents)
)))
(define (chord-meta root . optional-parameter-list)
(let ((chord-type (optional-parameter 1 optional-parameter-list "M")))
(let* ((chord-type-number (index-in-list-by-predicate chord-types chord-type (lambda (chord-types-row ct) (equal? (car chord-types-row) ct))))
(root-number (calculate-root-number root))
(chord-type-number-two-ciffer-hex-string (binary-to-hex-string (int10-to-binary chord-type-number 1)))
(chord-root-number-two-ciffer-hex-string (binary-to-hex-string (int10-to-binary root-number 1)))
)
(Meta 'deltaTime "0" 'type "127"
(string-append "43 7B 01" " "
chord-root-number-two-ciffer-hex-string " " chord-type-number-two-ciffer-hex-string " "
chord-root-number-two-ciffer-hex-string " " chord-type-number-two-ciffer-hex-string)))))
(define (calculate-root-number root0)
(let* ((root (upcase-string root0))
(real-root (string-ref root 0))
(root-variation (if (> (string-length root) 1) (string-ref root 1) #f))
(part1-hex-ciffer
(cond ((not root-variation) 3)
((eqv? root-variation #\#) 4)
((eqv? root-variation #\b) 2)
((eqv? root-variation #\B) 2)
(else (laml-error "chord-meta -> calculate-root-number. Unknown root variation. Use only the empty or '#'" root))))
(part2-hex-ciffer
(cond ((eqv? #\C real-root) 1)
((eqv? #\D real-root) 2)
((eqv? #\E real-root) 3)
((eqv? #\F real-root) 4)
((eqv? #\G real-root) 5)
((eqv? #\A real-root) 6)
((eqv? #\B real-root) 7)
((eqv? #\H real-root) 7)
(else (laml-error "chord-meta -> calculate-root-number. Unknown root. Use only C D E F G A H B (or H for B)")))))
(+ (* 16 part1-hex-ciffer) part2-hex-ciffer)))
(define (lyrics txt)
(Meta 'deltaTime "0" 'type "5" txt))
(define (play-chord root chord-type start-octave number-of-octaves time-delta duration . optional-parameter-list)
(let ((ch (optional-parameter 1 optional-parameter-list 1))
(vel (optional-parameter 2 optional-parameter-list 80)))
(let* ((absolute-repeated-root-chord-formula (chord-note-list root chord-type start-octave number-of-octaves))
(time-delta-list (make-list (length absolute-repeated-root-chord-formula) time-delta))
)
(map
(lambda (nn dt)
(NoteOn 'deltaTime dt 'channel ch 'note (between 0 127 nn) 'velocity vel 'duration duration))
absolute-repeated-root-chord-formula
time-delta-list)
)))
(define (noteon-sequence-ending-at note lgt root chord-type time-delta duration . optional-parameter-list)
(let ((ch (optional-parameter 1 optional-parameter-list 1))
(vel (optional-parameter 2 optional-parameter-list 80)))
(let ((chord-lst (chord-note-list-ending-at note lgt root chord-type)))
(if chord-lst
(cons
(NoteOn 'deltaTime (- (* time-delta (- (length chord-lst) 1))) 'channel ch 'note (first chord-lst) 'velocity vel 'duration duration)
(map
(lambda (note-val)
(NoteOn 'deltaTime time-delta 'channel ch 'note note-val 'velocity vel 'duration duration)
)
(cdr chord-lst))
)
'()))))
(define (strum-one-note note-on-ast lgt root chord-type time-delta duration . optional-parameter-list)
(let* ((ch (optional-parameter 1 optional-parameter-list (ast-attribute note-on-ast 'channel)))
(vel (optional-parameter 2 optional-parameter-list (ast-attribute note-on-ast 'velocity)))
(note (as-number (ast-attribute note-on-ast 'note)))
(seq (noteon-sequence-ending-at note lgt root chord-type time-delta duration ch vel)))
(if (not (null? seq))
(append (list note-on-ast) (butlast seq))
(list note-on-ast))))
(define strum-1
(xml-in-laml-positional-abstraction 3 0
(lambda (lgt root chord-type contents attributes)
(map (lambda (mes-ast)
(if (and (ast? mes-ast) (equal? "NoteOn" (ast-element-name mes-ast)))
(strum-one-note mes-ast lgt root chord-type 300 300)
mes-ast))
contents))))
(define strum-2
(xml-in-laml-abstraction
(lambda (contents attributes)
(map (lambda (mes-ast)
(if (and (ast? mes-ast) (equal? "NoteOn" (ast-element-name mes-ast)))
(let* ((lgt (as-number (ast-attribute mes-ast 'strum-length 4)))
(chord (ast-attribute mes-ast 'chord #f)))
(if chord
(let* ((root-chordtype (split-chord-to-root-and-type chord))
(root (car root-chordtype))
(chord-type (cdr root-chordtype)))
(strum-one-note mes-ast lgt root chord-type 300 300))
mes-ast))
mes-ast))
contents))))
(define strum-3
(xml-in-laml-positional-abstraction 1 0
(lambda (ch contents attributes)
(strum-3-internal ch contents #f #f 10))))
(define (strum-3-internal ch contents root chord-type strum-length)
(cond ((null? contents) '())
(else (let ((mes-ast (car contents)))
(cond ((and (ast? mes-ast) (equal? "NoteOn" (ast-element-name mes-ast)) (= ch (as-number (ast-attribute mes-ast 'channel))))
(let* ((lgt-new (as-number (ast-attribute mes-ast 'strum-length strum-length)))
(chord-new (ast-attribute mes-ast 'chord #f)))
(if chord-new
(let* ((root-chordtype (split-chord-to-root-and-type chord-new))
(root-new (car root-chordtype))
(chord-type-new (cdr root-chordtype)))
(append (strum-one-note mes-ast lgt-new root-new chord-type-new 300 300)
(strum-3-internal ch (cdr contents) root-new chord-type-new lgt-new)))
(if (and root chord-type)
(append (strum-one-note mes-ast lgt-new root chord-type 300 300)
(strum-3-internal ch (cdr contents) root chord-type strum-length))
(cons mes-ast (strum-3-internal ch (cdr contents) root chord-type strum-length))))))
((meta-chord-ast? mes-ast)
(let* ((root-and-chordtype (meta-chord-root-and-chordtype mes-ast))
(root-new (car root-and-chordtype))
(chord-type-new (cdr root-and-chordtype)))
(cons mes-ast (strum-3-internal ch (cdr contents) root-new chord-type-new strum-length))))
(else (cons mes-ast (strum-3-internal ch (cdr contents) root chord-type strum-length))))))))
(define (split-chord-to-root-and-type chord)
(let ((lgt (string-length chord)))
(cond ((= lgt 1) (cons (substring chord 0 1) "M"))
((= lgt 2)
(if (eqv? (string-ref chord 1) #\#)
(cons (substring chord 0 2) "M")
(cons (substring chord 0 1) (substring chord 1 lgt))))
((>= lgt 2)
(if (eqv? (string-ref chord 1) #\#)
(cons (substring chord 0 2) (substring chord 2 lgt))
(cons (substring chord 0 1) (substring chord 1 lgt)))))))
(define (make-pitch-bend-change-list ch n duration scale-fn . optional-parameters)
(let ((first-delta-time (optional-parameter 1 optional-parameters (/ duration n))))
(letrec ((make-function-domain-values
(lambda (length increment actual)
(if (= length 0)
'()
(cons actual (make-function-domain-values (- length 1) increment (+ actual increment))))))
)
(let ((pitch-value-fn (compose (lambda (r) (+ (* r 8192) 8192)) scale-fn))
(delta-dur (/ duration n))
(function-unit-domain-values (make-function-domain-values n (/ 1 (- n 1)) 0))
)
(cons (let ((value (between 0 16383 (pitch-value-fn (car function-unit-domain-values)))))
(PitchBendChange 'deltaTime (as-int-string first-delta-time) 'channel (as-string ch)
'value (as-int-string value)))
(map
(lambda (unit-domain-value)
(let ((value (between 0 16383 (pitch-value-fn unit-domain-value))))
(PitchBendChange 'deltaTime (as-int-string delta-dur) 'channel (as-string ch) 'value (as-int-string value))))
(cdr function-unit-domain-values)))))))
(define (make-tempo-change-list n0 duration base-tempo scale-fn . optional-parameter-list)
(let* ((n (- n0 1))
(last-tempo (optional-parameter 1 optional-parameter-list #f)))
(letrec ((make-function-domain-values
(lambda (length increment actual)
(if (= length 0)
'()
(cons actual (make-function-domain-values (- length 1) increment (+ actual increment))))))
)
(if last-tempo
(let ((function-unit-domain-values (make-function-domain-values (+ n 1) (/ 1 n) 0))
(delta-dur (/ duration n0))
)
(append
(map
(lambda (unit-domain-value)
(Meta 'deltaTime (as-int-string delta-dur) 'type "81" (tempo= (* base-tempo (scale-fn unit-domain-value))))
)
(butlast function-unit-domain-values))
(list
(Meta 'deltaTime (as-int-string delta-dur) 'type "81" (tempo= last-tempo)))))
(let ((function-unit-domain-values (make-function-domain-values (+ n 1) (/ 1 n) 0))
(delta-dur (/ duration n0))
)
(map
(lambda (unit-domain-value)
(Meta 'deltaTime (as-int-string delta-dur) 'type "81" (tempo= (* base-tempo (scale-fn unit-domain-value))))
)
function-unit-domain-values))
))))
(define (make-volume-change-list ch n0 duration start-volume scale-fn . optional-parameter-list)
(let* ((n (- n0 1))
(end-volume (optional-parameter 1 optional-parameter-list #f)))
(letrec ((make-function-domain-values
(lambda (length increment actual)
(if (= length 0)
'()
(cons actual (make-function-domain-values (- length 1) increment (+ actual increment))))))
)
(if end-volume
(let ((function-unit-domain-values (make-function-domain-values (+ n 1) (/ 1 n) 0))
(delta-dur (/ duration n0))
)
(append
(map
(lambda (unit-domain-value)
(ControlChange 'deltaTime (as-int-string delta-dur) 'channel ch 'control "7"
'value (as-int-string (between 0 127 (* start-volume (scale-fn unit-domain-value)))))
)
(butlast function-unit-domain-values))
(list
(ControlChange 'deltaTime (as-int-string delta-dur) 'channel ch 'control "7"
'value (as-int-string (between 0 127 end-volume))))))
(let ((function-unit-domain-values (make-function-domain-values (+ n 1) (/ 1 n) 0))
(delta-dur (/ duration n0))
)
(map
(lambda (unit-domain-value)
(ControlChange 'deltaTime (as-int-string delta-dur) 'channel ch 'control "7"
'value (as-int-string (between 0 127 (* start-volume (scale-fn unit-domain-value)))))
)
function-unit-domain-values))
))))
(define replicate-channel
(xml-in-laml-positional-abstraction 2 0
(lambda (ch-from ch-to cont attr)
(replicate-channel-1 ch-from ch-to cont))))
(define (replicate-channel-1 ch-from ch-to message-list)
(map
(lambda (mes-ast)
(if (ast? mes-ast)
(let ((channel (ast-attribute mes-ast 'channel #f)))
(if channel
(if (= ch-from (as-number channel))
(list
mes-ast
(copy-ast-mutate-attributes mes-ast 'channel ch-to)
)
mes-ast)
mes-ast))
mes-ast))
message-list))
(define replicate-by-predicate
(xml-in-laml-positional-abstraction 2 0
(lambda (predicate ch-to cont attr)
(replicate-by-predicate-1 predicate ch-to cont))))
(define (replicate-by-predicate-1 predicate ch-to message-list)
(map
(lambda (mes-ast)
(if (ast? mes-ast)
(let ((channel (ast-attribute mes-ast 'channel #f)))
(if (and channel (predicate mes-ast))
(list
mes-ast
(copy-ast-mutate-attributes mes-ast 'channel ch-to)
)
mes-ast))
mes-ast
))
message-list))
(define replicate-by-predicate-and-transformation
(xml-in-laml-positional-abstraction 2 0
(lambda (predicate transf cont attr)
(replicate-by-predicate-and-transformation-1 predicate transf cont))))
(define (replicate-by-predicate-and-transformation-1 predicate transf message-list)
(map
(lambda (mes-ast)
(if (ast? mes-ast)
(let ((channel (ast-attribute mes-ast 'channel #f)))
(if (and channel (predicate mes-ast))
(let ((the-transformation (transf mes-ast)))
(cond ((ast? the-transformation) (list mes-ast (transf mes-ast)))
((list? the-transformation) (cons mes-ast the-transformation))
(else (laml-error "replicate-by-predicate-1: The transformation must return an AST, or a list of ASTs"))))
mes-ast))
mes-ast
))
message-list))
(define join-channels
(xml-in-laml-positional-abstraction 2 0
(lambda (ch-list ch-to cont attr)
(join-channels-1 ch-list ch-to cont))))
(define (join-channels-1 ch-list ch-to message-list)
(map
(lambda (mes-ast)
(if (ast? mes-ast)
(let ((channel (ast-attribute mes-ast 'channel #f)))
(if channel
(if (member (as-number channel) ch-list)
(copy-ast-mutate-attributes mes-ast 'channel ch-to)
mes-ast)
mes-ast))
mes-ast))
message-list))
(define select-channel
(xml-in-laml-positional-abstraction 1 0
(lambda (ch cont attr)
(eliminate-midi-null-events (select-channel-1 ch cont)))))
(define (select-channel-1 c message-list)
(map
(lambda (mes-ast)
(if (ast? mes-ast)
(let ((channel (ast-attribute mes-ast 'channel #f)))
(if channel
(if (= c (as-number (ast-attribute mes-ast 'channel)))
mes-ast
(midi-null-event (ast-attribute mes-ast 'deltaTime 0)))
mes-ast))
mes-ast))
message-list))
(define delete-channel
(xml-in-laml-positional-abstraction 1 0
(lambda (ch cont attr)
(delete-channel-1 ch cont))))
(define (delete-channel-1 c message-list)
(map
(lambda (mes-ast)
(if (ast? mes-ast)
(let ((channel (ast-attribute mes-ast 'channel #f)))
(if channel
(if (= c (as-number (ast-attribute mes-ast 'channel)))
(midi-null-event (ast-attribute mes-ast 'deltaTime 0))
mes-ast)
mes-ast))
mes-ast))
message-list))
(define delete-channel-abs-time
(xml-in-laml-positional-abstraction 1 0
(lambda (ch cont attr)
(delete-channel-abs-time-1 ch cont))))
(define (delete-channel-abs-time-1 ch message-list)
(delete-channel-abs-time-2 ch message-list '()))
(define (delete-channel-abs-time-2 ch message-list res)
(if (null? message-list)
(reverse res)
(let ((mes-ast (car message-list)))
(if (and (ast? mes-ast) (ast-attribute mes-ast 'channel #f) (= ch (as-number (ast-attribute mes-ast 'channel))))
(delete-channel-abs-time-2 ch (cdr message-list) res)
(delete-channel-abs-time-2 ch (cdr message-list) (cons mes-ast res))))))
(define select-channels
(xml-in-laml-positional-abstraction 1 0
(lambda (ch-list cont attr)
(if (and (boolean? ch-list) ch-list)
cont
(eliminate-midi-null-events (select-channels-1 ch-list cont 0))))))
(define (select-channels-1 c-list message-list between-time)
(cond ((null? message-list) '())
(else (let ((mes-ast (first message-list)))
(if (ast? mes-ast)
(let ((channel (ast-attribute mes-ast 'channel #f)))
(if channel
(if (or (and (boolean? c-list) c-list) (member (as-number (ast-attribute mes-ast 'channel)) c-list))
(cons (if (delta-time-message? mes-ast)
(copy-ast-mutate-attributes mes-ast 'deltaTime (+ (time-of-message mes-ast) between-time))
mes-ast)
(select-channels-1 c-list (cdr message-list) 0))
(if (delta-time-message? mes-ast)
(cons (midi-null-event (+ (time-of-message mes-ast) between-time))
(select-channels-1 c-list (cdr message-list) 0))
(select-channels-1 c-list (cdr message-list) (+ between-time (time-of-message mes-ast)))
)
)
(cons
(if (delta-time-message? mes-ast)
(copy-ast-mutate-attributes mes-ast 'deltaTime (+ (time-of-message mes-ast) between-time))
mes-ast)
(select-channels-1 c-list (cdr message-list) 0))
)
)
(cons mes-ast (select-channels-1 c-list (cdr message-list) between-time)))))))
(define (time-of-message mes-ast)
(let ((abs-time (ast-attribute mes-ast 'absTime #f))
(delta-time (ast-attribute mes-ast 'deltaTime #f)))
(cond (abs-time (as-number abs-time))
(delta-time (as-number delta-time))
(else (laml-error "time-of-message: Message AST without deltaTime or absTime attribute")))))
(define (delta-time-message? mes-ast)
(if (ast? mes-ast)
(as-boolean (ast-attribute mes-ast 'deltaTime #f))
#f))
(define (abs-time-message? mes-ast)
(if (ast? mes-ast)
(as-boolean (ast-attribute mes-ast 'absTime #f))
#f))
(define rechannel
(xml-in-laml-positional-abstraction 1 0
(lambda (ch-map cont attr)
(rechannel-1 ch-map cont))))
(define (rechannel-1 ch-map message-list)
(map
(lambda (mes-ast)
(if (ast? mes-ast)
(let ((channel (ast-attribute mes-ast 'channel #f)))
(if channel
(if (assoc (as-number channel) ch-map)
(copy-ast-mutate-attributes mes-ast 'channel (cdr (assoc (as-number channel) ch-map)))
mes-ast)
mes-ast))
mes-ast))
message-list))
(define eliminate-midi-null-events
(xml-in-laml-abstraction
(lambda (cont attr)
(eliminate-midi-null-events-1 cont 0 0))))
(define (eliminate-midi-null-events-1 message-list abs-time acc-delta)
(eliminate-events-1 midi-null-event-message? message-list abs-time acc-delta))
(define eliminate-events
(xml-in-laml-positional-abstraction 1 0
(lambda (predicate cont attr)
(eliminate-events-1 predicate cont 1 0))))
(define (eliminate-events-1 predicate message-list abs-time acc-delta)
(cond ((null? message-list) '())
(else (let ((mes-ast (first message-list)))
(if (ast? mes-ast)
(cond ((and (abs-time-message? mes-ast) (predicate mes-ast))
(let ((delta-time (- (time-of-message mes-ast) abs-time)))
(eliminate-events-1 predicate (cdr message-list) (time-of-message mes-ast) (+ delta-time acc-delta))))
((and (abs-time-message? mes-ast) (not (predicate mes-ast)))
(cons mes-ast (eliminate-events-1 predicate (cdr message-list) (time-of-message mes-ast) 0)))
((and (delta-time-message? mes-ast) (predicate mes-ast))
(let ((delta-time (time-of-message mes-ast)))
(eliminate-events-1 predicate (cdr message-list) (+ abs-time delta-time) (+ delta-time acc-delta))))
((and (delta-time-message? mes-ast) (not (predicate mes-ast)))
(let ((delta-time (time-of-message mes-ast)))
(cons (copy-ast-mutate-attributes mes-ast 'deltaTime (+ acc-delta delta-time))
(eliminate-events-1 predicate (cdr message-list) (+ abs-time delta-time) 0))))
(else (laml-error "eliminate-events-1: Should not happen.")))
(cons mes-ast (eliminate-events-1 predicate (cdr message-list) abs-time acc-delta)))))))
(define split-channel-by-predicate
(xml-in-laml-positional-abstraction 4 0
(lambda (channel predicate channel-true channel-false cont attr)
(split-channel-by-predicate-1 channel predicate channel-true channel-false cont))))
(define (split-channel-by-predicate-1 channel predicate channel-true channel-false message-list)
(split-channel-by-predicate-2 channel predicate channel-true channel-false message-list '())
)
(define (split-channel-by-predicate-2 channel predicate channel-true channel-false message-list res-list)
(cond ((null? message-list) (reverse res-list))
(else (let ((mes-ast (first message-list)))
(if (ast? mes-ast)
(if (and (NoteOn? mes-ast) (= channel (midi 'channel mes-ast)))
(if (predicate mes-ast)
(split-channel-by-predicate-2 channel predicate channel-true channel-false (cdr message-list)
(cons (copy-ast-mutate-attributes mes-ast 'channel channel-true) res-list))
(split-channel-by-predicate-2 channel predicate channel-true channel-false (cdr message-list)
(cons (copy-ast-mutate-attributes mes-ast 'channel channel-false) res-list)))
(split-channel-by-predicate-2 channel predicate channel-true channel-false (cdr message-list)
(cons mes-ast res-list)))
(split-channel-by-predicate-2 channel predicate channel-true channel-false (cdr message-list) res-list))))))
(define split-channel-by-contextual-predicate
(xml-in-laml-positional-abstraction 4 0
(lambda (channel predicate channel-true channel-false cont attr)
(let ((behind-context (as-number (defaulted-get-prop 'behind-context attr 240)))
(ahead-context (as-number (defaulted-get-prop 'ahead-context attr 240))))
(split-channel-by-contextual-predicate-1 channel predicate channel-true channel-false behind-context ahead-context cont)))))
(define (split-channel-by-contextual-predicate-1 channel predicate channel-true channel-false behind-context ahead-context message-list)
(split-channel-by-contextual-predicate-2 channel predicate channel-true channel-false behind-context ahead-context message-list '() '())
)
(define (split-channel-by-contextual-predicate-2 channel predicate channel-true channel-false behind-context ahead-context message-list past-list res-list)
(cond ((null? message-list) (reverse res-list))
(else (let ((mes-ast (first message-list)))
(if (ast? mes-ast)
(if (and (NoteOn? mes-ast) (= channel (midi 'channel mes-ast)))
(let* ((tm (as-number (ast-attribute mes-ast 'absTime)))
(past-list (list-prefix-while past-list (lambda (n) (>= (midi 'absTime n) (- tm behind-context)))))
(ahead-list (list-prefix-while message-list (lambda (n) (<= (midi 'absTime n) (+ tm ahead-context))))))
(display-message (length past-list) (length ahead-list))
(if (predicate mes-ast (filter (NoteOnCh? (list channel)) (append (reverse past-list) ahead-list)))
(split-channel-by-contextual-predicate-2 channel predicate channel-true channel-false behind-context ahead-context (cdr message-list)
(cons mes-ast past-list) (cons (copy-ast-mutate-attributes mes-ast 'channel channel-true) res-list))
(split-channel-by-contextual-predicate-2 channel predicate channel-true channel-false behind-context ahead-context (cdr message-list)
(cons mes-ast past-list) (cons (copy-ast-mutate-attributes mes-ast 'channel channel-false) res-list))))
(split-channel-by-contextual-predicate-2 channel predicate channel-true channel-false behind-context ahead-context (cdr message-list)
(cons mes-ast past-list) (cons mes-ast res-list)))
(split-channel-by-contextual-predicate-2 channel predicate channel-true channel-false behind-context ahead-context
(cdr message-list) past-list res-list))))))
(define substitute-section-by-bar
(xml-in-laml-positional-abstraction 2 0
(lambda (channels section-list cont attr)
(substitute-section-by-bar-1 channels section-list cont))))
(define (substitute-section-by-bar-1 channels section-list message-list)
(let ((sorted-section-list
(sort-list
section-list
(lambda (s1 s2) (<= (bar-number-of s1) (bar-number-of s2)))))
)
(let* ((section (first sorted-section-list))
(start-end-repl (by-bar-advancement-substitution section))
)
(multi-substitution channels message-list
(first start-end-repl) (second start-end-repl) (third start-end-repl) sorted-section-list by-bar-advancement-substitution #f))))
(define (by-bar-advancement-substitution section)
(let* ((units-per-bar (* global-ppqn (first global-signature)))
(bar (bar-number-of section))
(repl-start-point (* bar units-per-bar))
(number-of-bars (bar-length-of section))
(repl-length (* number-of-bars units-per-bar))
(repl-end-point (+ repl-start-point repl-length))
(replacement-lst (replicate-if-necessary (replacement-list-of section) (* number-of-bars units-per-bar)))
)
(list repl-start-point repl-end-point replacement-lst)))
(define (multi-substitution channels ml repl-start-point repl-end-point replacement-lst section-insertion-list section-advancement-fn replacing?)
(cond ((null? ml) '())
((and (not replacing?) (not (ast? (car ml))))
(cons (car ml) (multi-substitution channels (cdr ml) repl-start-point repl-end-point replacement-lst section-insertion-list section-advancement-fn replacing?)))
((and (not replacing?) (ast? (car ml)))
(let* ((mes (car ml))
(abs-time (as-number (ast-attribute mes 'absTime))))
(if (and (>= abs-time repl-start-point) (< abs-time repl-end-point))
(cons
(cons
(if (member (as-number (ast-attribute mes 'channel)) channels)
(midi-null-event-abs-time (ast-attribute mes 'absTime))
mes)
replacement-lst
)
(multi-substitution channels (cdr ml) repl-start-point repl-end-point replacement-lst section-insertion-list section-advancement-fn #t))
(cons mes (multi-substitution channels (cdr ml) repl-start-point repl-end-point replacement-lst section-insertion-list section-advancement-fn replacing?)))))
((and replacing? (not (ast? (car ml))))
(cons (car ml) (multi-substitution channels (cdr ml) repl-start-point repl-end-point replacement-lst section-insertion-list section-advancement-fn replacing?)))
((and replacing? (ast? (car ml)))
(let* ((mes (car ml))
(abs-time (as-number (ast-attribute mes 'absTime))))
(if (<= abs-time repl-end-point)
(if (and (member (as-number (ast-attribute mes 'channel)) channels) (equal? (ast-element-name mes) "NoteOn"))
(multi-substitution channels (cdr ml) repl-start-point repl-end-point replacement-lst section-insertion-list section-advancement-fn replacing?)
(cons mes (multi-substitution channels (cdr ml) repl-start-point repl-end-point replacement-lst section-insertion-list section-advancement-fn replacing?)))
(if (not (null? (cdr section-insertion-list)))
(let* ((next-section (second section-insertion-list))
(start-end-repl (section-advancement-fn next-section))
)
(cons mes (multi-substitution channels (cdr ml)
(first start-end-repl) (second start-end-repl) (third start-end-repl)
(cdr section-insertion-list) section-advancement-fn #f)))
(cons mes (multi-substitution channels (cdr ml) repl-start-point repl-end-point replacement-lst '() section-advancement-fn #f))))))
(else (laml-error "multi-substitution: Should not happen"))))
(define (replicate-if-necessary delta-message-list source-length)
(let ((mes-lst-lgt (length-of-delta-time-midi-list delta-message-list)))
(replicate-if-necessary-1 delta-message-list source-length mes-lst-lgt)))
(define (replicate-if-necessary-1 delta-message-list source-length mes-lst-lgt)
(if (<= mes-lst-lgt source-length)
(cons delta-message-list (replicate-if-necessary-1 delta-message-list (- source-length mes-lst-lgt) mes-lst-lgt))
'()))
(define (length-of-delta-time-midi-list message-list)
(length-of-delta-time-midi-list-1 message-list 0))
(define (length-of-delta-time-midi-list-1 message-list res)
(cond ((null? message-list) res)
((ast? (car message-list))
(length-of-delta-time-midi-list-1 (cdr message-list) (+ res (as-number (ast-attribute (car message-list) 'deltaTime)))))
(else (length-of-delta-time-midi-list-1 (cdr message-list) res))))
(define thin-out-section-by-bar
(xml-in-laml-positional-abstraction 2 0
(lambda (channels section-list cont attr)
(thin-out-section-by-bar-1 channels section-list cont))))
(define (thin-out-section-by-bar-1 channels section-list message-list)
(let ((units-per-bar (* global-ppqn (first global-signature)))
(sorted-section-list
(sort-list
section-list
(lambda (s1 s2) (<= (bar-number-of s1) (bar-number-of s2)))))
)
(let* ((section (first sorted-section-list))
(bar (bar-number-of section))
(repl-start-point (* bar units-per-bar))
(number-of-bars (bar-length-of section))
(repl-length (* number-of-bars units-per-bar))
(repl-end-point (+ repl-start-point repl-length))
(keep-pred (keep-predicate-of section))
)
(multi-thin-out channels message-list repl-start-point repl-end-point keep-pred sorted-section-list units-per-bar #f))))
(define (multi-thin-out channels ml repl-start-point repl-end-point keep-pred section-list upb thinning-out?)
(cond ((null? ml) '())
((and (not thinning-out?) (not (ast? (car ml))))
(cons (car ml) (multi-thin-out channels (cdr ml) repl-start-point repl-end-point keep-pred section-list upb thinning-out?)))
((and (not thinning-out?) (ast? (car ml)))
(let* ((mes (car ml))
(abs-time (as-number (ast-attribute mes 'absTime)))
(delta-time? (ast-attribute mes 'deltaTime #f))
)
(if delta-time?
(laml-error "thin-out-section-by-bar: Encountered a deltaTime message. Can only be applied in pure absTime mode."))
(if (and (>= abs-time repl-start-point) (< abs-time repl-end-point))
(let ((ch (ast-attribute mes 'channel #f))
)
(if ch
(if (member (as-number ch) channels)
(if (keep-pred abs-time)
(cons mes (multi-thin-out channels (cdr ml) repl-start-point repl-end-point keep-pred section-list upb #t))
(multi-thin-out channels (cdr ml) repl-start-point repl-end-point keep-pred section-list upb #t))
(cons mes (multi-thin-out channels (cdr ml) repl-start-point repl-end-point keep-pred section-list upb #t)))))
(cons mes (multi-thin-out channels (cdr ml) repl-start-point repl-end-point keep-pred section-list upb thinning-out?)))))
((and thinning-out? (not (ast? (car ml))))
(cons (car ml) (multi-thin-out channels (cdr ml) repl-start-point repl-end-point keep-pred section-list upb thinning-out?)))
((and thinning-out? (ast? (car ml)))
(let* ((mes (car ml))
(abs-time (as-number (ast-attribute mes 'absTime))))
(if (<= abs-time repl-end-point)
(if (and (member (as-number (ast-attribute mes 'channel)) channels) (equal? (ast-element-name mes) "NoteOn"))
(if (keep-pred abs-time)
(cons mes (multi-thin-out channels (cdr ml) repl-start-point repl-end-point keep-pred section-list upb #t))
(multi-thin-out channels (cdr ml) repl-start-point repl-end-point keep-pred section-list upb #t))
(cons mes (multi-thin-out channels (cdr ml) repl-start-point repl-end-point keep-pred section-list upb thinning-out?)))
(if (not (null? (cdr section-list)))
(let* ((next-section (second section-list))
(next-bar (bar-number-of next-section))
(next-repl-start-point (* next-bar upb))
(next-number-of-bars (bar-length-of next-section))
(next-repl-length (* next-number-of-bars upb))
(next-repl-end-point (+ next-repl-start-point next-repl-length))
(next-keep-pred (keep-predicate-of next-section)))
(cons mes (multi-thin-out channels (cdr ml) next-repl-start-point next-repl-end-point next-keep-pred (cdr section-list) upb #f)))
(cons mes (multi-thin-out channels (cdr ml) repl-start-point repl-end-point keep-pred '() upb #f))))))
(else (laml-error "multi-thin-out: Should not happen"))))
(define scale-velocity-of-sections-by-bar
(xml-in-laml-positional-abstraction 2 0
(lambda (channels section-list cont attr)
(let ((min-vel (as-number (defaulted-get-prop 'min-velocity attr "0")))
(max-vel (as-number (defaulted-get-prop 'max-velocity attr "127"))))
(scale-velocity-of-sections-by-bar-1 channels section-list min-vel max-vel cont)))))
(define (scale-velocity-of-sections-by-bar-1 channels section-list min-vel max-vel message-list)
(let ((sorted-section-list
(sort-list
section-list
(lambda (s1 s2) (<= (bar-number-of s1) (bar-number-of s2)))))
)
(let* ((section (first sorted-section-list))
(start-end-sf (by-bar-advancement-velocity-scaling section))
)
(multi-scale-velocity channels message-list min-vel max-vel (first start-end-sf) (second start-end-sf) (third start-end-sf)
sorted-section-list by-bar-advancement-velocity-scaling #f 0 0))))
(define (by-bar-advancement-velocity-scaling section)
(let* ((units-per-bar (* global-ppqn (first global-signature)))
(bar (bar-number-of section))
(repl-start-point (* bar units-per-bar))
(number-of-bars (bar-length-of section))
(repl-length (* number-of-bars units-per-bar))
(repl-end-point (+ repl-start-point repl-length))
(scaling-fu (scaling-function-of section))
)
(list repl-start-point repl-end-point scaling-fu)))
(define (multi-scale-velocity channels ml min-vel max-vel repl-start-point repl-end-point scaling-fu section-list by-bar-advancement-velocity-scaling scaling? nss i)
(cond ((null? ml) '())
((and (not scaling?) (not (ast? (car ml))))
(cons (car ml) (multi-scale-velocity channels (cdr ml) min-vel max-vel repl-start-point
repl-end-point scaling-fu section-list by-bar-advancement-velocity-scaling scaling? nss i)))
((and (not scaling?) (ast? (car ml)))
(display "X")
(let* ((mes (car ml))
(abs-time (as-number (ast-attribute mes 'absTime)))
(delta-time? (ast-attribute mes 'deltaTime #f))
)
(if delta-time?
(laml-error "scale-velocity-of-sections-by-bar: Encountered a deltaTime message."))
(if (and (>= abs-time repl-start-point) (< abs-time repl-end-point))
(let ((ch (ast-attribute mes 'channel #f))
)
(if ch
(let ((scaling-steps (find-number-of-scaling-steps-in ml channels repl-end-point)))
(if (member (as-number ch) channels)
(cons (scale-message mes scaling-fu scaling-steps 1 min-vel max-vel)
(multi-scale-velocity channels (cdr ml) min-vel max-vel repl-start-point
repl-end-point scaling-fu section-list by-bar-advancement-velocity-scaling #t scaling-steps 2))
(cons mes (multi-scale-velocity channels (cdr ml) min-vel max-vel repl-start-point
repl-end-point scaling-fu section-list by-bar-advancement-velocity-scaling #t scaling-steps 1))
))
(let ((scaling-steps (find-number-of-scaling-steps-in ml channels repl-end-point)))
(cons mes (multi-scale-velocity channels (cdr ml) min-vel max-vel repl-start-point
repl-end-point scaling-fu section-list by-bar-advancement-velocity-scaling #t scaling-steps 1)))))
(cons mes (multi-scale-velocity channels (cdr ml) min-vel max-vel repl-start-point repl-end-point
scaling-fu section-list by-bar-advancement-velocity-scaling scaling? nss i)))))
((and scaling? (not (ast? (car ml))))
(cons (car ml) (multi-scale-velocity channels (cdr ml) min-vel max-vel repl-start-point repl-end-point
scaling-fu section-list by-bar-advancement-velocity-scaling scaling? nss i)))
((and scaling? (ast? (car ml)))
(let* ((mes (car ml))
(abs-time (as-number (ast-attribute mes 'absTime))))
(if (<= abs-time repl-end-point)
(begin
(display-message "W" nss i)
(if (and (member (as-number (ast-attribute mes 'channel)) channels) (equal? (ast-element-name mes) "NoteOn"))
(cons (scale-message mes scaling-fu nss i min-vel max-vel)
(multi-scale-velocity channels (cdr ml) min-vel max-vel repl-start-point
repl-end-point scaling-fu section-list by-bar-advancement-velocity-scaling #t nss (+ i 1)))
(cons mes (multi-scale-velocity channels (cdr ml) min-vel max-vel repl-start-point repl-end-point
scaling-fu section-list by-bar-advancement-velocity-scaling scaling? nss i))))
(begin
(display "V")
(if (not (null? (cdr section-list)))
(let* ((next-section (second section-list))
(start-end-sf (by-bar-advancement-velocity-scaling next-section))
)
(cons mes (multi-scale-velocity channels (cdr ml) min-vel max-vel (first start-end-sf) (second start-end-sf) (third start-end-sf)
(cdr section-list) by-bar-advancement-velocity-scaling #f 0 0)))
(cons mes (multi-scale-velocity channels (cdr ml) min-vel max-vel repl-start-point repl-end-point
scaling-fu '() by-bar-advancement-velocity-scaling #f 0 0)))))))
(else (laml-error "multi-scale-velocity: Should not happen"))))
(define (find-number-of-scaling-steps-in message-list channels time-limit)
(find-number-of-scaling-steps-in-1 message-list channels time-limit 0))
(define (find-number-of-scaling-steps-in-1 message-list channels time-limit count)
(cond ((null? message-list) count)
((not (ast? (car message-list)))
(find-number-of-scaling-steps-in-1 (cdr message-list) channels time-limit count))
((> (as-number (ast-attribute (car message-list) 'absTime)) time-limit) count)
((and (equal? (ast-element-name (car message-list)) "NoteOn")
(ast-attribute (car message-list) 'channel #f)
(member (as-number (ast-attribute (car message-list) 'channel)) channels))
(find-number-of-scaling-steps-in-1 (cdr message-list) channels time-limit (+ count 1)))
(else
(find-number-of-scaling-steps-in-1 (cdr message-list) channels time-limit count))))
(define (scale-message noteon-ast scaling-fu scaling-steps i min-vel max-vel)
(display-message i scaling-steps)
(let* ((old-velocity (as-number (ast-attribute noteon-ast 'velocity)))
(new-velocity (between min-vel max-vel
(+ min-vel (* (- old-velocity min-vel) (scaling-fu (/ i scaling-steps)))))))
(copy-ast-mutate-attributes noteon-ast 'velocity (as-int-string new-velocity))))
(define envelope-sections-by-bar
(xml-in-laml-positional-abstraction 1 0
(lambda (section-list cont attr)
(envelope-sections-by-bar-1 section-list cont))))
(define (envelope-sections-by-bar-1 section-list message-list)
(let ((units-per-bar (* global-ppqn (first global-signature)))
(sorted-section-list
(sort-list
section-list
(lambda (s1 s2) (<= (bar-number-of s1) (bar-number-of s2)))))
)
(let* ((section (first sorted-section-list))
(bar (bar-number-of section))
(repl-start-point (* bar units-per-bar))
(number-of-bars (bar-length-of section))
(repl-length (* number-of-bars units-per-bar))
(repl-end-point (+ repl-start-point repl-length))
(pre-envelope-list (pre-envelope-of section))
(post-envelope-list (post-envelope-of section))
(post-envelope-list-length (total-length-of-message-list post-envelope-list))
)
(multi-enveloping message-list repl-start-point repl-end-point pre-envelope-list post-envelope-list post-envelope-list-length
sorted-section-list units-per-bar #f #f))))
(define (multi-enveloping ml repl-start-point repl-end-point pre-envelope-list post-envelope-list
post-envelope-length section-envelope-list upb enveloping? post-env-inserted?)
(cond ((null? ml) '())
((and (not enveloping?) (not (ast? (car ml))))
(cons (car ml)
(multi-enveloping (cdr ml) repl-start-point repl-end-point pre-envelope-list post-envelope-list
post-envelope-length section-envelope-list upb enveloping? post-env-inserted? )))
((and (not enveloping?) (ast? (car ml)))
(let* ((mes (car ml))
(abs-time (as-number (ast-attribute mes 'absTime))))
(if (and (>= abs-time repl-start-point) (< abs-time repl-end-point))
(append
pre-envelope-list
(cons
mes
(multi-enveloping (cdr ml) repl-start-point repl-end-point pre-envelope-list post-envelope-list
post-envelope-length section-envelope-list upb #t #f)))
(cons mes (multi-enveloping (cdr ml) repl-start-point repl-end-point pre-envelope-list post-envelope-list
post-envelope-length section-envelope-list upb enveloping? post-env-inserted?)))))
((and enveloping? (not (ast? (car ml))))
(cons (car ml) (multi-enveloping (cdr ml) repl-start-point repl-end-point pre-envelope-list
post-envelope-list post-envelope-length section-envelope-list upb enveloping?
post-env-inserted?)))
((and enveloping? (ast? (car ml)))
(let* ((mes (car ml))
(abs-time (as-number (ast-attribute mes 'absTime))))
(if (<= abs-time repl-end-point)
(if (and (>= abs-time (- repl-end-point post-envelope-length)) (not post-env-inserted?))
(append
post-envelope-list
(cons
mes
(multi-enveloping (cdr ml) repl-start-point repl-end-point pre-envelope-list post-envelope-list
post-envelope-length section-envelope-list upb #t #t)))
(cons mes (multi-enveloping (cdr ml) repl-start-point repl-end-point pre-envelope-list
post-envelope-list post-envelope-length section-envelope-list upb enveloping?
post-env-inserted?)) )
(if (not (null? (cdr section-envelope-list)))
(let* ((next-section (second section-envelope-list))
(next-bar (bar-number-of next-section))
(next-repl-start-point (* next-bar upb))
(next-number-of-bars (bar-length-of next-section))
(next-repl-length (* next-number-of-bars upb))
(next-repl-end-point (+ next-repl-start-point next-repl-length))
(pre-envelope-list (pre-envelope-of next-section))
(post-envelope-list (post-envelope-of next-section))
(post-envelope-list-length (total-length-of-message-list post-envelope-list))
)
(cons mes
(multi-enveloping (cdr ml) next-repl-start-point next-repl-end-point pre-envelope-list post-envelope-list
post-envelope-length (cdr section-envelope-list) upb #f #f)))
(cons mes (multi-enveloping (cdr ml) repl-start-point repl-end-point pre-envelope-list
post-envelope-list post-envelope-length '() upb #f #f))))))
(else (laml-error "multi-enveloping: Should not happen"))))
(define bar-number-of (make-selector-function 1 "bar-number-of"))
(define bar-length-of (make-selector-function 2 "bar-length-of"))
(define start-time-of (make-selector-function 1 "start-time-of"))
(define end-time-of (make-selector-function 2 "end-time-of"))
(define replacement-list-of (make-selector-function 3 "replacement-list-of"))
(define keep-predicate-of (make-selector-function 3 "keep-predicate-of"))
(define scaling-function-of (make-selector-function 3 "scaling-function-of"))
(define pre-envelope-of (make-selector-function 3 "pre-envelope-of"))
(define post-envelope-of (make-selector-function 4 "post-envelope-of"))
(define substitute-section-by-time
(xml-in-laml-positional-abstraction 2 0
(lambda (channels section-list cont attr)
(substitute-section-by-time-1 channels section-list cont))))
(define contextual-message-list '())
(define (substitute-section-by-time-1 channels section-list message-list)
(set! contextual-message-list message-list)
(let ((units-per-bar (* global-ppqn (first global-signature)))
(sorted-section-list
(sort-list
section-list
(lambda (s1 s2) (<= (bar-number-of s1) (bar-number-of s2)))))
)
(let* ((section (first sorted-section-list))
(start-end-repl (by-time-advancement-substitution section))
)
(multi-substitution channels message-list
(first start-end-repl) (second start-end-repl) (third start-end-repl)
sorted-section-list by-time-advancement-substitution #f))))
(define (by-time-advancement-substitution section)
(let* ((repl-start-point (start-time-of section))
(repl-end-point (end-time-of section))
(replacement-lst (stretch-if-necessary (replacement-list-of section) (- repl-end-point repl-start-point)))
)
(list repl-start-point repl-end-point replacement-lst)))
(define (stretch-if-necessary delta-message-list to-length)
(let* ((mes-lst-lgt (length-of-delta-time-midi-list delta-message-list))
(stretch-factor (/ to-length mes-lst-lgt)))
(time-stretch-1 stretch-factor delta-message-list)))
(define scale-velocity-of-sections-by-time
(xml-in-laml-positional-abstraction 2 0
(lambda (channels section-list cont attr)
(let ((min-vel (as-number (defaulted-get-prop 'min-velocity attr "0")))
(max-vel (as-number (defaulted-get-prop 'max-velocity attr "127"))))
(scale-velocity-of-sections-by-time-1 channels section-list min-vel max-vel cont)))))
(define (scale-velocity-of-sections-by-time-1 channels section-list min-vel max-vel message-list)
(set! contextual-message-list message-list)
(let ((sorted-section-list
(sort-list
section-list
(lambda (s1 s2) (<= (bar-number-of s1) (bar-number-of s2)))))
)
(let* ((section (first sorted-section-list))
(start-end-sf (by-time-advancement-velocity-scaling section))
)
(multi-scale-velocity channels message-list min-vel max-vel (first start-end-sf) (second start-end-sf) (third start-end-sf)
sorted-section-list by-time-advancement-velocity-scaling #f 0 0))))
(define (by-time-advancement-velocity-scaling section)
(let* ((repl-start-point (start-time-of section))
(repl-end-point (end-time-of section))
(scaling-fu (scaling-function-of section))
)
(list repl-start-point repl-end-point scaling-fu)))
(define (time-of-marker marker-name . optional-parameter-list)
(let ((message-lst (optional-parameter 1 optional-parameter-list contextual-message-list)))
(let* ((marker-lgt (string-length marker-name))
(res-mes (find-in-list
(lambda (mes)
(and (Meta? mes 6)
(let ((meta-txt (ast-text mes)))
(and (>= (string-length meta-txt) marker-lgt)
(equal? (substring meta-txt 0 marker-lgt) marker-name)))))
message-lst)))
(if res-mes
(ast-attribute res-mes 'absTime)
(laml-error "Cannot find marker" marker-name (length message-lst))))))
(define (regular-beats n ch note-value distance)
(map
(lambda (n) (NoteOn 'deltaTime distance 'channel ch 'note note-value 'velocity 127 'duration 100))
(number-interval 1 n)))
(define (beat direction stretch base-velocity total-length velocity-scaling-fn delta-time-scaling-fn . optional-parameter-list)
(let ((transposition (optional-parameter 1 optional-parameter-list 0))
(ch (optional-parameter 2 optional-parameter-list 1))
(base-duration (optional-parameter 3 optional-parameter-list 960))
(time-note-list (optional-parameter 4 optional-parameter-list '((240 C2) (240 E2) (240 G2) (240 B2) (240 C3) (240 E3))))
)
(transpose-channels (list ch) transposition
(let* ((directional-time-note-list (if (eq? direction 'down) (reverse time-note-list) time-note-list))
(notes
(scale-attribute-1 'deltaTime delta-time-scaling-fn
(scale-attribute-1 'velocity velocity-scaling-fn
(time-stretch stretch
(cons
(let* ((t 0)
(nv (second (first directional-time-note-list)))
(n-velocity (third-else (first directional-time-note-list) base-velocity))
(nn (cond ((eq? nv '-) #f) ((number? nv) nv) (else (note-name-to-note-number nv))))
)
(if (eq? nn #f)
(midi-null-event-delta-time t "Dropped note")
(NoteOn 'deltaTime t 'channel ch 'note nn 'velocity n-velocity (duration-to-next base-duration))))
(map
(lambda (t-nv)
(let* ((t (first t-nv))
(nv (second t-nv))
(n-velocity (third-else t-nv base-velocity))
(nn (cond ((eq? nv '-) #f) ((number? nv) nv) (else (note-name-to-note-number nv))))
)
(if (eq? nn #f)
(midi-null-event-delta-time t "Dropped note")
(NoteOn 'deltaTime t 'channel ch 'note nn 'velocity n-velocity (duration-to-next base-duration)))))
(cdr directional-time-note-list)))
))))
(note-lgt (accumulate-right + 0 (map (lambda (ast) (as-number (ast-attribute ast 'deltaTime))) notes)))
)
(if (> note-lgt total-length) (laml-error "Stretched NoteOn sequence of length" note-lgt "does not fit in an interval of length" total-length))
(list
(midi-comment (if (eq? direction 'down) "Downwards:" "Upwards:"))
notes
(midi-null-event-delta-time (- total-length note-lgt) (string-append "Filling to total-length " (as-string total-length)))
(midi-comment (if (eq? direction 'down) "End downwards." "End upwards."))
)))))
(define (third-else lst default)
(if (>= (length lst) 3) (third lst) default))
(define (add-together-delta-times-until ast-list stop-ast)
(cond ((null? ast-list) 0)
((not (ast? (car ast-list))) (add-together-delta-times-until (cdr ast-list) stop-ast))
((eq? (car ast-list) stop-ast) (as-number (ast-attribute stop-ast 'deltaTime)) )
(else (+ (as-number (ast-attribute (car ast-list) 'deltaTime)) (add-together-delta-times-until (cdr ast-list) stop-ast)))))
(define (duration-to-next default-duration)
(lambda (root-ast note-ast)
(let* ((track (find-first-ast root-ast "MidiTrack"))
(events-in-track (ast-subtrees track))
(note-value (ast-attribute note-ast 'note -1))
(channel (ast-attribute note-ast 'channel -1))
(events-from-note-ast (find-tail-in-list (lambda (el) (eq? el note-ast)) events-in-track))
(events-after-note-ast (if (not (null? events-from-note-ast)) (cdr events-from-note-ast) '()))
(next-similar-note-ast (find-in-list
(lambda (n-ast)
(and (NoteOn? n-ast)
(equal? note-value (ast-attribute n-ast 'note))
(equal? channel (ast-attribute n-ast 'channel))
))
events-after-note-ast))
(dur (if next-similar-note-ast (add-together-delta-times-until events-after-note-ast next-similar-note-ast) default-duration))
)
(list 'duration (max 0 dur)))))
(define (generate-mega-voice-function mega-voice-map)
(lambda (note-name section-name velocity)
(let* ((note-name-str (as-string note-name))
(relative-note-name? (member (as-number (string-ref note-name-str 0)) lower-case-interval))
(min-note-mvm (min-note-of-mega-voice-map section-name mega-voice-map))
(max-note-mvm (max-note-of-mega-voice-map section-name mega-voice-map))
(min-vel-mvm (min-velocity-of-mega-voice-map section-name mega-voice-map))
(max-vel-vmv (max-velocity-of-mega-voice-map section-name mega-voice-map))
)
(list
(if relative-note-name?
(mv-relative-to-absolute-note-number (- (note-name-to-note-number note-name) 24) min-note-mvm max-note-mvm)
(between min-note-mvm max-note-mvm (note-name-to-note-number note-name)))
(mv-scale-velocity velocity min-vel-mvm max-vel-vmv)))))
(define lower-case-interval (number-interval 97 122))
(define (min-note-of-mega-voice-map section-name mega-voice-map)
(let ((section (find-in-list (lambda (sec) (equal? (as-string section-name) (as-string (first sec)))) mega-voice-map)))
(if section (second section) (laml-error "min-note-of-mega-voice-map: Unknown section" section-name))))
(define (max-note-of-mega-voice-map section-name mega-voice-map)
(let ((section (find-in-list (lambda (sec) (equal? (as-string section-name) (as-string (first sec)))) mega-voice-map)))
(if section (third section) (laml-error "max-note-of-mega-voice-map: Unknown section" section-name))))
(define (min-velocity-of-mega-voice-map section-name mega-voice-map)
(let ((section (find-in-list (lambda (sec) (equal? (as-string section-name) (as-string (first sec)))) mega-voice-map)))
(if section (fourth section) (laml-error "min-velocity-of-mega-voice-map: Unknown section" section-name))))
(define (max-velocity-of-mega-voice-map section-name mega-voice-map)
(let ((section (find-in-list (lambda (sec) (equal? (as-string section-name) (as-string (first sec)))) mega-voice-map)))
(if section (fifth section) (laml-error "max-velocity-of-mega-voice-map: Unknown section" section-name))))
(define (mv-scale-velocity velocity min-vel max-vel)
(to-int (+ min-vel (* (/ (- max-vel min-vel) 127) (- velocity 1)))))
(define (mv-relative-to-absolute-note-number rel-note-number min-note max-note)
(let ((result (+ rel-note-number min-note)))
(if (<= result max-note)
result
max-note)))
(define steel-guitar-megavoice-map
(list
(list 'harmonics 0 95 121 127) (list 'slide 0 95 106 120) (list 'hammer 0 95 91 105) (list 'mute 0 95 76 90) (list 'dead 0 95 61 75)
(list 'open-hard 0 95 41 60) (list 'open-medium 0 95 21 40) (list 'open-soft 0 95 1 20)
(list 'strum-noice 96 119 1 127) (list 'fret-noice 120 127 1 127)))
(define (split-and-process-style style-file-path output-dir-path mode channel-selection)
(let* ((target-dir (file-name-proper (file-name-proper style-file-path)))
(midi-ast (midi-file-to-laml-ast style-file-path mode 0 #f #f))
(midi-header (ast-subtree midi-ast "MidiHeader"))
(track-ast (ast-subtree midi-ast "MidiTrack"))
(track-events (ast-subtrees track-ast))
(track-meta-divisions (filter meta-division-event? track-events))
(track-meta-division-names (map ast-text track-meta-divisions))
(init-stuff (midi-event-ast-subsequence track-events #t (third track-meta-division-names)))
(section-list
(map
(lambda (from to)
(midi-event-ast-subsequence track-events from to))
(cddr track-meta-division-names)
(append (cdddr track-meta-division-names) (list #t))))
(section-name-list (map no-spaces-in-string (cddr track-meta-division-names)))
(end-of-track-event (Meta 'deltaTime "0" 'type "47" "")))
(ensure-directory-existence! output-dir-path target-dir)
(for-each
(lambda (section section-name)
(write-text-file
(standard-midi-file-ast-to-bin
(StandardMidiFile 'internal:run-action-procedure "false"
midi-header
(MidiTrack
init-stuff
(select-channels channel-selection section)
end-of-track-event)))
(string-append output-dir-path target-dir "/" section-name "." "mid")
)
)
section-list section-name-list)))
(define (split-and-process-all-styles input-dir-path output-dir-path mode channel-selection)
(let* ((file-list (directory-list input-dir-path))
(style-file-list (filter (lambda (fn) (member (file-name-extension fn) (list "sty" "pst" "psc" "sst" "prs" "bcs"))) file-list)))
(for-each (lambda (style-file)
(display-message style-file)
(split-and-process-style (string-append input-dir-path style-file) output-dir-path mode channel-selection)
(display-message "")
)
style-file-list)))
(define (split-and-process-style-one-channel-refined style-file-path output-dir-path mode channel)
(let ((midi-ast (midi-file-to-laml-ast style-file-path mode 0 #f #f)))
(split-and-process-style-one-channel-given-ast-refined #f style-file-path midi-ast output-dir-path mode channel)))
(define (split-and-process-style-one-channel-given-ast-refined meta-file-path style-file-path midi-ast output-dir-path mode channel)
(if (not (eq? mode 'deltaTime))
(laml-error "split-and-process-style-one-channel-given-ast-refined: mode must be deltaTime" mode))
(if (not (directory-exists? output-dir-path))
(let ((parent-output-dir (parent-directory output-dir-path))
(last-dir (directory-leave-name output-dir-path))
)
(if (or (not parent-output-dir) (not last-dir))
(laml-error "You should not work in the root directory"))
(display-message "Creating" last-dir "in" parent-output-dir)
(ensure-directory-existence! parent-output-dir last-dir)))
(let* ((style-name-0 (file-name-proper (file-name-proper style-file-path)))
(style-name (transliterate style-name-0 #\space "-"))
(midi-header (ast-subtree midi-ast "MidiHeader"))
(track-ast (ast-subtree midi-ast "MidiTrack"))
(track-events (ast-subtrees track-ast))
(track-meta-divisions (filter meta-division-event? track-events))
(track-meta-division-names (map ast-text track-meta-divisions))
(init-stuff (midi-event-ast-subsequence track-events #t (third track-meta-division-names)))
(section-list
(map
(lambda (from to)
(midi-event-ast-subsequence track-events from to))
(cddr track-meta-division-names)
(append (cdddr track-meta-division-names) (list #t))))
(section-name-list (map no-spaces-in-string (cddr track-meta-division-names)))
(end-of-track-event (Meta 'deltaTime "0" 'type "47" "")))
(ensure-directory-existence! output-dir-path style-name)
(ensure-directory-existence! (string-append output-dir-path style-name "/") (as-string channel))
(for-each
(lambda (section section-name)
(let* ((init-events-for-selected-channel (select-channel channel init-stuff))
(body-events-for-selected-channel (select-channel channel section))
(target-file-path (string-append output-dir-path style-name "/" (as-string channel) "/" section-name "." "mid"))
)
(if (not (null? (filter (lambda (x) (and (ast? x) (equal? "NoteOn" (ast-element-name x)))) body-events-for-selected-channel)))
(let ((meta-info (make-meta-info-about-style-part
style-name-0 section-name channel style-file-path target-file-path
midi-header init-events-for-selected-channel body-events-for-selected-channel)))
(if meta-file-path (add-meta-info-to-meta-base meta-file-path meta-info))
(write-text-file
(standard-midi-file-ast-to-bin
(StandardMidiFile 'internal:run-action-procedure "false"
midi-header
(MidiTrack
init-events-for-selected-channel
body-events-for-selected-channel
end-of-track-event)))
target-file-path
))
'do-nothing)))
section-list section-name-list)))
(define (split-and-process-style-refined meta-file-path style-file-path output-dir-path mode)
(set! global-meta-info-list '())
(split-and-process-style-refined-1 meta-file-path style-file-path output-dir-path mode))
(define (split-and-process-style-refined-1 meta-file-path style-file-path output-dir-path mode)
(let ((midi-ast (midi-file-to-laml-ast style-file-path mode 0 #f #f)))
(for-each (lambda (channel)
(split-and-process-style-one-channel-given-ast-refined meta-file-path style-file-path midi-ast output-dir-path mode channel))
(number-interval 1 16))))
(define (split-and-process-all-styles-refined meta-file-path input-dir-path output-dir-path mode)
(set! global-meta-info-list '())
(split-and-process-all-styles-refined-1 meta-file-path input-dir-path output-dir-path mode))
(define (split-and-process-all-styles-refined-1 meta-file-path input-dir-path output-dir-path mode)
(let* ((file-list (directory-list input-dir-path))
(style-file-list (filter (lambda (fn) (member (downcase-string (file-name-extension fn)) (list "sty" "pst" "psc" "sst" "prs" "bcs"))) file-list)))
(for-each (lambda (style-file)
(display-message style-file)
(split-and-process-style-refined-1 meta-file-path (string-append input-dir-path style-file) output-dir-path mode)
(display-message "")
)
style-file-list)))
(define (split-and-process-all-style-directory-refined meta-file-path input-dir-path output-dir-path mode)
(set! global-meta-info-list '())
(split-and-process-all-style-directory-refined-1 meta-file-path input-dir-path output-dir-path mode)
)
(define (split-and-process-all-style-directory-refined-1 meta-file-path input-dir-path output-dir-path mode)
(let* ((directory-list (filter directory-exists? (map (lambda (subdir) (string-append input-dir-path subdir "/"))
(directory-list input-dir-path))))
(leave-output-dir (directory-leave-name output-dir-path))
(output-parent-dir (parent-directory output-dir-path))
)
(ensure-directory-existence! output-parent-dir leave-output-dir)
(for-each (lambda (dir)
(let ((leave-dir (directory-leave-name dir)))
(display-message "***" dir)
(ensure-directory-existence! output-dir-path leave-dir)
(split-and-process-all-styles-refined-1 meta-file-path dir (string-append output-dir-path leave-dir "/") mode)
(display-message ""))
)
directory-list)
(save-meta-info-on-file meta-file-path global-meta-info-list)
)
)
(define (make-meta-info-about-style-part style-name section-name channel style-file-path target-file-path
midi-header init-events-for-selected-channel body-events-for-selected-channel)
(let* ((nil-if-false (lambda (x) (if (and (boolean? x) (not x)) 'nil x)))
(ppqn (as-number (ast-attribute midi-header 'pulsesPerQuarterNote)))
(meta-time-signature-ast (find-in-list (lambda (x) (and (ast? x) (equal? "Meta" (ast-element-name x)) (equal? (ast-attribute x 'type #f) "88")))
init-events-for-selected-channel))
(time-signature (if meta-time-signature-ast (time-signature-of-meta-type-88-ast meta-time-signature-ast) #f))
(instrument-tuple (find-instrument-info-of channel init-events-for-selected-channel))
(instrument-name (if instrument-tuple (find-tyros-voice (first instrument-tuple) (second instrument-tuple) (third instrument-tuple)) #f))
(number-of-notes (length (filter (lambda (x) (and (ast? x) (equal? "NoteOn" (ast-element-name x)))) body-events-for-selected-channel)))
(number-of-different-notes (count-number-of-different-notes body-events-for-selected-channel))
(program-control-changes (program-control-change-info init-events-for-selected-channel body-events-for-selected-channel))
(length-of-body
(accumulate-right + 0
(map (lambda (ast) (as-number (ast-attribute ast 'deltaTime)))
(cdr
(filter (lambda (x) (ast? x)) body-events-for-selected-channel)))))
)
(list
(nil-if-false time-signature)
(ceiling (/ length-of-body ppqn))
number-of-notes
(nil-if-false instrument-tuple)
(nil-if-false instrument-name)
(nil-if-false section-name)
channel
ppqn
length-of-body
(nil-if-false style-name)
(nil-if-false (truncate-this-string "c:/users/kurt/Media/Tyros/Styles/midi/" style-file-path))
(nil-if-false (truncate-this-string "c:/users/kurt/Media/Tyros/Styles/midi/MIDI-PIECES/All-pieces/" target-file-path))
number-of-different-notes
program-control-changes
)
)
)
(define (count-number-of-different-notes midi-even-list)
(let ((occ-count (make-vector 128 0)))
(for-each
(lambda (x)
(if (and (ast? x) (equal? "NoteOn" (ast-element-name x)))
(let ((note (as-number (ast-attribute x 'note))))
(vector-set! occ-count note (+ 1 (vector-ref occ-count note)))))
)
midi-even-list)
(accumulate-right + 0 (map (lambda (note) (if (> (vector-ref occ-count note) 0) 1 0)) (number-interval 0 127)))))
(define (program-control-change-info init-event-list body-event-list)
(let* ((all-events (append init-event-list body-event-list))
(program-events (filter (lambda (x) (and (ast? x) (equal? "ProgramChange" (ast-element-name x)))) all-events))
(control-change-expression-events
(filter (lambda (x) (and (ast? x) (equal? "ControlChange" (ast-element-name x)) (= 11 (as-number (ast-attribute x 'control))))) all-events))
(pitch-bend-change-events
(filter (lambda (x) (and (ast? x) (equal? "PitchBendChange" (ast-element-name x)))) all-events))
)
(list (length program-events)
(length control-change-expression-events)
(length pitch-bend-change-events))))
(define (find-instrument-info-of channel midi-events-for-selected-channel)
(let* ((msb-ast (find-in-list (lambda (x) (and (ast? x)
(equal? "ControlChange" (ast-element-name x))
(= (as-number (ast-attribute x 'channel)) channel)
(equal? (ast-attribute x 'control #f) "0")))
midi-events-for-selected-channel))
(msb (if msb-ast (ast-attribute msb-ast 'value #f) #f))
(lsb-ast (find-in-list (lambda (x) (and (ast? x)
(equal? "ControlChange" (ast-element-name x))
(= (as-number (ast-attribute x 'channel)) channel)
(equal? (ast-attribute x 'control #f) "32")))
midi-events-for-selected-channel))
(lsb (if lsb-ast (ast-attribute lsb-ast 'value #f) #f))
(prog-number-ast (find-in-list (lambda (x) (and (ast? x)
(equal? "ProgramChange" (ast-element-name x))
(= (as-number (ast-attribute x 'channel)) channel)))
midi-events-for-selected-channel))
(prog-number (if prog-number-ast (ast-attribute prog-number-ast 'number #f) #f)))
(if (and msb lsb prog-number)
(list (as-number msb) (as-number lsb) (as-number prog-number))
#f) ))
(define global-meta-info-list '())
(define (add-meta-info-to-meta-base meta-file-path meta-info)
(set! global-meta-info-list (cons meta-info global-meta-info-list))
(if (= 0 (remainder (length global-meta-info-list) 1000))
(begin
(display "Saving meta info about midi-pieces... ")
(save-meta-info-on-file meta-file-path global-meta-info-list)
(display-message " DONE")))
)
(define (save-meta-info-on-file meta-file-path meta-info-list)
(if (not (file-exists? meta-file-path))
(let ((fnpe (file-name-proper-and-extension meta-file-path))
(fnip (file-name-initial-path meta-file-path)))
(display-message "Creating meta piece file" fnpe "in" fnip)
(if (directory-exists? fnip)
(file-write '() meta-file-path)
(laml-error "Trying to make meta midi piece file in non-existing directory" fnip))))
(file-write (reverse meta-info-list) meta-file-path)
)
(define (adapt-meta-info-file-to-relative-file-paths meta-info-path)
(let ((meta-lst (file-read meta-info-path)))
(file-write (map adapt-meta-entry-to-relative-file-paths meta-lst) meta-info-path)))
(define (adapt-meta-entry-to-relative-file-paths me)
(list (list-ref me 0) (list-ref me 1) (list-ref me 2) (list-ref me 3) (list-ref me 4) (list-ref me 5) (list-ref me 6) (list-ref me 7) (list-ref me 8) (list-ref me 9)
(truncate-this-string "c:/users/kurt/Media/Tyros/Styles/midi/" (list-ref me 10))
(truncate-this-string "c:/users/kurt/Media/Tyros/Styles/midi/MIDI-PIECES/All-pieces/" (list-ref me 11))
(list-ref me 12) (list-ref me 13)))
(define (truncate-this-string str in-str)
(let ((str-lgt (string-length str)))
(if (equal? (substring in-str 0 str-lgt) str )
(substring in-str str-lgt (string-length in-str))
(laml-error "truncate-this-string: problems" str in-str))))
(define (abs-time-message-list-to-delta-timing message-ast-list previous-abs-time)
(cond ((null? message-ast-list) '())
((ast? (car message-ast-list))
(let* ((message-ast (car message-ast-list))
(this-abs-time (as-number (ast-attribute message-ast 'absTime)))
(new-delta-time (- this-abs-time previous-abs-time))
)
(cons (sm-abs-to-delta-time message-ast new-delta-time)
(abs-time-message-list-to-delta-timing (cdr message-ast-list) this-abs-time))))
(else (cons (car message-ast-list) (abs-time-message-list-to-delta-timing (cdr message-ast-list) previous-abs-time)))))
(define (sm-abs-to-delta-time ast delta-time)
(make-ast (ast-element-name ast)
(ast-subtrees ast)
(append (list 'deltaTime
(as-string delta-time))
(but-props (ast-attributes ast) (list 'absTime)))
(ast-kind ast)
(ast-language ast)
(ast-internal-attributes ast)))
(define (delta-time-message-list-to-abs-timing message-ast-list start-time)
(cond ((null? message-ast-list) '())
((ast? (car message-ast-list))
(let* ((message-ast (car message-ast-list))
(delta-time (ast-attribute message-ast 'deltaTime))
(new-abs-time (+ start-time (as-number delta-time)))
)
(cons (sm-delta-to-abs-time message-ast new-abs-time)
(delta-time-message-list-to-abs-timing (cdr message-ast-list) new-abs-time))))
(else (cons (car message-ast-list) (delta-time-message-list-to-abs-timing (cdr message-ast-list) start-time)))))
(define (sm-delta-to-abs-time ast abs-time)
(let ((existing-info (ast-attribute ast 'info "")))
(make-ast (ast-element-name ast)
(ast-subtrees ast)
(append (list
'absTime (as-string abs-time)
)
(but-props (ast-attributes ast) (list 'deltaTime 'info)))
(ast-kind ast)
(ast-language ast)
(ast-internal-attributes ast))))
(define (split-arpeggio-recording source-file-path start-number target-dir-list . optional-parameter-list)
(let* ((expected-length (optional-parameter 1 optional-parameter-list #f))
(given-number-interval (optional-parameter 2 optional-parameter-list #f))
(target-dir (first target-dir-list))
(trimmed-target-dir (second target-dir-list))
(meta-target-dir (third target-dir-list))
(midi-ast (midi-file-to-laml-ast source-file-path 'absTime 0 #f))
(midi-header (ast-subtree midi-ast "MidiHeader"))
(track (ast-subtree midi-ast "MidiTrack"))
(messages (ast-subtrees track))
(sections (sublist-by-predicate messages (lambda (ast prev-ast n) (ControlChange? ast 0))))
(sections-1 (cdr sections))
(sections-2 (map (lambda (section)
(let* ((first-mes (first section))
(first-abs-time (midi 'absTime first-mes)))
(time-displace (- first-abs-time) section)))
sections-1))
(count (length sections-1))
)
(if (and expected-length (not (= expected-length count)))
(laml-error "Expected length: " expected-length " Actual length: " count))
(if (and given-number-interval (not (= expected-length (length given-number-interval))))
(laml-error "The explicitly given list has length" (length given-number-interval) ". The expected length is" expected-length))
(for-each
(lambda (section number)
(let* ((arp-meta-data (get-arpeggio-meta-info number))
(a-length (arp-length arp-meta-data))
(a-time-sig-str (arp-time-sig arp-meta-data))
(a-time-sig-lst (parse-arp-time-signature a-time-sig-str))
(nom (first a-time-sig-lst))
(denom (second a-time-sig-lst))
(target-file (string-append target-dir (as-string number) "." "mid"))
(trimmed-target-file (string-append trimmed-target-dir (as-string number) "." "mid"))
(total-length (total-length-of-message-list section))
(cc-and-pc-section (list-part 1 3 section))
(rest-section (cdr (cdr (cdr section))))
(first-abs-time (if (not (null? rest-section))
(midi 'absTime (first rest-section))
#f))
(time-displaced-rest-section
(time-displace-1 (if first-abs-time (- 480 first-abs-time) 480)
rest-section
))
(trimmed-time-displaced-rest-section
(filter (lambda (event-ast)
(< (midi 'absTime event-ast)
(+ 480 (* a-length nom (cond ((= denom 4) 480) ((= denom 8) 240) (else (laml-error "unsupported time sig")))))))
time-displaced-rest-section))
)
(if (file-exists? target-file) (delete-file target-file))
(if (file-exists? trimmed-target-file) (delete-file trimmed-target-file))
(analyze-arpeggio-for-recording-control! number time-displaced-rest-section arp-meta-data)
(analyze-arpeggio-and-write-results! meta-target-dir number cc-and-pc-section trimmed-time-displaced-rest-section time-displaced-rest-section arp-meta-data)
(write-text-file
(standard-midi-file-ast-to-bin
(StandardMidiFile 'internal:run-action-procedure "false"
midi-header
(MidiTrack
(Meta 'absTime "0" 'type "81" (tempo= (arp-tempo arp-meta-data)))
(midi-comment-abs-time 0 (string-append "Motif XS Arpeggio number " (as-string number)))
cc-and-pc-section
time-displaced-rest-section
(Meta 'absTime (+ total-length 960) 'type "47" "")
)))
target-file)
(write-text-file
(standard-midi-file-ast-to-bin
(StandardMidiFile 'internal:run-action-procedure "false"
midi-header
(MidiTrack
(Meta 'absTime "0" 'type "81" (tempo= (arp-tempo arp-meta-data)))
(midi-comment-abs-time 0 (string-append "Motif XS Arpeggio number " (as-string number)))
cc-and-pc-section
trimmed-time-displaced-rest-section
(Meta 'absTime
(+ 480 (* a-length nom (cond ((= denom 4) 480) ((= denom 8) 240) (else (laml-error "unsupported time sig")))))
'type "47" "")
)))
trimmed-target-file)
)
)
sections-2
(if given-number-interval given-number-interval (number-interval start-number (+ start-number count -1))))
)
)
(define (split-arpeggio-recording-via-pc-recording source-file-path start-number target-dir-list . optional-parameter-list)
(let* ((expected-length (optional-parameter 1 optional-parameter-list #f))
(given-number-interval (optional-parameter 2 optional-parameter-list #f))
(target-dir (first target-dir-list))
(trimmed-target-dir (second target-dir-list))
(meta-target-dir (third target-dir-list))
(midi-ast (midi-file-to-laml-ast source-file-path 'absTime 0 #f))
(midi-header (MidiHeader 'format "0" 'numberOfTracks "1" 'pulsesPerQuarterNote "480" 'mode "absTime" 'counterTransposition "0"))
(track (ast-subtree midi-ast "MidiTrack" 2))
(messages (ast-subtrees track))
(sections (sublist-by-predicate messages (lambda (ast prev-ast n) (ControlChange? ast 0))))
(sections-1 (cdr sections))
(sections-2 (map (lambda (section)
(let* ((first-mes (first section))
(first-abs-time (midi 'absTime first-mes)))
(time-displace (- first-abs-time) section)))
sections-1))
(count (length sections-1))
)
(if (and expected-length (not (= expected-length count)))
(laml-error "Expected length: " expected-length " Actual length: " count))
(if (and given-number-interval (not (= expected-length (length given-number-interval))))
(laml-error "The explicitly given list has length" (length given-number-interval) ". The expected length is" expected-length))
(for-each
(lambda (section number)
(let* ((arp-meta-data (get-arpeggio-meta-info number))
(target-file (string-append target-dir (as-string number) "." "mid"))
(total-length (total-length-of-message-list section))
(stretched-section (time-stretch-1 0.5 section))
(cc-and-pc-section (list-part 1 3 stretched-section))
(rest-section (cdr (cdr (cdr stretched-section))))
(first-abs-time (if (not (null? rest-section))
(midi 'absTime (first rest-section))
#f))
)
(if (file-exists? target-file) (delete-file target-file))
(analyze-arpeggio-for-recording-control! number rest-section arp-meta-data)
(write-text-file
(standard-midi-file-ast-to-bin
(StandardMidiFile 'internal:run-action-procedure "false"
midi-header
(MidiTrack
(Meta 'absTime "0" 'type "81" (tempo= (arp-tempo arp-meta-data)))
(midi-comment-abs-time 0 (string-append "Motif XS Arpeggio number " (as-string number)))
cc-and-pc-section
(time-displace-1 (if first-abs-time (- 480 first-abs-time) 480)
rest-section
)
(Meta 'absTime (+ total-length 960) 'type "47" "")
)))
target-file)
)
)
sections-2
(if given-number-interval given-number-interval (number-interval start-number (+ start-number count -1)))
)
)
)
(define (analyze-arpeggio-for-recording-control! arp-number midi-event-list arp-meta-data)
(let* ((midi-event-list-1 (filter ast? midi-event-list))
(a-length (arp-length arp-meta-data))
(a-time-sig-str (arp-time-sig arp-meta-data))
(a-time-sig-lst (parse-arp-time-signature a-time-sig-str))
(nom (first a-time-sig-lst))
(denom (second a-time-sig-lst))
(last-abs-time (ast-attribute (last midi-event-list-1) 'absTime))
(ppqn 480)
)
(cond ((= denom 4)
(let ((required-length (* nom ppqn a-length))
(actual-length (- (as-number last-abs-time) 480)))
(display-message
(string-append
(as-string arp-number) ": "
(if (> required-length actual-length) "!!" " ")
"Required length: " a-time-sig-str " " (as-string required-length ) ". " "Actual length: " (as-string actual-length)))))
((= denom 8)
(let ((required-length (* nom (/ ppqn 2) a-length))
(actual-length (- (as-number last-abs-time) 480)))
(display-message
(string-append
(as-string arp-number) ": "
(if (> required-length actual-length) "!!" " ")
"Required length: " "(" a-time-sig-str ")" " " (as-string required-length ) ". " "Actual length: " (as-string actual-length)))))
(else (display-message "Non-fit")))))
(define (analyze-arpeggio-and-write-results! target-dir arp-number cc-pc-events trimmed-midi-event-list untrimmed-midi-event-list arp-meta-data)
(let* (
(nil-if-false (lambda (x) (if (and (boolean? x) (not x)) 'nil 't)))
(midi-event-list-1 (filter ast? trimmed-midi-event-list))
(a-length (arp-length arp-meta-data))
(a-time-sig-str (arp-time-sig arp-meta-data))
(a-time-sig-lst (parse-arp-time-signature a-time-sig-str))
(nom (first a-time-sig-lst))
(denom (second a-time-sig-lst))
(last-abs-time (ast-attribute (last untrimmed-midi-event-list) 'absTime))
(ppqn 480)
(required-length (* nom ppqn a-length))
(actual-length (- (as-number last-abs-time) 480))
(msb-lsb-pc (find-instrument-info-of 1 cc-pc-events))
(number-of-notes (length (filter (lambda (x) (and (ast? x) (equal? "NoteOn" (ast-element-name x)))) midi-event-list-1)))
(number-of-different-notes (count-number-of-different-notes midi-event-list-1))
(program-control-changes (program-control-change-info cc-pc-events midi-event-list-1))
)
(let ((result
(list
(nil-if-false (<= required-length actual-length))
msb-lsb-pc
number-of-notes
number-of-different-notes
program-control-changes
)
)
(target-file (string-append target-dir (as-string arp-number) "." "dat"))
)
(if (file-exists? target-file) (delete-file target-file))
(file-write result target-file)
)
)
)
(define (parse-arp-time-signature time-sig-str)
(map as-number (split-string-by-predicate time-sig-str (lambda (ch) (eqv? ch #\/)))))
(define cached-arpeggio-list #f)
(define (get-arpeggio-meta-info arp-number)
(if cached-arpeggio-list
(list-ref cached-arpeggio-list (- arp-number 1))
(let ((arp-info-list (file-read (string-append midi-software-dir "data/Motif-xs-arps.dat"))))
(set! cached-arpeggio-list arp-info-list)
(list-ref arp-info-list (- arp-number 1)))))
(define arp-main-cat (make-selector-function 1 "arp-main-cat"))
(define arp-sub-cat (make-selector-function 2 "arp-sub-cat"))
(define arp-number (make-selector-function 3 "arp-number"))
(define arp-role (make-selector-function 4 "arp-role"))
(define arp-name (make-selector-function 5 "arp-name"))
(define arp-generation (make-selector-function 6 "arp-generation"))
(define arp-time-sig (make-selector-function 7 "arp-time-sig"))
(define arp-length (make-selector-function 8 "arp-lenght"))
(define arp-tempo (make-selector-function 9 "arp-tempo"))
(define arp-accent? (make-selector-function 10 "arp-accent?"))
(define arp-random-sfx? (make-selector-function 11 "arp-random-sfx?"))
(define arp-voice (make-selector-function 12 "arp-voice"))
(define arp-voice-specific (make-selector-function 13 "arp-voice-specific"))
(define (pitch-bend-scale factor)
(let ((mid-value 8192))
(lambda (value)
(+ (* (- value mid-value) factor) mid-value))))
(define (copy-midi-ast-list ast-lst)
(map copy-midi-ast ast-lst))
(define (copy-midi-ast x)
(if (ast? x)
(make-ast
(ast-element-name x)
(ast-subtrees x)
(copy-midi-property-list (ast-attributes x))
(ast-kind x)
(ast-language x)
(ast-internal-attributes x))
x))
(define (copy-midi-property-list plst)
(if (null? plst)
'()
(cons (car plst) (cons (cadr plst) (copy-midi-property-list (cddr plst))))))
(define (total-length-of-message-list message-list)
(let ((message-list-asts-only (filter ast? message-list)))
(cond ((abs-time-sequence? message-list)
(let* ((first-message (first message-list-asts-only))
(last-message (last message-list-asts-only)))
(- (time-of-message last-message) (time-of-message first-message))))
((delta-time-sequence? message-list)
(accumulate-right + 0 (map (lambda (ast) (time-of-message ast)) message-list-asts-only)))
(else (laml-error "total-length-of-message-list: Cannot determine time mode of message-list. Is the message-list maybe empty?")))))
(define (enforce-minimum-message-length min-length message-list)
(let ((lgt (total-length-of-message-list message-list)))
(if (< lgt min-length)
(append
message-list
(list (midi-null-event-delta-time (- min-length lgt) (string-append "Enforcing of minium length"))))
message-list)))
(define (icon name)
(cond ((equal? name "penguin") "S713")
((equal? name "butterfly") "S690")
((equal? name "candle") "S719")
((equal? name "banana") "S696")
((equal? name "orange") "S697")
((equal? name "lighting") "S718")
(else "S713")))
(define (note-complement note-str-list)
(let* ((note-list (string-to-list (transliterate note-str-list #\space "") (list #\,)))
(complement-note-list
(map (lambda (nn) (if (member nn note-list) #f nn)) note-name-list)))
(list-to-string (filter (lambda (x) x) complement-note-list) ",")))
(define (chord-complement chord-str-list)
(let* ((chord-list (string-to-list (transliterate chord-str-list #\space "") (list #\,)))
(complement-chord-list
(map (lambda (cn) (if (member cn chord-list) #f cn)) chord-name-list)))
(list-to-string (filter (lambda (x) x) complement-chord-list) ",")))
(define drum-map-vector
#(latin-percussion latin-percussion others others others others others
others others others others others snare-drum snare-drum snare-drum snare-drum snare-drum
latin-high-pitch snare-drum others bass-drum snare-drum bass-drum bass-drum snare-drum snare-drum others
snare-drum tom hi-hat tom hi-hat tom hi-hat tom tom crash-cymbal
tom ride-cymbal cymbal ride-cymbal others cymbal others crash-cymbal others ride-cymbal
latin-percussion latin-percussion latin-percussion latin-percussion latin-percussion
latin-percussion latin-percussion latin-high-pitch latin-high-pitch latin-high-pitch
latin-high-pitch latin-high-pitch latin-high-pitch latin-high-pitch latin-high-pitch
latin-high-pitch latin-high-pitch latin-high-pitch latin-high-pitch latin-high-pitch
others others latin-high-pitch others others
others others others undefined undefined others others
)
)
(define (drum-category-of-note-value note-value)
(if (and (>= note-value 13) (<= note-value 91))
(vector-ref drum-map-vector (- note-value 13))
'undefined))
(define (get-fixed-part-from-to-abstime the-fixed-part-full-path first-abs-time last-abs-time)
(let* ((fixed-part-ast-list (map uncompact-midi-laml-entry (file-read the-fixed-part-full-path))))
(filter-messages-1
(lambda (m) (and (>= (midi 'absTime m) first-abs-time) (<= (midi 'absTime m) last-abs-time)))
fixed-part-ast-list)
)
)
(define (end-sectional-playing delta-time)
(list
(midi-comment-delta-time delta-time "Ending part starts here")
(map (lambda (ch)
(ControlChange 'deltaTime "0" 'channel ch 'control "64" 'value "0"))
(number-interval 1 16))
(Meta 'deltaTime "10" 'type "47" "")
)
)