;;********************************************

;;********************************************

;;////////////////////////////////////////////

;;Quantize Time-Onsets into RTM

;;////////////////////////////////////////////

;;Mauricio Rodriguez - 2007

;;////////////////////////////////////////////

;;marod@ccrma.stanford.edu

;;////////////////////////////////////////////

;;********************************************

;;********************************************

#|

******************************

******************************

Use and copying of this software and preparation of derivative works

based upon this software are prohibited unless permission of the author.

Suggestions, comments and bug reports are welcome. Please address email to:

marod@ccrma.stanford.edu

******************************

******************************

|#

;;Main:

;; quantize-to-pwgl [beats-per-measure rhythmic-pattern]

;;(quantize-to-pwgl '(4) '(0.0 0.6 1.0 2.2))

;;Code:

(defun subdivision-list (n)

(let ((ratio (/ 1.0 n)))

(loop for x from 0 to n collect (* x ratio))))

;;(subdivision-list 16)

#|

(defun absolute-difference (value list)

(mapcar #'(lambda (x) (abs (- value x))) list))

|#

(defun absolute-difference (value list)

(apply #'min  (mapcar #'(lambda (x) (abs (- value x)))

list)))

(defun absolute-difference-in-lists (rhythmic-list subdivision-list)

(loop for x in rhythmic-list collect (absolute-difference x subdivision-list)))

#|

(defun minimal-deviation-sieve* (rhythmic-pattern-list)

(do ((current-subdivision

(loop for x from 8 to 16 collect x)

(rest current-subdivision))

(output nil (cons

(list (first current-subdivision)

(apply #'+ (absolute-difference-in-lists

rhythmic-pattern-list

(subdivision-list

(first current-subdivision)))))

output)))

((endp current-subdivision) (reverse output))))

(defun minimal-deviation-sieve* (rhythmic-pattern-list)

(do ((current-subdivision

(loop for x from 1 to 100 collect x)

(rest current-subdivision))

(output nil (cons

(list (first current-subdivision)

(apply #'+ (absolute-difference-in-lists

rhythmic-pattern-list

(subdivision-list

(first current-subdivision)))))

output)))

((endp current-subdivision) (reverse output))))

(defun minimal-deviation-sieve (rhythmic-pattern-list)

(do ((current-subdivision

(loop for x from 1 to 100 collect x)

(rest current-subdivision))

(output nil (cons

(apply #'+ (absolute-difference-in-lists

rhythmic-pattern-list

(subdivision-list

(first current-subdivision))))

output)))

((endp current-subdivision) (reverse output))))

|#

(defun minimal-deviation-sieve* (rhythmic-pattern-list)

(do ((current-subdivision

(loop for x from 1 to 16 collect x)

(rest current-subdivision))

(output nil (cons

(list (first current-subdivision)

(apply #'+ (absolute-difference-in-lists

rhythmic-pattern-list

(subdivision-list

(first current-subdivision)))))

output)))

((endp current-subdivision) (reverse output))))

(defun minimal-deviation-sieve (rhythmic-pattern-list)

(do ((current-subdivision

(loop for x from 1 to 16 collect x)

(rest current-subdivision))

(output nil (cons

(apply #'+ (absolute-difference-in-lists

rhythmic-pattern-list

(subdivision-list

(first current-subdivision))))

output)))

((endp current-subdivision) (reverse output))))

;;////////////////////////////////////////////

;; To add fitting function:

;;////////////////////////////////////////////

#|

(defun fitting-function (n)

(loop for x from 1 to n collect (/ .25 x)))

(defun fitting-function (n)

(loop for x from 2 to n collect (/ 2.0 x)))

(defun fitting-deviation-difference (rhythmic-pattern-list)

(do ((index

(loop for x from 1 to 100

collect x)

(rest index))

(fitting

(fitting-function 100)

(rest fitting))

(deviation

(minimal-deviation-sieve rhythmic-pattern-list)

(rest deviation))

(output

nil

(cons (list (first index)

(- (first fitting) (first deviation)))

output)))

((or (endp index)

(endp fitting)

(endp deviation))

(reverse output))))

(defun fitting-deviation-difference (rhythmic-pattern-list)

(do ((index

(loop for x from 1 to 100

collect x)

(rest index))

(fitting

(loop for x from 1 to 100 collect (/ (/ (- (length rhythmic-pattern-list) 2) 4.0) x))

(rest fitting))

(deviation

(minimal-deviation-sieve rhythmic-pattern-list)

(rest deviation))

(output

nil

(cons (list (first index)

(- (first fitting) (first deviation)))

output)))

((or (endp index)

(endp fitting)

(endp deviation))

(reverse output))))

|#

