changeset 157:f5f4bf8d74d7

Fixed previous patch darcs-hash:20071204151652-1f211-efd2cee99c632933f62a188cf9333dfb5bfe9918.gz
author d.mullensiefen <d.mullensiefen@gold.ac.uk>
date Tue, 04 Dec 2007 15:16:52 +0000
parents cc7724248043
children 49b418a68acb
files implementations/midi/methods.lisp
diffstat 1 files changed, 137 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/implementations/midi/methods.lisp	Tue Dec 04 15:00:55 2007 +0000
+++ b/implementations/midi/methods.lisp	Tue Dec 04 15:16:52 2007 +0000
@@ -187,3 +187,140 @@
 
 (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)))))
+
+(defmethod trim-enclosing-silence ((composition midi-composition))
+  (let ((start (timepoint (bar-before (onset (elt composition 0))
+                                      composition)))
+        (end)
+        (new-sequence) (new-composition))
+    ;; First attend to the events themselves - copy and slide
+    (sequence:dosequence (event composition)
+      (push (copy-event event) new-sequence)
+      (setf (timepoint (car new-sequence)) (- (timepoint event)
+                                             start))
+      (when (or (not end)
+                (> (timepoint (cut-off event)) end))
+        (setf end (timepoint (cut-off event)))))
+    ;; Make the new composition with slid events
+    ;; Should work, but doesn't
+    #+nil
+    (setf new-composition (sequence:make-sequence-like composition 0))
+    (setf new-composition (make-instance 'midi-composition
+                                         :time 0
+                                         :interval (- end start)))
+    (setf (amuse::%list-slot-sequence-data new-composition)
+          (reverse new-sequence))
+    ;; Time-sigs
+    (let ((sigs))
+      (dolist (sig (time-signatures composition))
+        ;; only include if signature affects window
+        (when (and (> (timepoint (cut-off sig))
+                      start)
+                   (< (timepoint sig)
+                      end))
+          ;; copy the signature
+          (push (copy-time-signature sig)
+                sigs)
+          ;; adjust the timing
+          (setf (timepoint (car sigs))
+                (max 0 (- (timepoint (car sigs)) start))
+                (duration (car sigs))
+                (- (min (timepoint (cut-off (car sigs)))
+                        (- end start))
+                   (timepoint (car sigs))))))
+      (setf (time-signatures new-composition) (reverse sigs)))
+    (let ((sigs))
+      (dolist (sig (key-signatures composition))
+        ;; only include if signature affects window
+        (when (and (> (timepoint (cut-off sig))
+                      start)
+                   (< (timepoint sig)
+                      end))
+          ;; copy the signature
+          (push (copy-key-signature sig)
+                sigs)
+          ;; adjust the timing
+          (setf (timepoint (car sigs))
+                (max 0 (- (timepoint (car sigs)) start))
+                (duration (car sigs))
+                (- (min (timepoint (cut-off (car sigs)))
+                        (- end start))
+                   (timepoint (car sigs))))))
+      (setf (key-signatures new-composition) (reverse sigs)))
+    (let ((tempi))
+      (dolist (tempo (tempi composition))
+        ;; only include if signature affects window
+        (when (and (> (timepoint (cut-off tempo))
+                      start)
+                   (< (timepoint tempo)
+                      end))
+          ;; copy the signature
+          (push (copy-tempo tempo)
+                tempi)
+          ;; adjust the timing
+          (setf (timepoint (car tempi))
+                (max 0 (- (timepoint (car tempi)) start))
+                (duration (car tempi))
+                (- (min (timepoint (cut-off (car tempi)))
+                        (- end start))
+                   (timepoint (car tempi))))))
+      (setf (tempi new-composition) (reverse tempi)))
+    new-composition))
+
+
+(defgeneric bar-before (moment composition))
+
+(defmethod bar-before (moment (composition midi-composition))
+  "Returns the moment at which the containing bar begins"
+  (do ((time-sigs (time-signatures composition) (cdr time-sigs)))
+      ((null time-sigs) nil)
+    (let ((bar-period (make-standard-period
+		       (crotchets-in-a-bar (car time-sigs)))))
+      (when (time> (cut-off (car time-sigs))
+                   moment)
+        (do ((bar (time+ (onset (car time-sigs)) bar-period)
+                  (time+ bar bar-period))
+             (prev-bar (onset (car time-sigs))))
+            ((time> bar moment) (return-from bar-before prev-bar))
+          (setf prev-bar bar))))))
\ No newline at end of file