view tools/segmentation/simple-example.lisp @ 136:fd85f52d9f9d

Class revolution * PITCH-DESIGNATOR -> PITCH (PITCH removed) * MOMENT-DESIGNATOR -> MOMENT , MOMENT -> STANDARD-MOMENT * PERIOD-DESIGNATOR -> PERIOD , PERIOD -> STANDARD-PERIOD * ANCHORED-PERIOD-DESIGNATOR -> ANCHORED-PERIOD , ANCHORED-PERIOD -> STANDARD-ANCHORED-PERIOD * FLOATING-PERIOD removed * TIME-SIGNATURE-DESIGNATOR -> TIME-SIGNATURE & TIME-SIGNATURE-PERIOD * TIME-SIGNATURE -> STANDARD-TIME-SIGNATURE & STANDARD-TIME-SIGNATURE-PERIOD * KEY-SIGNATURE-DESIGNATOR -> KEY-SIGNATURE (& ...-PERIOD) * KEY-SIGNATURE -> STANDARD-KEY-SIGNATURE (& ...-PERIOD) * TEMPO now abstract (& TEMPO-PERIOD) * STANDARD-TEMPO AND STANDARD-TEMPO-PERIOD * COMPOSITION, CONSTITUENT & TIME-ORDERED-CONSTITUENT all have STANDARD- forms make-x methods and specialisers changes appropriately darcs-hash:20070831142943-f76cc-7be0d08963de06d87b36e4922076287d565c7ee2.gz
author David Lewis <d.lewis@gold.ac.uk>
date Fri, 31 Aug 2007 15:29:43 +0100
parents 8ea75cc8bc2c
children
line wrap: on
line source
(in-package "AMUSE-SEGMENTATION")

;;;;;;;;;;;;;;;;;
;; 
;; Demo example: `simple segmenter'
;;
;; Simple segmenter segments a piece at long gaps between notes (where
;; `gaps' are the amount of time between successive note-onsets).
;;
;; In this implementation, the modal gap-length is calculated (the
;; highest is taken in cases of a tie) and a threshold is taken of 3.9
;; times that length. An absolute gap of 1.5 seconds is also used if
;; beats-to-seconds is available.

(defclass simple-segmenter (after-segmenter) ())

(defmethod boundary-strength ((segmenter simple-segmenter) (event moment) (composition composition))
  (declare (ignore segmenter))
  (multiple-value-bind (i-o-i mode i-o-i-rt)
      (inter-onset-intervals-for-simple-segmenter-with-cache composition)
    (if (or (eq event (elt composition 0))
	    (> (cdr (assoc event i-o-i)) (* mode 3.9))
	    (and i-o-i-rt (> (cdr (assoc event i-o-i-rt))
			     1.5)))
	1
	0)))

;; helper-functions

(defparameter *i-o-i-cache* (make-hash-table :weakness :KEY))
(defun inter-onset-intervals-for-simple-segmenter-with-cache (composition &key (rounding-divisor 1/4))
  (unless (gethash composition *i-o-i-cache*)
    (setf (gethash composition *i-o-i-cache*)
	  (multiple-value-list (inter-onset-intervals-for-simple-segmenter composition
									   :rounding-divisor rounding-divisor))))
  (values-list (gethash composition *i-o-i-cache*)))

(defgeneric inter-onset-intervals-for-simple-segmenter (composition &key rounding-divisor)
  (:documentation "Returns values: inter-onset-intervals, i-o-i
  mode and real-time-i-o-is. Both sets of i-o-is are alists
  of (<event> . i-o-i)"))

(defmethod inter-onset-intervals-for-simple-segmenter ((composition composition)
						       &key (rounding-divisor 1/4))
  ;; FIXME: (vaguely) assumes monody
  (let ((i-o-i-list) (i-o-i-secs-list) (real-time t) (prev) (i-o-i-period)
	(hits (make-hash-table))
	(modal-value) (modal-count 0))
    (sequence:dosequence (event composition)
      (when prev
	(setf i-o-i-period (inter-onset-interval prev event))
	(when real-time
	  (setf i-o-i-secs-list
		(acons event (handler-case (beats-to-seconds i-o-i-period composition)
			       ((or undefined-action insufficient-information) ()
				   (setf real-time nil)))
		       i-o-i-secs-list)))
	(setf i-o-i-list (acons event (duration i-o-i-period) i-o-i-list))
	(when (> (round (duration i-o-i-period) rounding-divisor) 0)
	  ;; larger than 32 crotchets doesn't really count as a useful
	  ;; i-o-i for our purposes (or am I just doing this because
	  ;; I'm using an array).
	  (if (gethash (round (duration i-o-i-period) rounding-divisor) hits)
	      (incf (gethash (round (duration i-o-i-period) rounding-divisor) hits))
	      (setf (gethash (round (duration i-o-i-period) rounding-divisor) hits) 1))))
      (setf prev event))
    ;; we want the highest mode if there are several
    (maphash #'(lambda (key value) 
                 (when (> value modal-count)
                   (setf modal-value key 
                         modal-count value)))
             hits)
    (values i-o-i-list (* modal-value rounding-divisor) (and real-time i-o-i-secs-list))))