(defun fitting-deviation-difference (rhythmic-pattern-list)

(do ((index

(loop for x from 1 to 16

collect x)

(rest index))

(fitting

(loop for x from 1 to 16 collect (/ (/ (- (length rhythmic-pattern-list) 2) 4.0) x))

(rest fitting))

(deviation

(minimal-deviation-sieve rhythmic-pattern-list)

(rest deviation))

(output

nil

(cons (list (first index)

(- (first fitting) (first deviation)))

output)))

((or (endp index)

(endp fitting)

(endp deviation))

(reverse output))))

#|

(defun search-max-in-compound-list (max list)

(loop for x in list

for y = (second x)

when (= max y )

return (first x)))

|#

(defun search-max-in-compound-list (list)

(let ((maxima

(apply #'max (loop for z in list

collect (second z)))))

(loop for x in list

for y = (second x)

when (= maxima y )

return (first x))))

(defun offset-list (list offset-value)

(mapcar #'(lambda (x) (+ x offset-value))

list))

#|

(defun quantize-rhythm* (event-list)

(search-max-in-compound-list

(mapcar #'list

(loop for x from 1 to 100

collect x)

(mapcar #'/

(loop for x in (fitting-deviation-difference event-list)

collect (second x))

(offset-list (minimal-deviation-sieve event-list) 0.005)))))

(defun quantize-rhythm* (event-list)

(search-max-in-compound-list

(rest (mapcar #'list

(loop for x from 1 to 100

collect x)

(mapcar #'/

(loop for x in (fitting-deviation-difference event-list)

collect (second x))

(offset-list (minimal-deviation-sieve event-list) 0.005))))))

