changeset 146:a74494a94be9

implementations/midi: implement MONODY for midi files darcs-hash:20070924160443-c0ce4-302ec7f06335a374b673f70ef2e79d4b2a8b3616.gz
author Marcus Pearce <m.pearce@gold.ac.uk>
date Mon, 24 Sep 2007 17:04:43 +0100
parents b5b18959c301
children 8156c30c0c53
files implementations/midi/classes.lisp implementations/midi/methods.lisp
diffstat 2 files changed, 45 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/implementations/midi/classes.lisp	Mon Sep 24 16:44:39 2007 +0100
+++ b/implementations/midi/classes.lisp	Mon Sep 24 17:04:43 2007 +0100
@@ -20,6 +20,9 @@
   signatures, tempi, key signatures and other controllers as
   lists in slots"))
 
+(defclass midi-monody (amuse:standard-monody midi-composition)
+  ())
+
 (defclass midi-message (midi-object) ;?
   ((channel :accessor %midi-message-channel :initarg :channel)
    (track :accessor %midi-message-track :initarg :track)))
--- a/implementations/midi/methods.lisp	Mon Sep 24 16:44:39 2007 +0100
+++ b/implementations/midi/methods.lisp	Mon Sep 24 17:04:43 2007 +0100
@@ -144,3 +144,45 @@
 
 (defmethod crotchet ((object midi-object))
   (make-standard-period 1))
+
+(defmethod monody ((identifier midifile-identifier))
+  (monody (get-composition identifier)))
+
+;; TODO: improve this naive first-cut at MONODY for midi files which
+;; simply selects a track which is both monodic (if any monodic tracks
+;; exist) and contains the highest pitch of any monodic track.
+(defmethod monody ((c midi-composition))
+  (flet ((not-overlapping (track) 
+           (let ((result t)
+                 (track (sort (copy-list track) #'amuse:time<)))
+             (dotimes (i (1- (length track)) result)
+               (let ((e1 (elt track i))
+                     (e2 (elt track (1+ i))))
+                 (unless (or (before e1 e2) (meets e1 e2))
+                   (setf result nil)))))))
+    (let ((tracks (make-hash-table))
+          (result nil)
+          (max-pitch 0))
+      (sequence:dosequence (message c)
+        (let* ((tracknum (amuse-midi:midi-track message))
+               (track (gethash tracknum tracks)))
+          (setf (gethash tracknum tracks) (cons message track))))
+      (maphash #'(lambda (k v)
+                   (declare (ignore k))
+                   (let ((max (apply #'max (mapcar #'midi-pitch-number v))))
+                     (when (and (not-overlapping v) (> max max-pitch))
+                       (setf result (sort v #'amuse:time<)
+                             max-pitch max))))
+               tracks)
+      (when result 
+        (let ((monody (make-instance 'midi-monody 
+                                     :time (amuse:timepoint c)
+                                     :interval (amuse:duration c)
+                                     :time-signatures (time-signatures c)
+                                     :key-signatures (key-signatures c)
+                                     :tempi (tempi c)
+                                     :controllers (%midi-misc-controllers c))))
+          (sequence:adjust-sequence monody (length result)
+                                    :initial-contents result)
+          monody)))))
+