diff clojure/com/aurellem/music/midi_util.clj @ 243:5b59c6f17cd5

Added the list of types and advantages to the hardcoded collection.
author Dylan Holmes <ocsenave@gmail.com>
date Sun, 25 Mar 2012 22:29:12 -0500
parents 2e751984b42d
children 2873f50b7291
line wrap: on
line diff
     1.1 --- a/clojure/com/aurellem/music/midi_util.clj	Sun Mar 25 02:53:29 2012 -0500
     1.2 +++ b/clojure/com/aurellem/music/midi_util.clj	Sun Mar 25 22:29:12 2012 -0500
     1.3 @@ -28,11 +28,17 @@
     1.4     (File. path)))
     1.5  
     1.6  
     1.7 -(defn midi-play
     1.8 +
     1.9 +(def midi-play-file
    1.10    "Plays the MIDI file at the given location. The MIDI file runs in
    1.11  the current thread until it finishes or is cancelled."
    1.12 -  [path]
    1.13 -  (let [midi (midi-load path)]
    1.14 +  (comp midi-play-seq midi-load))
    1.15 +
    1.16 +
    1.17 +(defn midi-play-seq
    1.18 +  "Plays the MIDI Sequence. The MIDI runs in
    1.19 +the current thread until it finishes or is cancelled."
    1.20 +  [midi]
    1.21      (if (nil? midi) nil
    1.22          (let [song
    1.23                (doto
    1.24 @@ -46,8 +52,8 @@
    1.25                  (do
    1.26                    (Thread/sleep 10)
    1.27                    (recur))
    1.28 -                (throw (Exception. "Song stopped!"))))
    1.29 -            (finally (.close song)))))))
    1.30 +                ))
    1.31 +            (finally (.close song))))))
    1.32  
    1.33  
    1.34  (defn midi-test-1 []
    1.35 @@ -57,14 +63,15 @@
    1.36         (getTracks))
    1.37        
    1.38        (vec)
    1.39 -      (second)
    1.40 +      (nth 1)
    1.41  
    1.42        ((fn[trk]
    1.43           (map #(. trk (get %))
    1.44                (range 0 (. trk size)))))
    1.45  
    1.46        ((fn [evts]
    1.47 -         (map (juxt #(identity (.getMessage %)) #(vec (.getMessage (.getMessage %))) #(.getTick %) ) evts)
    1.48 +         (map (juxt #(.getTick %)  #(vec (.getMessage (.getMessage
    1.49 +         %))) #(.getMessage %) ) evts)
    1.50           )
    1.51        
    1.52        )))
    1.53 @@ -73,31 +80,83 @@
    1.54  
    1.55  
    1.56  
    1.57 +(defn midi-short
    1.58 +  "Creates a MIDI event containing a ShortMessage."
    1.59 +  [tick [status & ns]]
    1.60 +  (MidiEvent.
    1.61 +   (apply
    1.62 +    (fn
    1.63 +      ([x] (doto (ShortMessage.) (.setMessage x)))
    1.64 +      ([x y] (doto (ShortMessage.) (.setMessage x y 0)))
    1.65 +      ([x y z] (doto (ShortMessage.) (.setMessage x y z)))
    1.66 +      ([x y z w] (doto (ShortMessage.) (.setMessage x y z w))))
    1.67 +    status
    1.68 +    ns)
    1.69 +   tick))
    1.70  
    1.71 -(defn midi-event
    1.72 -  "Creates an event at the given tick, of the given msg-type,
    1.73 -  containing data in coll. msg-type can be :meta, :short. If :meta, x
    1.74 -  is the type of the msg. If :short, x is the status of the message."
    1.75 -  [tick msg-type x coll]
    1.76 +(defn midi-meta
    1.77 +  "Creates a MIDI event containing a MetaMessage"
    1.78 +  [tick type  ns]
    1.79 +  (MidiEvent.
    1.80 +   (doto (MetaMessage.)
    1.81 +     (.setMessage type
    1.82 +                 (byte-array (map byte ns))
    1.83 +                 (count ns)))
    1.84 +   tick))
    1.85  
    1.86 -    (cond (= msg-type :meta)
    1.87 -          (MetaMessage.)
    1.88 -          (= msg-type :short)
    1.89 -          (ShortMessage.))
    1.90 -    
    1.91 -  )
    1.92 +
    1.93 +   
    1.94 +(defn sign
    1.95 +  "Interpret the bits of n as a signed two's-complement byte"
    1.96 +  [n]
    1.97 +  (if (>= n 128) (- n 256)
    1.98 +      n))
    1.99 +
   1.100 +(defn unsign
   1.101 +  "Interpret the bits as an unsigned byte."
   1.102 +  [n]
   1.103 +  (if (neg? n) (+ n 256) n))
   1.104 +
   1.105 +
   1.106  
   1.107  
   1.108  (defn midi-test-2 []
   1.109 -  (let [sequence (Sequence. (float 30) 15)] ;; 30 fps, 15 frames per beat
   1.110 +  (let [sequence (Sequence. (float 30) 12)] ;; 30 fps, 10 frames per beat
   1.111      (doto (. sequence (createTrack))
   1.112 -      (.add (MidiEvent. (MetaMessage.) 0)))))
   1.113 +      (.add (midi-meta 0 3 [-1 3 33 79 114 105 103 105 110 97 108 32
   1.114 +      99 111 109 112 111 115 101 114 58 32 74 117 110 105 99 104 105 32 77
   1.115 +                            97 115 117 100 97]))
   1.116  
   1.117 +      (.add (midi-short 0 [-80 0 0])) ;; control change = -80
   1.118 +      (.add (midi-short 0 [-80 7 100])) ;; control change, volume, 100
   1.119 +      (.add (midi-short 0 [-80 10 64])) ;; control change, pan, 64 (middle?)
   1.120 +      (.add (midi-short 0 [-80 32 0]))  ;; ctrl chg, LSB ctrl 0 = bank 0
   1.121 +      (.add (midi-short 0 [-64 01]))  ;; program/instrument change = -64
   1.122 +      (.add (midi-short 0 [-80 101 0]))
   1.123 +      (.add (midi-short 1 [-80 100 0]))
   1.124 +      (.add (midi-short 2 [-80 6 2]))
   1.125 +      (.add (midi-short 3 [-80 38 0]))
   1.126 +      (.add (midi-short 3 [-32 0 56])) ;; pitch bend?! = -32
   1.127 +      (.add (midi-short 3 [-112 68 100])) ;; note on = -112
   1.128 +      (.add (midi-short 20 [-112 68 0]))
   1.129 +      (.add (midi-short 40 [-112 68 100]))
   1.130 +      (.add (midi-short 60 [-112 68 0]))
   1.131 +      (.add (midi-short 80 [-112 68 100]))
   1.132 +      (.add (midi-short 100 [-112 68 0]))
   1.133 +      (.add (midi-short 120 [-80 7 100])) ;; control change
   1.134 +      (.add (midi-short 120 [-112 76 100])) ;; note-on
   1.135 +      (.add (midi-short 181 [-80 7 90]))  ;; control change
   1.136 +      (.add (midi-short 209 [-80 7 80])) ;; control change
   1.137 +      (.add (midi-short 240 [-80 7 65])) ;; control change
   1.138 +      (.add (midi-short 270 [-80 7 50])) ;; control change
   1.139 +      (.add (midi-short 300 [-112 76 0])) ;; note on = -112
   1.140 +      (.add (midi-short 360 [-80 7 0])))
   1.141 +      ;;(.add (midi-short 360 [-1 47 0])) ;; system reset = -1
   1.142  
   1.143 +    sequence
   1.144 +    )))
   1.145  
   1.146 -            [com.sun.media.sound.FastShortMessage [-80 0 0] 0] [com.sun.media.sound.FastShortMessage [-80 7 100] 0] [com.sun.media.sound.FastShortMessage [-80 10 64] 0] [com.sun.media.sound.FastShortMessage [-80 32 0] 0] [com.sun.media.sound.FastShortMessage [-64 80] 0] [com.sun.media.sound.FastShortMessage [-80 101 0] 0] [com.sun.media.sound.FastShortMessage [-80 100 0] 1] [com.sun.media.sound.FastShortMessage [-80 6 2] 2] [com.sun.media.sound.FastShortMessage [-80 38 0] 3] [com.sun.media.sound.FastShortMessage [-32 0 56] 3] [com.sun.media.sound.FastShortMessage [-112 68 100] 3] [com.sun.media.sound.FastShortMessage [-112 68 0] 20] [com.sun.media.sound.FastShortMessage [-112 68 100] 40] [com.sun.media.sound.FastShortMessage [-112 68 0] 60] [com.sun.media.sound.FastShortMessage [-112 68 100] 80] [com.sun.media.sound.FastShortMessage [-112 68 0] 100] [com.sun.media.sound.FastShortMessage [-80 7 100] 120] [com.sun.media.sound.FastShortMessage [-112 76 100] 120] [com.sun.media.sound.FastShortMessage [-80 7 90] 181] [com.sun.media.sound.FastShortMessage [-80 7 80] 209] [com.sun.media.sound.FastShortMessage [-80 7 65] 240] [com.sun.media.sound.FastShortMessage [-80 7 50] 270] [com.sun.media.sound.FastShortMessage [-112 76 0] 300] [com.sun.media.sound.FastShortMessage [-80 7 0] 360] [javax.sound.midi.Track$ImmutableEndOfTrack [-1 47 0] 360])
   1.147 -com.aurellem.music.midi-util> (midi-test-1)
   1.148 -([javax.sound.midi.MetaMessage [-1 3 33 79 114 105 103 105 110 97 108 32 99 111 109 112 111 115 101 114 58 32 74 117 110 105 99 104 105 32 77 97 115 117 100 97] 0] [com.sun.media.sound.FastShortMessage [-80 0 0] 0] [com.sun.media.sound.FastShortMessage [-80 7 100] 0] [com.sun.media.sound.FastShortMessage [-80 10 64] 0] [com.sun.media.sound.FastShortMessage [-80 32 0] 0] [com.sun.media.sound.FastShortMessage [-64 80] 0] [com.sun.media.sound.FastShortMessage [-80 101 0] 0] [com.sun.media.sound.FastShortMessage [-80 100 0] 1] [com.sun.media.sound.FastShortMessage [-80 6 2] 2] [com.sun.media.sound.FastShortMessage [-80 38 0] 3] [com.sun.media.sound.FastShortMessage [-32 0 56] 3] [com.sun.media.sound.FastShortMessage [-112 68 100] 3] [com.sun.media.sound.FastShortMessage [-112 68 0] 20] [com.sun.media.sound.FastShortMessage [-112 68 100] 40] [com.sun.media.sound.FastShortMessage [-112 68 0] 60] [com.sun.media.sound.FastShortMessage [-112 68 100] 80] [com.sun.media.sound.FastShortMessage [-112 68 0] 100] [com.sun.media.sound.FastShortMessage [-80 7 100] 120] [com.sun.media.sound.FastShortMessage [-112 76 100] 120] [com.sun.media.sound.FastShortMessage [-80 7 90] 181] [com.sun.media.sound.FastShortMessage [-80 7 80] 209] [com.sun.media.sound.FastShortMessage [-80 7 65] 240] [com.sun.media.sound.FastShortMessage [-80 7 50] 270] [com.sun.media.sound.FastShortMessage [-112 76 0] 300] [com.sun.media.sound.FastShortMessage [-80 7 0] 360] [javax.sound.midi.Track$ImmutableEndOfTrack [-1 47 0] 360])
   1.149 +
   1.150    
   1.151  
   1.152  ;;; ROM MUSIC MANIPULATION
   1.153 @@ -153,6 +212,11 @@
   1.154    "Returns the number represented by the bytes."
   1.155    [low high]
   1.156    (+ low (* 256  high)))
   1.157 +(defn high-low-format
   1.158 +  "Returns the number represented by the bytes."
   1.159 +  [high low]
   1.160 +  (+ low (* 256 high)))
   1.161 +
   1.162  
   1.163  (defn rom-tracks
   1.164    "Given a valid address to a music header, returns a list of the
   1.165 @@ -171,6 +235,7 @@
   1.166           1
   1.167           )]
   1.168  
   1.169 +    tracklist
   1.170      (map
   1.171       (fn [trk] (take-while #(not= 0xFF %) (drop trk rom)))
   1.172       tracklist)
   1.173 @@ -179,14 +244,31 @@
   1.174    
   1.175  
   1.176  
   1.177 -(defn parse-track
   1.178 +
   1.179 +(defn note?
   1.180 +  "Does the given byte correspond to a note?"
   1.181 +  [n]
   1.182 +  
   1.183 +(defn parse-ops
   1.184    "Consumes the list of opcodes, returning a runnable MIDI Sequence object."
   1.185 -  [track]
   1.186 -  (fn [midi track]
   1.187 -    (cond (empty? track) midi)))
   1.188 +  [ops]
   1.189 +  (
   1.190 +   (fn [midi ops]
   1.191 +     (let [x (first ops)]
   1.192 +       (cond (empty? ops) midi
   1.193 +             (= x 0xDA)
   1.194 +               ;; set tempo (high-low (nth ops 1)(nth ops 2))
   1.195 +             (recur (identity midi) (drop 3 ops))
   1.196 +             
   1.197 +             (note? x)
   1.198 +             
   1.199  
   1.200 +             )
   1.201  
   1.202 -
   1.203 +   (doto (Sequence. (float 30) 15) ;; 30 fps, 15 frames per beat
   1.204 +     (.createTrack))
   1.205 +   ops
   1.206 +   ))
   1.207  
   1.208  
   1.209