(defun quantize-rhythm* (event-list)

(if (equal event-list '(0.0 1.0))

1

(search-max-in-compound-list

(rest (mapcar #'list

(loop for x from 1 to 100

collect x)

(mapcar #'/

(loop for x in (fitting-deviation-difference event-list)

collect (second x))

(offset-list (minimal-deviation-sieve event-list) 0.005)))))))

|#

(defun quantize-rhythm* (event-list)

(if (equal event-list '(0.0 1.0))

1

(search-max-in-compound-list

(rest (mapcar #'list

(loop for x from 1 to 16

collect x)

(mapcar #'/

(loop for x in (fitting-deviation-difference event-list)

collect (second x))

(offset-list (minimal-deviation-sieve event-list) 0.005)))))))

#|

(search-max-in-compound-list

(rest (mapcar #'list

(loop for x from 1 to 100

collect x)

(mapcar #'/

(loop for x in (fitting-deviation-difference '(0.0 0.063 1.0))

collect (second x))

(offset-list (minimal-deviation-sieve '(0.0 0.063 1.0)) 0.005)))))

(search-max-in-compound-list

(rest (mapcar #'list

(loop for x from 1 to 100

collect x)

(mapcar #'/

(loop for x in (fitting-deviation-difference '(0.0 0.05 1.0))

collect (second x))

(offset-list (minimal-deviation-sieve '(0.0 0.05 1.0)) 0.005)))))

|#

;;////////////////////////////////////////////

;;Quantify and get beat proportions:

;;////////////////////////////////////////////

(defun build-difference (value list)

(mapcar #'(lambda (x) (list x (abs (- value x)))) list))

(defun search-min-in-compound-list (list)

(let ((minima

(apply #'min (loop for z in list

collect (second z)))))

(loop for x in list

for y = (second x)

when (= minima y )

return (first x))))

(defun rhythmic-approximation* (rhythmic-pattern rhythmic-reservoir)

(if (endp rhythmic-pattern)

nil

(cons

(search-min-in-compound-list

(build-difference

(first rhythmic-pattern)

rhythmic-reservoir))

(rhythmic-approximation* (rest rhythmic-pattern) rhythmic-reservoir))))

#|

(defun rhythmic-approximation (rhythmic-pattern)

(rhythmic-approximation*

rhythmic-pattern

(subdivision-list

(search-max-in-compound-list

(rest (fitting-deviation-difference rhythmic-pattern))))))

|#

(defun rhythmic-approximation (rhythmic-pattern)

(rhythmic-approximation*

rhythmic-pattern

(subdivision-list

(quantize-rhythm* rhythmic-pattern))))

;;(rhythmic-approximation '(0.0 0.21 0.42 1.0))

;;(rhythmic-approximation '(0.0 0.21 0.42 0.6 1.0))

;;(rhythmic-approximation '(0.0 0.1429 1.0))

(defun make-pairs* (list)

(if (endp list)

nil

(cons (List (first list) (second list))

(make-pairs* (rest list)))))

(defun make-pairs (list)

(let ((current-list (make-pairs* list)))

(loop for x in current-list

when (not (equal (second x) nil))

collect x)))

(defun pair-difference (x y)

(abs (- x y)))

(defun list-difference (list)

(mapcar #'(lambda (x) (pair-difference (first x) (second x))) (make-pairs list)))

(defun beat-approximation* (pattern subdivision-ratio)

(let ((current-pattern (list-difference pattern)))

(loop for x in current-pattern

collect (round (/ x subdivision-ratio)))))

(defun beat-approximation (pattern subdivision-ratio)

(let ((check-beat-approximation (beat-approximation* pattern subdivision-ratio)))

(loop for x in check-beat-approximation

when (/= 0 x)

collect x)))

#|

(defun quantize-pattern (rhythmic-pattern)

(beat-approximation

(rhythmic-approximation

rhythmic-pattern)

(/ 1.0

(search-max-in-compound-list

(rest (fitting-deviation-difference rhythmic-pattern))))))

|#

(defun quantize-pattern (rhythmic-pattern)

(beat-approximation

(rhythmic-approximation

rhythmic-pattern)

(/ 1.0 (quantize-rhythm* rhythmic-pattern))))

;;////////////////////////////////////////////

;; To build RTM:

;;////////////////////////////////////////////

(defun events-and-markers (event-list)

(let* ((markers (loop for x from 0.0 to (ceiling (first (last event-list)))

collect (float x)))

(compound-list (remove-duplicates (sort (append event-list markers) #'<))))

compound-list))

(defun mark-events* (event-list)

(let* ((markers (loop for x from 0.0 to (ceiling (first (last event-list)))

collect (float x)))

(compound-list (remove-duplicates (sort (append event-list markers) #'<))))

(do ((current-compound-list compound-list (rest current-compound-list))

(output nil (if (find (first current-compound-list) event-list)

(cons (list (first current-compound-list) 0)

output)

(cons (list (first current-compound-list) 1)

output))))

((endp current-compound-list) (reverse output)))))

(defun mark-events (event-list)

(mark-events* (append event-list (list (float (ceiling (first (last event-list))))))))

(defun get-tied-beats* (marked-events)

(let ((beats (loop for x from 0.0 to (first (first (last marked-events)))

collect x)))

(loop for alpha in (loop for x in beats

collect (loop for y in marked-events

when (equal x (first y))

collect (second y)))

append alpha)))

(defun tie-indexing (rhythmic-pattern)

(butlast

(get-tied-beats*

(mark-events rhythmic-pattern))))

#|

(defun pseudo-integer-p (number)

(if (= (- number (truncate number)) 0)

t

nil))

(defun gather-until-pseudo-integer (list)

(if (or (endp list) (pseudo-integer-p (first list)))

nil

(cons (first list)

(gather-until-pseudo-integer (rest list)))))

|#

(defun collect-within-range (low high list)

(loop for x in list

when (and (>= x low)

(<= x high))

collect x))

(defun split-by-beats (list)

(do ((low -1.0 (incf low))

(high 0.0 (incf high))

(output nil (cons (collect-within-range low high list)

output)))

((equal high (first (last list))) (reverse output))))

(defun normalize-list-member (list)

(if (= (apply #'max list) 1.0)

list

(mapcar #'(lambda (x) (- x (- (apply #'max list) 1.0)))

list)))

(defun normalize-list (list)

(loop for x in list

collect (normalize-list-member x)))

(defun normalize-rhtyhm (rhythmic-pattern)

(normalize-list

(split-by-beats

(events-and-markers rhythmic-pattern))))

#|

(defun quantizer* (rhythmic-pattern)

(let ((ties (tie-indexing rhythmic-pattern)))

(list (loop for x in (normalize-rhtyhm rhythmic-pattern)

collect (quantize-pattern x))

ties)))

|#

(defun quantizer** (rhythmic-pattern)

(let ((ties (tie-indexing rhythmic-pattern)))

(list (loop for x in (normalize-rhtyhm rhythmic-pattern)

collect (quantize-pattern x))

ties)))

(defun quantizer* (list)

(if (= 0 (- (first (last list)) (ceiling (first (last list)))))

(quantizer** (append list (list (+ 1.0 (first (last list))))))

(quantizer** list)))

(defun convert-to-tied (list index)

(if (= index 0)

list

(cons (* (first list) 1.0) (rest list))))

(defun quantize-to-simple-rtm (rhythmic-pattern)

(let ((rtm-and-ties (quantizer* rhythmic-pattern)))

(do ((current-rtm-cells (first rtm-and-ties) (rest current-rtm-cells))

(current-tie-indexing (second rtm-and-ties) (rest current-tie-indexing))

(output nil (cons (convert-to-tied (first current-rtm-cells)

(first current-tie-indexing))

output)))

((endp current-rtm-cells) (reverse output)))))

;;(quantize-to-simple-rtm '(0.0 0.6 1.0 2.2))

(defun take-n (n list)

(if (or (= n 0) (endp list))

nil

(cons (first list) (take-n (1- n) (rest list)))))

(defun clon-n (n element)

(if (= n 0)

nil

(cons element (clon-n (decf n) element))))

(defun chain-rest (n list)

(let ((difference-value (- n (length list))))

(append list (clon-n difference-value '(-1)))))

(defun group-measures* (beats-per-measure-list list)

(do ((current-beat-list

beats-per-measure-list

(if (= (length current-beat-list) 1)

beats-per-measure-list

(rest current-beat-list)))

(current-list

list

(nthcdr (first current-beat-list) current-list))

(output

nil

(cons (take-n (first current-beat-list) current-list) output)))

((endp current-list) (reverse output))))

(defun group-measures (beats-per-measure-list list)

(let ((group-list (group-measures* beats-per-measure-list list)))

(do ((current-beat-list

beats-per-measure-list

(if (= (length current-beat-list) 1)

beats-per-measure-list

(rest current-beat-list)))

(current-list

group-list

(rest current-list))

(output

nil

(cons (chain-rest (first current-beat-list) (first current-list)) output)))

((endp current-list) (reverse output)))))

(defun make-rtm-beat (list)

(if (endp list)

nil

(cons (list 1 (first list))

(make-rtm-beat (rest list)))))

(defun make-rtm-measure (list)

(mapcar #'(lambda (x) (make-rtm-beat x))

list))

(defun quantize-to-pwgl (beats-per-measure rhythmic-pattern)

(make-rtm-measure

(group-measures

beats-per-measure

(quantize-to-simple-rtm rhythmic-pattern))))

;;(quantize-to-pwgl '(4) '(0.0 0.6 1.0 2.2))

#|

(quantize-to-pwgl '(4)

'(

0.0

1.615487528

1.766258503

2.284195011

2.887165532

4.676689342

4.84340136

4.994217687

5.311337868

5.613673469

5.947256235

6.414693877

6.900521541

7.439387755

8.289863945

9.359183673

9.476984126

9.861405895

))

|#

;;To load delta time in LispWorks

(defun choose-file-dialog (&key (prompt "Open file")  (operation :open))

(let ((screen (capi:convert-to-screen)))

(capi:screen-width screen)

(capi:screen-height screen)

(capi:prompt-for-file prompt

:operation operation

:owner screen

:filters '("All Files" "*.*"))))

(defvar *time-points* nil)

(defun load-delta-time ()

(setf *time-points* (fibo-process-starting-at-zero

(with-open-file (input (choose-file-dialog)

:direction :input)

(read-from input)))))

(defun read-from (stream)

(let ((this-object (read stream nil)))

(unless (not this-object)

(cons this-object

(read-from stream)))))

(defun fibo-process-starting-at-zero (list)

(let ((fibo-process (do ((sum (first list) (+ sum (first local-list)))

(local-list (rest list) (rest local-list))

(output-list nil (cons sum output-list)))

((not local-list)

(reverse (cons (+ (first (last list))

(first output-list))

output-list))))))

(cons 0.0 (butlast fibo-process))))

#|

(defun cleaning-taps (tap-list)

(if (endp tap-list)

nil

(cons (first tap-list)

(cleaning-taps (rest tap-list)))))

;;(load-delta-time)

|#

(defun current-delta-time ()

*time-points*)

(defun tolerance-check (value reference tolerance)

(if (>= (abs (- value reference)) tolerance)

value

reference))

(defun tolerance-check-in-list (value-list reference-list tolerance)

(loop for x in value-list

collect (loop for y in reference-list

collect (tolerance-check x y tolerance))))

;;(tolerance-check-in-list '(0.0 0.52 0.99 1.0 1.019 2.9719) '(0.0 1.0 2.0 3.0) 0.05)

(defun member-check (element list)

(let ((current-list list))

(if (equal 'nil (remove element current-list))

element

(first (remove element current-list)))))

(defun normalize-list-to-tolerance* (list tolerance)

(let ((markers (loop for x from (floor (first list)) to (ceiling (first (last list)))

collect (float x))))

(do ((current-list

list

(rest current-list))

(tolerance-list

(tolerance-check-in-list

list

markers

tolerance)

(rest tolerance-list))

(current-markers

markers

(rest current-markers))

(output

nil

(cons (member-check (first current-list)

(first tolerance-list))

output)))

((endp current-list) (reverse output)))))

;;(normalize-list-to-tolerance* '(0.0 0.52 0.99 1.0 1.019 2.9719) 0.05)

(defun normalize-list-to-tolerance (list tolerance)

(remove-duplicates (normalize-list-to-tolerance* list tolerance)))

;;(normalize-list-to-tolerance '(0.0 0.52 0.99 1.0 1.019 2.9719) 0.05)