annotate tools/segmentation/simple-example.lisp @ 77:edc6633e09ce

simple-segmenter fix darcs-hash:20070713151502-f76cc-1b07f4a06f41a75100d05278bdded9d34265e12c.gz
author David Lewis <d.lewis@gold.ac.uk>
date Fri, 13 Jul 2007 16:15:02 +0100
parents 6b2ac9eef629
children 14e32f4d61d0
rev   line source
d@74 1 (in-package "AMUSE-SEGMENTATION")
d@74 2
d@74 3 ;;;;;;;;;;;;;;;;;
d@74 4 ;;
d@74 5 ;; Demo example: `simple segmenter'
d@74 6 ;;
d@74 7 ;; Simple segmenter segments a piece at long gaps between notes (where
d@74 8 ;; `gaps' are the amount of time between successive note-onsets).
d@74 9 ;;
d@74 10 ;; In this implementation, the modal gap-length is calculated (the
d@74 11 ;; highest is taken in cases of a tie) and a threshold is taken of 3.9
d@74 12 ;; times that length. An absolute gap of 1.5 seconds is also used if
d@74 13 ;; beats-to-seconds is available.
d@74 14
d@75 15 (defclass simple-segmenter (before-segmenter) ())
d@75 16
d@75 17 (defmethod boundary-strength ((segmenter simple-segmenter) (event moment-designator) (composition composition))
d@75 18 (declare (ignore segmenter))
d@75 19 (multiple-value-bind (i-o-i mode i-o-i-rt)
d@75 20 (inter-onset-intervals-for-simple-segmenter-with-cache composition)
d@75 21 (if (or (eq event (elt composition 0))
d@75 22 (> (cdr (assoc event i-o-i)) (* mode 3.9))
d@75 23 (and i-o-i-rt (> (cdr (assoc event i-o-i-rt))
d@75 24 1.5)))
d@75 25 1
d@75 26 0)))
d@74 27
d@74 28 (defgeneric simple-segmentsp (event composition))
d@74 29 (defmethod simple-segmentsp ((event moment-designator) (composition composition))
d@74 30 (multiple-value-bind (i-o-i mode i-o-i-rt)
d@74 31 (inter-onset-intervals-for-simple-segmenter-with-cache composition)
d@74 32 (if (or (eq event (elt composition 0))
d@74 33 (> (cdr (assoc event i-o-i)) (* mode 3.9))
d@74 34 (and i-o-i-rt (> (cdr (assoc event i-o-i-rt))
d@74 35 1.5)))
d@74 36 1
d@74 37 0)))
d@74 38
d@74 39 ;; helper-functions
d@74 40
d@74 41 (defparameter *i-o-i-cache* (make-hash-table :weakness :KEY))
d@74 42 (defun inter-onset-intervals-for-simple-segmenter-with-cache (composition &key (rounding-divisor 1/4))
d@74 43 (unless (gethash composition *i-o-i-cache*)
d@74 44 (setf (gethash composition *i-o-i-cache*)
d@74 45 (multiple-value-list (inter-onset-intervals-for-simple-segmenter composition
d@74 46 :rounding-divisor rounding-divisor))))
d@74 47 (values-list (gethash composition *i-o-i-cache*)))
d@74 48
d@74 49 (defgeneric inter-onset-intervals-for-simple-segmenter (composition &key rounding-divisor)
d@74 50 (:documentation "Returns values: inter-onset-intervals, i-o-i
d@74 51 mode and real-time-i-o-is. Both sets of i-o-is are alists
d@74 52 of (<event> . i-o-i)"))
d@74 53 (defmethod inter-onset-intervals-for-simple-segmenter ((composition composition)
d@74 54 &key (rounding-divisor 1/4))
d@74 55 ;; FIXME: (vaguely) assumes monody
d@74 56 (let ((i-o-i-list) (i-o-i-secs-list) (real-time t) (prev) (i-o-i-period)
d@77 57 (hits (make-hash-table))
d@74 58 (modal-value) (modal-count 0))
d@74 59 (sequence:dosequence (event composition)
d@74 60 (when prev
d@74 61 (setf i-o-i-period (inter-onset-interval prev event))
d@74 62 (when real-time
d@74 63 (setf i-o-i-secs-list
d@74 64 (acons event (handler-case (beats-to-seconds i-o-i-period composition)
d@74 65 ((or undefined-action insufficient-information) ()
d@74 66 (setf real-time nil)))
d@74 67 i-o-i-secs-list)))
d@74 68 (setf i-o-i-list (acons event (duration i-o-i-period) i-o-i-list))
d@77 69 (when (> (round (duration i-o-i-period) rounding-divisor) 0)
d@74 70 ;; larger than 32 crotchets doesn't really count as a useful
d@74 71 ;; i-o-i for our purposes (or am I just doing this because
d@77 72 ;; I'm using an array).
d@77 73 (if (gethash hits (round (duration i-o-i-period) rounding-divisor))
d@77 74 (incf (gethash hits (round (duration i-o-i-period) rounding-divisor)))
d@77 75 (setf (gethash hits (round (duration i-o-i-period) rounding-divisor)) 1)))
d@74 76 (setf prev event))
d@74 77 (loop for i downfrom (1- (length hits)) to 0
d@74 78 ;; we want the highest mode if there are several
d@74 79 when (> (aref hits i) modal-count)
d@74 80 do (setf modal-value i
d@74 81 modal-count (aref hits i)))
d@74 82 (values i-o-i-list (* modal-value rounding-divisor) (and real-time i-o-i-secs-list))))
d@74 83