comparison 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
comparison
equal deleted inserted replaced
242:2e751984b42d 243:5b59c6f17cd5
26 (MidiSystem/getSequence file) 26 (MidiSystem/getSequence file)
27 nil)) 27 nil))
28 (File. path))) 28 (File. path)))
29 29
30 30
31 (defn midi-play 31
32 (def midi-play-file
32 "Plays the MIDI file at the given location. The MIDI file runs in 33 "Plays the MIDI file at the given location. The MIDI file runs in
33 the current thread until it finishes or is cancelled." 34 the current thread until it finishes or is cancelled."
34 [path] 35 (comp midi-play-seq midi-load))
35 (let [midi (midi-load path)] 36
37
38 (defn midi-play-seq
39 "Plays the MIDI Sequence. The MIDI runs in
40 the current thread until it finishes or is cancelled."
41 [midi]
36 (if (nil? midi) nil 42 (if (nil? midi) nil
37 (let [song 43 (let [song
38 (doto 44 (doto
39 (MidiSystem/getSequencer) 45 (MidiSystem/getSequencer)
40 (.open) 46 (.open)
44 (loop [] 50 (loop []
45 (if (. song (isRunning)) 51 (if (. song (isRunning))
46 (do 52 (do
47 (Thread/sleep 10) 53 (Thread/sleep 10)
48 (recur)) 54 (recur))
49 (throw (Exception. "Song stopped!")))) 55 ))
50 (finally (.close song))))))) 56 (finally (.close song))))))
51 57
52 58
53 (defn midi-test-1 [] 59 (defn midi-test-1 []
54 (-> (. 60 (-> (.
55 (midi-load 61 (midi-load
56 "/home/ocsenave/bk_robert/sounds/sounds/www.vgmusic.com/console/nintendo/gameboy/PkmRB-Item.mid") 62 "/home/ocsenave/bk_robert/sounds/sounds/www.vgmusic.com/console/nintendo/gameboy/PkmRB-Item.mid")
57 (getTracks)) 63 (getTracks))
58 64
59 (vec) 65 (vec)
60 (second) 66 (nth 1)
61 67
62 ((fn[trk] 68 ((fn[trk]
63 (map #(. trk (get %)) 69 (map #(. trk (get %))
64 (range 0 (. trk size))))) 70 (range 0 (. trk size)))))
65 71
66 ((fn [evts] 72 ((fn [evts]
67 (map (juxt #(identity (.getMessage %)) #(vec (.getMessage (.getMessage %))) #(.getTick %) ) evts) 73 (map (juxt #(.getTick %) #(vec (.getMessage (.getMessage
74 %))) #(.getMessage %) ) evts)
68 ) 75 )
69 76
70 ))) 77 )))
71 78
72 79
73 80
74 81
75 82
76 83 (defn midi-short
77 (defn midi-event 84 "Creates a MIDI event containing a ShortMessage."
78 "Creates an event at the given tick, of the given msg-type, 85 [tick [status & ns]]
79 containing data in coll. msg-type can be :meta, :short. If :meta, x 86 (MidiEvent.
80 is the type of the msg. If :short, x is the status of the message." 87 (apply
81 [tick msg-type x coll] 88 (fn
82 89 ([x] (doto (ShortMessage.) (.setMessage x)))
83 (cond (= msg-type :meta) 90 ([x y] (doto (ShortMessage.) (.setMessage x y 0)))
84 (MetaMessage.) 91 ([x y z] (doto (ShortMessage.) (.setMessage x y z)))
85 (= msg-type :short) 92 ([x y z w] (doto (ShortMessage.) (.setMessage x y z w))))
86 (ShortMessage.)) 93 status
87 94 ns)
88 ) 95 tick))
96
97 (defn midi-meta
98 "Creates a MIDI event containing a MetaMessage"
99 [tick type ns]
100 (MidiEvent.
101 (doto (MetaMessage.)
102 (.setMessage type
103 (byte-array (map byte ns))
104 (count ns)))
105 tick))
106
107
108
109 (defn sign
110 "Interpret the bits of n as a signed two's-complement byte"
111 [n]
112 (if (>= n 128) (- n 256)
113 n))
114
115 (defn unsign
116 "Interpret the bits as an unsigned byte."
117 [n]
118 (if (neg? n) (+ n 256) n))
119
120
89 121
90 122
91 (defn midi-test-2 [] 123 (defn midi-test-2 []
92 (let [sequence (Sequence. (float 30) 15)] ;; 30 fps, 15 frames per beat 124 (let [sequence (Sequence. (float 30) 12)] ;; 30 fps, 10 frames per beat
93 (doto (. sequence (createTrack)) 125 (doto (. sequence (createTrack))
94 (.add (MidiEvent. (MetaMessage.) 0))))) 126 (.add (midi-meta 0 3 [-1 3 33 79 114 105 103 105 110 97 108 32
95 127 99 111 109 112 111 115 101 114 58 32 74 117 110 105 99 104 105 32 77
96 128 97 115 117 100 97]))
97 129
98 [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]) 130 (.add (midi-short 0 [-80 0 0])) ;; control change = -80
99 com.aurellem.music.midi-util> (midi-test-1) 131 (.add (midi-short 0 [-80 7 100])) ;; control change, volume, 100
100 ([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]) 132 (.add (midi-short 0 [-80 10 64])) ;; control change, pan, 64 (middle?)
133 (.add (midi-short 0 [-80 32 0])) ;; ctrl chg, LSB ctrl 0 = bank 0
134 (.add (midi-short 0 [-64 01])) ;; program/instrument change = -64
135 (.add (midi-short 0 [-80 101 0]))
136 (.add (midi-short 1 [-80 100 0]))
137 (.add (midi-short 2 [-80 6 2]))
138 (.add (midi-short 3 [-80 38 0]))
139 (.add (midi-short 3 [-32 0 56])) ;; pitch bend?! = -32
140 (.add (midi-short 3 [-112 68 100])) ;; note on = -112
141 (.add (midi-short 20 [-112 68 0]))
142 (.add (midi-short 40 [-112 68 100]))
143 (.add (midi-short 60 [-112 68 0]))
144 (.add (midi-short 80 [-112 68 100]))
145 (.add (midi-short 100 [-112 68 0]))
146 (.add (midi-short 120 [-80 7 100])) ;; control change
147 (.add (midi-short 120 [-112 76 100])) ;; note-on
148 (.add (midi-short 181 [-80 7 90])) ;; control change
149 (.add (midi-short 209 [-80 7 80])) ;; control change
150 (.add (midi-short 240 [-80 7 65])) ;; control change
151 (.add (midi-short 270 [-80 7 50])) ;; control change
152 (.add (midi-short 300 [-112 76 0])) ;; note on = -112
153 (.add (midi-short 360 [-80 7 0])))
154 ;;(.add (midi-short 360 [-1 47 0])) ;; system reset = -1
155
156 sequence
157 )))
158
159
101 160
102 161
103 ;;; ROM MUSIC MANIPULATION 162 ;;; ROM MUSIC MANIPULATION
104 163
105 (def songs;; music-headers 164 (def songs;; music-headers
151 210
152 (defn low-high-format 211 (defn low-high-format
153 "Returns the number represented by the bytes." 212 "Returns the number represented by the bytes."
154 [low high] 213 [low high]
155 (+ low (* 256 high))) 214 (+ low (* 256 high)))
215 (defn high-low-format
216 "Returns the number represented by the bytes."
217 [high low]
218 (+ low (* 256 high)))
219
156 220
157 (defn rom-tracks 221 (defn rom-tracks
158 "Given a valid address to a music header, returns a list of the 222 "Given a valid address to a music header, returns a list of the
159 data tracks" 223 data tracks"
160 [address] 224 [address]
169 233
170 (take 12 (drop (inc address) rom)) 234 (take 12 (drop (inc address) rom))
171 1 235 1
172 )] 236 )]
173 237
238 tracklist
174 (map 239 (map
175 (fn [trk] (take-while #(not= 0xFF %) (drop trk rom))) 240 (fn [trk] (take-while #(not= 0xFF %) (drop trk rom)))
176 tracklist) 241 tracklist)
177 242
178 )) 243 ))
179 244
180 245
181 246
182 (defn parse-track 247
248 (defn note?
249 "Does the given byte correspond to a note?"
250 [n]
251
252 (defn parse-ops
183 "Consumes the list of opcodes, returning a runnable MIDI Sequence object." 253 "Consumes the list of opcodes, returning a runnable MIDI Sequence object."
184 [track] 254 [ops]
185 (fn [midi track] 255 (
186 (cond (empty? track) midi))) 256 (fn [midi ops]
187 257 (let [x (first ops)]
188 258 (cond (empty? ops) midi
189 259 (= x 0xDA)
260 ;; set tempo (high-low (nth ops 1)(nth ops 2))
261 (recur (identity midi) (drop 3 ops))
262
263 (note? x)
264
265
266 )
267
268 (doto (Sequence. (float 30) 15) ;; 30 fps, 15 frames per beat
269 (.createTrack))
270 ops
271 ))
190 272
191 273
192 274
193 275
194 276