diff implementations/geerdes/constructors.lisp @ 88:8ea75cc8bc2c

Basic geerdes functionality moved to implementations/geerdes from separate package darcs-hash:20070720161242-f76cc-fd256cbbb81d8c418a6c7c45844264184c5ed932.gz
author David Lewis <d.lewis@gold.ac.uk>
date Fri, 20 Jul 2007 17:12:42 +0100
parents
children d041118612d4
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/implementations/geerdes/constructors.lisp	Fri Jul 20 17:12:42 2007 +0100
@@ -0,0 +1,178 @@
+(cl:in-package #:amuse-geerdes)
+
+(defgeneric %initialise-notes (composition))
+(defmethod %initialise-notes ((composition geerdes-composition))
+  (let ((notes) (l 0) (last-time 0) (monody-notes)
+	(monody (make-instance 'geerdes-monody :file-id (file-id composition)))
+	(timebase (%midi-timebase composition)))
+    (dolist (row (%midi-events composition))
+      (let* ((note (if (pitched-row-p row)
+		      (make-geerdes-pitched-event (%fast-pitch row)
+						  (%fast-velocity row)
+						  (%fast-patch row)
+						  (%fast-channel row)
+						  (%fast-track row)
+						  (%fast-onset row timebase)
+						  (%fast-duration row timebase)
+						  (%fast-id row))
+		      (make-geerdes-percussive-event (%fast-pitch row)
+						     (%fast-velocity row)
+						     (%fast-patch row)
+						     (%fast-channel row)
+						     (%fast-track row)
+						     (%fast-onset row timebase)
+						     (%fast-duration row timebase)
+						     (%fast-id row)))))
+	(when (%fast-monodyp row)
+	  (push note monody-notes))
+	(when (> (timepoint (cut-off note)) last-time)
+	  (setf last-time (timepoint (cut-off note))))
+	(push note notes)
+	(incf l)))
+    (sequence:adjust-sequence composition l :initial-contents (reverse notes))
+    (setf (duration composition) last-time
+	  (timepoint composition) 0)
+    (when monody-notes
+      (setf (%monody composition) (sequence:adjust-sequence monody (length monody-notes)
+							    :initial-contents (reverse monody-notes))
+	    (timepoint (%monody composition)) (timepoint (elt monody 0))
+	    (duration (%monody composition)) (- (timepoint (cut-off (car monody-notes)))
+						(timepoint (elt monody 0)))))
+    composition))
+
+(defgeneric %initialise-constituents (composition))
+(defmethod %initialise-constituents ((composition geerdes-composition))
+  ;; FIXME: Should the duration of composition be affected by this? On
+  ;; the one hand, it makes no difference to the musical content, but
+  ;; on the other, it seems illogical to reach outside the period.
+  (let ((timebase (%midi-timebase composition))
+	(time-sigs)
+	(tempi)
+	(mystery 0))
+    (dolist (row (%midi-constituents composition))
+      (cond
+	((%fast-tempo row)
+	 (push (make-tempo
+		(microsecond-per-crotchet-to-bpm
+		 (%fast-tempo row))
+		(%fast-onset row timebase)
+		(%fast-duration row timebase))
+	       tempi))
+	((%fast-numerator row)
+	 (push (make-basic-time-signature
+		(%fast-numerator row)
+		(%fast-denominator row)
+		(%fast-onset row timebase)
+		(%fast-duration row timebase))
+	       time-sigs))
+	(t (incf mystery))))
+    (setf (time-signatures composition) (reverse time-sigs)
+	  (tempi composition) (reverse tempi))
+    (when (%monody composition)
+      (setf (time-signatures (%monody composition)) (time-signatures composition)
+	    (tempi (%monody composition)) (tempi composition)))
+    (format t "There are ~D constituents not processed~%" mystery)
+    composition))
+
+(defun %fast-track (row)
+  (first row))
+(defun %fast-channel (row)
+  (second row))
+(defun %fast-onset (row timebase)
+  (/ (third row) timebase))
+(defun %fast-duration (row timebase)
+  (/ (fourth row) timebase))
+(defun %fast-patch (event-row)
+  (fifth event-row))
+(defun %fast-pitch (event-row)
+  (sixth event-row))
+(defun %fast-velocity (event-row)
+  (seventh event-row))
+(defun %fast-id (event-row)
+  (eighth event-row))
+(defun %fast-monodyp (event-row)
+  (ninth event-row))
+
+(defun %fast-tempo (tp-row)
+  (eighth tp-row))
+(defun %fast-numerator (ts-row)
+  (ninth ts-row))
+(defun %fast-denominator (ts-row)
+  (tenth ts-row))
+
+(defun pitched-row-p (event-row)
+  (and (not (= (%fast-channel event-row) 10))
+       (< (%fast-patch event-row) 112)))
+
+(defun make-geerdes-pitched-event (pitch-number velocity patch
+				channel track onset duration id)
+  (make-instance 'geerdes-pitched-event
+		 :number pitch-number
+		 :velocity velocity
+		 :patch patch
+		 :channel channel
+		 :track track
+		 :time onset
+		 :interval duration
+		 :id id))
+
+(defun make-geerdes-percussive-event (pitch-number velocity patch
+				   channel track onset duration id)
+  (make-instance 'geerdes-percussive-event
+		 :sound pitch-number
+		 :velocity velocity
+		 :patch patch
+		 :channel channel
+		 :track track
+		 :time onset
+		 :interval duration
+		 :id id))
+
+(defgeneric copy-event (event))
+(defmethod copy-event ((event geerdes-pitched-event))
+  (with-slots ((channel amuse-midi::channel)
+	       (track amuse-midi::track)
+	       (number amuse::number)
+	       (time amuse::time)
+	       (interval amuse::interval)
+	       (velocity amuse-midi::velocity)
+	       (patch amuse-midi::patch) id)
+      event
+    (make-instance 'geerdes-pitched-event
+		   :channel channel
+		   :track track
+		   :number number
+		   :time time
+		   :interval interval
+		   :velocity velocity
+		   :patch patch
+		   :id id)))
+(defmethod copy-event ((event geerdes-percussive-event)) 
+  (with-slots ((channel amuse-midi::channel)
+	       (track amuse-midi::track)
+	       (time amuse::time)
+	       (interval amuse::interval)
+	       (velocity amuse-midi::velocity)
+	       (patch amuse-midi::patch)
+	       (sound amuse-midi::sound) id)
+      event
+    (make-instance 'geerdes-percussive-event
+		   :channel channel 
+		   :track track
+		   :time time
+		   :interval interval
+		   :velocity velocity
+		   :patch patch
+		   :sound sound
+		   :id id)))
+
+;; We want any function that generates a sequence from a geerdes
+;; composition to preserve all slot values:
+(defmethod sequence:make-sequence-like :around ((o geerdes-composition)
+						length
+						&key (initial-element nil iep)
+						(initial-contents nil icp))
+  (declare (ignore iep icp length initial-element initial-contents))
+  (let ((result (call-next-method)))
+    (setf (%db-entry result) (%db-entry o))
+    result))