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

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

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

;;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)