diff utils/utils.lisp @ 33:d1010755f507

Large upload of local changes. Many additions, such as harmony and piece-level objects darcs-hash:20070413100909-f76cc-a8aa8dfc07f438dc0c1a7c45cee7ace2ecc1e6a5.gz
author David Lewis <d.lewis@gold.ac.uk>
date Fri, 13 Apr 2007 11:09:09 +0100
parents e2e19baba730
children ad321ce17e3e
line wrap: on
line diff
--- a/utils/utils.lisp	Mon Dec 18 13:23:31 2006 +0000
+++ b/utils/utils.lisp	Fri Apr 13 11:09:09 2007 +0100
@@ -2,3 +2,79 @@
 
 (cl:in-package #:amuse-utils) 
 
+;; Booleans (for filters)
+(defgeneric pitchedp (event)
+  (:method (e) (declare (ignore e)) nil))
+(defmethod pitchedp ((event amuse:pitched-event))
+  T)
+(defgeneric unpitchedp (event)
+  (:method (e) (not (pitchedp e))))
+
+;; Rhythm methods
+(defgeneric crotchets-in-a-bar (time-signature))
+(defmethod crotchets-in-a-bar ((time-signature basic-time-signature))
+  (let ((num (time-signature-numerator time-signature))
+	(den (time-signature-denominator time-signature)))
+    (* num (/ 4 den))))
+
+;; Pitch methods
+
+(defgeneric sounding-events (anchored-period sequence))
+(defmethod sounding-events ((anchored-period anchored-period)
+			    (sequence composition))
+  (let ((sounding))
+    (sequence:dosequence (event sequence (reverse sounding))
+      (cond
+	((time>= event (cut-off anchored-period))
+	 (return-from sounding-events (reverse sounding)))
+	((period-intersection anchored-period event)
+	 (push event sounding))))))
+
+(defgeneric midi-pitch-distribution (anchored-period composition))
+(defmethod midi-pitch-distribution ((anchored-period anchored-period)
+				    composition)
+  (let ((pitches (make-array 128 :initial-element 0)))
+    (dolist (event (remove-if #'unpitchedp (sounding-events anchored-period composition)) pitches)
+      (let ((overlap (period-intersection anchored-period event)))
+	(if overlap
+	    (incf (aref pitches (midi-pitch-number event))
+		  (duration overlap))
+	    (if (= (duration event) 0)
+		(format t "~%Note ~D beats in has no duration" (timepoint event))
+		(error "This function has gone wrong - looking for overlaps that don't exist")))))))
+
+(defgeneric pitch-class-distribution (anchored-period composition))
+(defmethod pitch-class-distribution ((anchored-period anchored-period)
+				     composition)
+  (let ((pitches (make-array 12 :initial-element 0)))
+    (dolist (event (remove-if #'unpitchedp (sounding-events anchored-period composition)) pitches)
+      (let ((overlap (period-intersection anchored-period event)))
+	(if overlap
+	    (incf (aref pitches (pitch-class event))
+		  (duration overlap))
+	    (if (= (duration event) 0)
+		(format t "~%Note ~D beats in has no duration" (timepoint event))
+		(error "This function has gone wrong - looking for overlaps that don't exist")))))))
+
+(defun normalised-midi-pitch-distribution (object1 object2)
+  (normalise-vector (midi-pitch-distribution object1 object2)))
+(defun normalised-pitch-class-distribution (object1 object2)
+  (normalise-vector (pitch-class-distribution object1 object2)))
+(defun normalise-vector (vector &optional (target-sum 1))
+  (let ((total (loop for i from 0 to (1- (length vector))
+		  sum (aref vector i))))
+    (cond
+      ((= total target-sum)
+       vector)
+      ((= total 0)
+       (make-array (length vector)
+		   :initial-element (/ target-sum (length vector))))
+      (t
+       (map 'vector #'(lambda (x) (* x (/ target-sum total))) vector)))))
+
+;; Not as simple as it seems - have to take into account numbering
+;; practices and leading silences in representations where bar number
+;; isn't part of the explicit structure.
+(defgeneric bar-number (moment composition))
+
+(defgeneric bass-note (anchored-period composition))
\ No newline at end of file