;;********************************************
;;********************************************
;;////////////////////////////////////////////
;;Pitch
Track from SPEAR files
;;////////////////////////////////////////////
;;Mauricio
Rodriguez - 2011
;;////////////////////////////////////////////
;;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:
;;analyze-spear-file
[]
;;(analyze-spear-file)
;;Code:
(defvar
*string-sequence* nil)
(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" "*.*"))))
(defun
load-text-file* ()
(setf *string-sequence* nil)
(setf *string-sequence*
(with-open-file (input (choose-file-dialog)
:direction :input)
(read-from
input))))
(defun read-from
(stream)
(let ((current-line (read-line stream
nil)))
(unless (not current-line)
(cons
current-line
(read-from stream)))))
;;(load-text-file*)
(defun
load-text-file ()
(load-text-file*)
(loop for x in *string-sequence*
collect (read-from-string (concatenate 'string "(" x
")"))))
;;(load-text-file)
(defun
append-data (list)
(if (endp list)
nil
(cons (second list)
(append-data (rest (rest list))))))
(defun data-text-file
(list)
(let ((non-header (nthcdr 4 list)))
(append-data non-header)))
(defun
get-delta-time (list)
(if (endp list)
nil
(cons (first list)
(get-delta-time (nthcdr 3 list)))))
(defun
get-frequency (list)
(if (endp list)
nil
(cons (second list)
(get-frequency (nthcdr 3 list)))))
(defun
get-amplitude (list)
(if (endp list)
nil
(cons (third list)
(get-amplitude (nthcdr 3 list)))))
(defvar
*store-data* nil)
(defun
load-data ()
(setf *store-data* nil)
(setf *store-data* (data-text-file
(load-text-file))))
;;(load-data)
;;*store-data*
(defun
time-table (list)
(sort (remove-duplicates (loop for
alpha in (mapcar #'(lambda (x) (get-delta-time x)) list)
append alpha)) #'<))
(defun
grouping (list)
(cond ((endp list) nil)
(t
(append (list (list (first list) (second list) (third list)))
(grouping (nthcdr 3 list))))))
#|
(defun
filter-amplitude-threshold* (list threshold)
(let ((group-list (grouping list)))
(loop for x in group-list
when (or
(>= (third x) threshold)
(equal (third x) 0.0))
collect x)))
|#
(defun
filter-amplitude-threshold (list threshold)
(let* ((group-list (grouping list))
(filter (loop for x in group-list
when (or (>= (third x) threshold)
(equal (third x) 0.0))
collect x)))
(loop for y in filter
append y)))
(defun
locate-timing (time-point list)
(loop for x in list
when (= time-point (first x))
collect x))
;;(locate-timing
0.0 (grouping (loop for beta in (mapcar #'(lambda (x)
(filter-amplitude-threshold x 0.005)) *store-data*) append beta)))
;;(locate-timing
0.137438 (grouping (loop for beta in (mapcar #'(lambda (x)
(filter-amplitude-threshold x 0.005)) *store-data*) append beta)))
(defun
get-max-amplitude (list)
(let ((maximum (apply #'max (loop for x
in list
collect
(third x)))))
(loop for alpha in list
when (equal
maximum (third alpha))
collect
alpha)))
(defun
get-max-frequency (list)
(let ((maximum (apply #'max (loop for x
in list
collect (second x)))))
(loop for alpha in list
when (equal
maximum (second alpha))
collect
alpha)))
(defun
locate-timing-filter* (list)
(let ((max-amplitude (get-max-amplitude
list)))
(if (= (length
max-amplitude) 1)
(first max-amplitude)
(first
(get-max-frequency max-amplitude)))))
(defun
partials-data (amplitude-threshold list)
(let* ((filter-threshold (mapcar
#'(lambda (x) (filter-amplitude-threshold x amplitude-threshold)) list))
(time-points (time-table filter-threshold))
(group-data (grouping (loop for x in filter-threshold
append
x))))
(loop for y in time-points
collect
(locate-timing-filter* (locate-timing y group-data)))))
;;(partials-data
0.005 *store-data*)
#|
(defun
continuity-p (reference-value input)
(or (= reference-value input)
(and (>
input reference-value) (<= input (+ reference-value 1)))
(and (<
input reference-value) (>= input (- reference-value 1)))))
(defun
continuity-p (reference-value input)
(cond ((equal input 'nil) t)
((or (= reference-value input)
(and
(> input reference-value) (<= input (+ reference-value 1)))
(and (< input reference-value) (>= input (- reference-value 1))))
t)
(t
'nil)))
|#
(defun
continuity-p (reference-value input resolution)
(cond ((equal input 'nil) t)
((or (= reference-value input)
(and (> input reference-value) (<= input (+ reference-value
resolution)))
(and (< input reference-value) (>= input (- reference-value
resolution)))) t)
(t
'nil)))
#|
(defun
sequence-continuity (list)
(do ((reference-value (first list) (first
current-list))
(current-list (rest list) (rest current-list))
(output
(list (first list)) (cons (first current-list) output)))
((or (endp
current-list) (not (continuity-p reference-value (first current-list))))
(reverse output))))
|#
(defun
sequence-continuity (list resolution)
(do ((reference-value (first list)
(first current-list))
(current-list
(rest list) (rest current-list))
(output
(list (first list)) (cons (first current-list) output)))
((or (endp
current-list) (not (continuity-p reference-value (first current-list)
resolution))) (reverse output))))
#|
(defun
group-continuity (list)
(do ((output nil (cons
(sequence-continuity current-list) output))
(current-list list (nthcdr (length (sequence-continuity current-list))
current-list)))
((endp
current-list) (reverse output))))
|#
(defun
group-continuity (list resolution)
(do ((output nil (cons (sequence-continuity
current-list resolution) output))
(current-list list (nthcdr (length (sequence-continuity current-list
resolution)) current-list)))
((endp
current-list) (reverse output))))
(defun
group-frequency-continuity (list resolution)
(group-continuity
(loop for x in list
collect (second x))
resolution))
(defun
length-index (list)
(loop for x in list
collect (length x)))
(defun
gather-n (list n)
(if (= n 0) nil
(cons (first
list) (gather-n (rest list) (1- n)))))
(defun
group-list (list index-group)
(do ((current-list list (nthcdr (first
indexing) current-list))
(indexing
index-group (rest indexing))
(output
nil (cons (gather-n current-list (first indexing)) output)))
((endp
indexing) (reverse output))))
(defun
flat-once (compound-list)
(loop for x in compound-list
collect (loop for y in x
append y)))
#|
(defun
group-partials (amplitude-threshold list resolution)
(let* ((data (partials-data
amplitude-threshold list))
(index (length-index (group-frequency-continuity data resolution))))
(flat-once (group-list data
index))))
;;(group-partials
0.005 *store-data* 40)
|#
(defun
group-partials (amplitude-threshold list resolution)
(let* ((data (partials-data
amplitude-threshold list))
(index (length-index (group-frequency-continuity data resolution))))
(group-list data index)))
;;(group-partials
0.005 *store-data* 40)
(defun
choose-new-file-dialog (&key (prompt "Save File") (operation
:save))
(choose-file-dialog :prompt prompt
:operation operation))
(defun
flatten-list (list)
(cond ((endp list) nil)
((listp (first list))
(append (flatten-list (first list))
(flatten-list (rest list))))
(t
(cons (first list)
(flatten-list (rest list))))))
(defun
spear-format (amplitude-threshold resolution)
(let ((partials (group-partials
amplitude-threshold *store-data* resolution)))
(with-open-file (output
(choose-new-file-dialog)
:direction :output
:if-exists :supersede)
(do
((current-list partials (rest current-list))
(index
0 (+ 1 index))
(printing
(progn
(format output "~&~a" "par-text-partials-format")
(format output "~&~a" "point-type time frequency amplitude")
(format output "~&~a ~a" "partials-count" (length partials))
(format output "~&~a" "partials-data"))
(progn
(format output "~&~a ~a ~,6f ~,6f"
index
(length (first current-list))
(third (first (last (first current-list))))
(first (first (last (first current-list)))))
(format output "~&~{~,6f ~}" (flatten-list (first
current-list))))))
((endp
current-list) t)))))
(defun
convert-frequency-to-midi (frequency)
(+ 69 (* 12 (/ (log (/ frequency 440.0)
10) (log 2 10)))))
(defun
frequency-to-midi (input-list)
(mapcar #'convert-frequency-to-midi
input-list))
(defun
mean-value (list)
(/ (apply #'+ list) (float (length
list))))
(defun
mean-frequency (list)
(loop for x in list
collect (convert-frequency-to-midi (mean-value (get-frequency x)))))
;;(load-data)
;;*store-data*
;;(spear-format
0.005 40)
;;(length
(mean-frequency *store-data*))
(defun
take-n (n input)
(if (zerop n)
'nil
(cons (first input) (take-n
(- n 1) (rest input)))))
(defun
normalize (x a b c d)
(+ c (* (- x a) (/ (float (- d c)) (- b
a)))))
(defun normalize-list-frequency
(input)
(let ((minimum (apply #'min input))
(maximum (apply #'max input)))
(mapcar #'(lambda (x)
(normalize x minimum maximum 0.0 1.0)) input)))
(defun
save-pitch-analysis ()
(with-open-file
(output
(make-pathname :directory '(:absolute "users" "home"
"directory")
:name "pitch-analysis"
:type "txt")
:direction :output
:if-exists :supersede)
(loop for x in
(normalize-list-frequency (mean-frequency *store-data*))
for string =
"~,2f" then " ~&~,2f"
do (format
output string x))
't))
;;(save-pitch-analysis)
(defun
analyze-spear-file ()
(load-data)
(spear-format 0.005 40)
(save-pitch-analysis))
;;(analyze-spear-file)