Mercurial > vba-clojure
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 |