comparison clojure/com/aurellem/run/music.clj @ 424:7bd806c4dbb6

changed assembly to handle mini-midi messages of different lengths.
author Robert McIntyre <rlm@mit.edu>
date Mon, 23 Apr 2012 04:45:55 -0500
parents 971bd1774eab
children df4e03672b05
comparison
equal deleted inserted replaced
423:971bd1774eab 424:7bd806c4dbb6
59 59
60 (store (Integer/parseInt "00000000" 2) 0xFF20) 60 (store (Integer/parseInt "00000000" 2) 0xFF20)
61 (store (Integer/parseInt "00000000" 2) 0xFF21) 61 (store (Integer/parseInt "00000000" 2) 0xFF21)
62 (store (Integer/parseInt "00000000" 2) 0xFF22) 62 (store (Integer/parseInt "00000000" 2) 0xFF22)
63 (store (Integer/parseInt "00000000" 2) 0xFF23)])) 63 (store (Integer/parseInt "00000000" 2) 0xFF23)]))
64
65
66 ;; mini-midi syntax
67
68 ;; codes
69 ;; note-code == 0x00
70 ;; change-duty-code = 0x01
71 ;; silence-code = 0x02
72
73 ;; silence format
74 ;; 2 bytes
75 ;; [silence-code (0x02)]
76 ;; [duration-8-bits]
77
78 ;; note data format
79 ;; 4 bytes
80 ;; [note-code (0x00)]
81 ;; [volume-4-bits 0 frequency-high-3-bits]
82 ;; [frequengy-low-8-bits]
83 ;; [duration-8-bits]
84
85 ;; change-duty-format
86 ;; 2 bytes
87 ;; [change-duty-code (0x01)]
88 ;; [new-duty]
89
90 (defn do-message
91 "Read the message which starts at the current value of HL and do
92 what it says. Duration is left in A, and HL is advanced
93 appropraitely."
94 []
95
96 )
97
98
99
100
101
64 102
65 (defn play-note 103 (defn play-note
66 "Play the note referenced by HL in the appropiate channel. 104 "Play the note referenced by HL in the appropiate channel.
67 Leaves desired-duration in A." 105 Leaves desired-duration in A."
68 [] 106 []
80 118
81 0x2A ;; load frequency low-bits 119 0x2A ;; load frequency low-bits
82 0xE0 120 0xE0
83 0x18 ;; set frequency-low-bits 121 0x18 ;; set frequency-low-bits
84 122
85 0x7E ;; load duration 123 0x2A ;; load duration
86 0x2B ;;
87 0x2B ;; HL-2 -> HL
88 ]) 124 ])
89 125
90 (defn music-step [] 126 (defn music-step []
91 (flatten 127 (flatten
92 [(play-note) 128 [
93 0xF5 ;; push A 129 0xF5 ;; push A
94 0xF0 130 0xF0
95 0x05 ;; load current ticks 131 0x05 ;; load current ticks
96 0xB8 ;; B holds previous sub-ticks, subtract it from A 132 0xB8 ;; B holds previous sub-ticks, subtract it from A
97 ;; if A-B caused a carry, then (B > A) is true, and 133 ;; if A-B caused a carry, then (B > A) is true, and
110 146
111 ;; if desired-ticks = current ticks 147 ;; if desired-ticks = current ticks
112 ;; go to next note ; set current set ticks to 0. 148 ;; go to next note ; set current set ticks to 0.
113 149
114 0x20 150 0x20
115 0x05 151 (+ (count (play-note)) 2)
116 152
117 0x23 153 (play-note)
118 0x23
119 0x23 ;; HL + 3 -> HL
120 154
121 0x0E 155 0x0E
122 0x00])) ;; 0->C (current-ticks) 156 0x00])) ;; 0->C (current-ticks)
123
124 (defn test-timer []
125 (flatten
126 [0x3E
127 0x01
128 0xE0
129 0x06 ;; set TMA to 0
130
131 0x3E
132 (Integer/parseInt "00000100" 2)
133 0xE0
134 0x07 ;; set TAC to 16384 Hz and activate timer
135
136 (repeat
137 500
138 [0xF0
139 0x05])]))
140
141 157
142 (defn music-kernel [] 158 (defn music-kernel []
143 (flatten 159 (flatten
144 [(clear-music-registers) 160 [(clear-music-registers)
145 161
159 0x3E 175 0x3E
160 (Integer/parseInt "00000110" 2) 176 (Integer/parseInt "00000110" 2)
161 0xE0 177 0xE0
162 0x07 ;; set TAC to 65536 Hz and activate timer 178 0x07 ;; set TAC to 65536 Hz and activate timer
163 179
164 0xF0 180
165 0x07 181 0xAF ;; initialiaze A to zero
166 182
183
167 (music-step) 184 (music-step)
168 0x18 185 0x18
169 (->signed-8-bit (+ (- (count (music-step))) 186 (->signed-8-bit (+ (- (count (music-step)))
170 -2))])) 187 -2))]))
171 188
186 0xA6 0x55 0xFF 203 0xA6 0x55 0xFF
187 0xA6 0x55 0xFF 204 0xA6 0x55 0xFF
188 0xA6 0x55 0xFF 205 0xA6 0x55 0xFF
189 0x00 0x00 0xFF 206 0x00 0x00 0xFF
190 ]) 207 ])
191 208
192 209 (defn frequency-code->frequency
210 [code]
211 (assert (<= 0 code 2047))
212 (/ 131072 (- 2048 code)))
213
214 (defn clamp [x low high]
215 (cond (> x high) high
216 (< x low) low
217 true x))
218
219 (defn frequency->frequency-code
220 [frequency]
221 (clamp
222 (Math/round
223 (float
224 (/ (- (* 2048 frequency) 131072) frequency)))
225 0x00 2048))
226
227 (defn note-codes [frequency volume duration]
228 (assert (<= 0 volume 0xF))
229 (assert (<= 0 duration 0xFF))
230 (let [frequency-code
231 (frequency->frequency-code frequency)
232 volume&high-frequency
233 (+ (bit-shift-left volume 4)
234 (bit-shift-right frequency-code 8))
235 low-frequency
236 (bit-and 0xFF frequency-code)]
237 [volume&high-frequency
238 low-frequency
239 duration]))
240
241 (def C4 (partial note-codes 261.63))
242 (def D4 (partial note-codes 293.66))
243 (def E4 (partial note-codes 329.63))
244 (def F4 (partial note-codes 349.23))
245 (def G4 (partial note-codes 392))
246 (def A4 (partial note-codes 440))
247 (def B4 (partial note-codes 493.88))
248 (def C5 (partial note-codes 523.3))
249
250 (def scale
251 (flatten
252 [(C4 0xF 0x40)
253 (D4 0xF 0x40)
254 (E4 0xF 0x40)
255 (F4 0xF 0x40)
256 (G4 0xF 0x40)
257 (A4 0xF 0x40)
258 (B4 0xF 0x40)
259 (C5 0xF 0x40)]))
260
193 (defn play-music [music-bytes] 261 (defn play-music [music-bytes]
194 (let [program-target 0xC000 262 (let [program-target 0xC000
195 music-target 0xD000] 263 music-target 0xD000]
196 (-> (set-memory-range (second (music-base)) 264 (-> (set-memory-range (second (music-base))
197 program-target (music-kernel)) 265 program-target (music-kernel))
218 (PC! target))))) 286 (PC! target)))))
219 287
220 (defn trippy [] 288 (defn trippy []
221 (run-moves (play-music many-notes ) (repeat 8000 []))) 289 (run-moves (play-music many-notes ) (repeat 8000 [])))
222 290
291 (defn test-timer []
292 (flatten
293 [0x3E
294 0x01
295 0xE0
296 0x06 ;; set TMA to 0
297
298 0x3E
299 (Integer/parseInt "00000100" 2)
300 0xE0
301 0x07 ;; set TAC to 16384 Hz and activate timer
302
303 (repeat
304 500
305 [0xF0
306 0x05])]))