changeset 438:067ea3f0d951

can now play midi files with two tracks.
author Robert McIntyre <rlm@mit.edu>
date Wed, 25 Apr 2012 13:46:31 -0500
parents 20a9d5faf47c
children 71878fbc277b
files clojure/com/aurellem/run/music.clj
diffstat 1 files changed, 43 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
     1.1 --- a/clojure/com/aurellem/run/music.clj	Wed Apr 25 13:09:06 2012 -0500
     1.2 +++ b/clojure/com/aurellem/run/music.clj	Wed Apr 25 13:46:31 2012 -0500
     1.3 @@ -390,27 +390,29 @@
     1.4     :duration length
     1.5     :volume 0})
     1.6  
     1.7 -(defn midi->mini-midi [#^File midi-file]
     1.8 +(defn commands
     1.9 +  "return all events where #(= (:command %) command)"
    1.10 +  [command s]
    1.11 +  (filter #(= command (:command %)) s))
    1.12 +
    1.13 +(defn midi-track->mini-midi [#^File midi-file track-num]
    1.14    (let [midi-events (parse-midi midi-file)
    1.15  
    1.16 -        note-on-events
    1.17 -        (filter #(= :Note_on_c (:command %)) midi-events)
    1.18 -        note-off-events
    1.19 -        (filter #(= :Note_off_c (:command %)) midi-events)
    1.20 +        note-on-events  (commands :Note_on_c  midi-events)
    1.21 +        note-off-events (commands :Note_off_c midi-events)
    1.22  
    1.23 -        channel-1-on
    1.24 -        (sort-by :time
    1.25 -                 (filter #(= 1 (:channel (:args %)))
    1.26 -                  note-on-events))
    1.27 -        channel-1-off
    1.28 -        (sort-by :time
    1.29 -                 (filter #(= 1 (:channel (:args %)))
    1.30 -                         note-off-events))
    1.31 +        select-channel
    1.32 +        (fn [n s]
    1.33 +          (sort-by :time (filter #(= n (:channel (:args %))) s)))
    1.34 +
    1.35 +        channel-on (select-channel track-num note-on-events)
    1.36          
    1.37 +        channel-off (select-channel track-num note-off-events)
    1.38          
    1.39 -        tempo (:args (first (filter #(= :Tempo (:command %)) midi-events)))
    1.40 -        division (:division
    1.41 -                  (:args (first (filter #(= :Header (:command %)) midi-events))))
    1.42 +        
    1.43 +        tempo (:args (first (commands :Tempo midi-events)))
    1.44 +        division
    1.45 +        (:division (:args (first (commands :Header midi-events))))
    1.46  
    1.47          notes
    1.48          (map
    1.49 @@ -423,7 +425,7 @@
    1.50              :volume (int (/ (:velocity (:args note-on)) 10))
    1.51              :time-stamp (/ (* (/ tempo division)
    1.52                                (:time note-on)) 1e6)})
    1.53 -         channel-1-on channel-1-off)
    1.54 +         channel-on channel-off)
    1.55  
    1.56          silences
    1.57          (map (fn [note-1 note-2]
    1.58 @@ -437,9 +439,8 @@
    1.59               notes)
    1.60          
    1.61          notes-with-silence
    1.62 -        (filter (comp not zero? :duration) (interleave silences notes))
    1.63 -        ]
    1.64 -
    1.65 +        (filter (comp not zero? :duration)
    1.66 +                (interleave silences notes))]
    1.67      (map
    1.68       (fn [note-event]
    1.69         (note-codes (:frequency note-event)
    1.70 @@ -447,6 +448,27 @@
    1.71                     (int (* (:duration note-event) 0x100))))
    1.72       notes-with-silence)))
    1.73  
    1.74 +(defn midi->mini-midi [#^File midi-file]
    1.75 +  {:track-1 (flatten (midi-track->mini-midi midi-file 1))
    1.76 +   :track-2 (flatten (midi-track->mini-midi midi-file 2))})
    1.77 +
    1.78 +(defn play-midi [#^File midi-file]
    1.79 +  (let [track-1-target 0xA000
    1.80 +        track-2-target 0xB000
    1.81 +        program-target 0xC000
    1.82 +        mini-midi (midi->mini-midi midi-file)
    1.83 +        long-silence (flatten (note-codes 20 0 9001))]
    1.84 +    
    1.85 +    (-> (second (music-base))
    1.86 +        (set-memory-range track-1-target long-silence)
    1.87 +        (set-memory-range track-2-target long-silence)
    1.88 +        (set-memory-range track-1-target (:track-1 mini-midi))
    1.89 +        (set-memory-range track-2-target (:track-2 mini-midi))
    1.90 +        (set-memory-range program-target (music-kernel))
    1.91 +        (PC! program-target))))
    1.92 +
    1.93 +
    1.94 +  
    1.95  
    1.96  (def C4 (partial note-codes 261.63))
    1.97  (def D4 (partial note-codes 293.66))
    1.98 @@ -477,6 +499,7 @@
    1.99          (PC! program-target))))
   1.100  
   1.101  
   1.102 +
   1.103  ;; (defn test-note [music-bytes]
   1.104  ;;   (-> (set-memory-range (second (music-base))
   1.105  ;;                         0xC000 (concat (clear-music-registers)