comparison clojure/com/aurellem/run/music.clj @ 484:f6b5a1914efa

merge.
author Robert McIntyre <rlm@mit.edu>
date Sun, 06 May 2012 20:52:31 -0500
parents 221b3fea9221
children 346b91ae503a
comparison
equal deleted inserted replaced
483:1bc26d1826e5 484:f6b5a1914efa
6 bootstrap-0 bootstrap-1)) 6 bootstrap-0 bootstrap-1))
7 (:require clojure.string) 7 (:require clojure.string)
8 (:import [com.aurellem.gb.gb_driver SaveState]) 8 (:import [com.aurellem.gb.gb_driver SaveState])
9 (:import java.io.File)) 9 (:import java.io.File))
10 10
11 (def third-kind 11 (def pony
12 (File. "/home/r/proj/midi/third-kind.mid")) 12 (File. user-home "/proj/vba-clojure/music/pony-title.mid"))
13
14 (def pony-csv
15 (File. user-home "proj/vba-clojure/music/pony-title.csv"))
16
17 (def sync-test
18 (File. user-home "proj/vba-clojure/music/sync-test.mid"))
19
20 (def drum-test
21 (File. user-home "proj/vba-clojure/music/drum-test.mid"))
22
23 (def regret
24 (File. user-home "proj/vba-clojure/music/ship-of-regret-and-sleep.mid"))
25
26 (def regret-csv
27 (File. user-home "proj/vba-clojure/music/ship-of-regret-and-sleep.csv"))
28
29 (def mother
30 (File. user-home "proj/vba-clojure/music/mother.mid"))
31
32 (def mother-csv
33 (File. user-home "proj/vba-clojure/music/mother.csv"))
34
13 35
14 (defn raw-midi-text [#^File midi-file] 36 (defn raw-midi-text [#^File midi-file]
15 (:out 37 (let [extention (apply str (take-last 3 (.getCanonicalPath
16 (clojure.java.shell/sh 38 midi-file)))]
17 "midicsv" 39 (cond (= "mid" extention)
18 (.getCanonicalPath midi-file) 40 (:out
19 "-"))) 41 (clojure.java.shell/sh
42 "midicsv"
43 (.getCanonicalPath midi-file)
44 "-"))
45 (= "csv" extention)
46 (slurp midi-file))))
20 47
21 (def command-line #"^(\d+), (\d+), ([^,]+)(.*)$") 48 (def command-line #"^(\d+), (\d+), ([^,]+)(.*)$")
22 49
23 (defmulti parse-command :command) 50 (defmulti parse-command :command)
24 51
168 195
169 (defn do-message 196 (defn do-message
170 "Read the message which starts at the current value of HL and do 197 "Read the message which starts at the current value of HL and do
171 what it says. Duration is left in A, and HL is advanced 198 what it says. Duration is left in A, and HL is advanced
172 appropraitely." 199 appropraitely."
173 ([] (do-message 0x16)) 200 ([] (do-message 0x16 1))
174 ([sound-base-address] 201 ([sound-base-address wave-duty]
202 (assert (<= 0 wave-duty 3))
175 (let [switch 203 (let [switch
176 [0x2A ;; load message code into A, increment HL 204 [0x2A ;; load message code into A, increment HL
177 205
178 ;; switch on message 206 ;; switch on message
179 0xFE 207 0xFE
181 209
182 0x20 210 0x20
183 :note-length] 211 :note-length]
184 212
185 play-note 213 play-note
186 [0x2A ;; load volume/frequency-high info 214 [0x3E ;; set wave-duty
215 (bit-shift-left wave-duty 6)
216 0xE0
217 sound-base-address
218 0x2A ;; load volume/frequency-high info
187 0xF5 ;; push A 219 0xF5 ;; push A
188 0xE6 220 0xE6
189 (Integer/parseInt "11110000" 2) ;; volume mask 221 (Integer/parseInt "11110000" 2) ;; volume mask
190 0xE0 222 0xE0
191 (inc sound-base-address) ;;0x17 ;; set volume 223 (inc sound-base-address) ;;0x17 ;; set volume
201 0x2A]] ;; load duration 233 0x2A]] ;; load duration
202 (replace 234 (replace
203 {:note-length (count play-note)} 235 {:note-length (count play-note)}
204 (concat switch play-note))))) 236 (concat switch play-note)))))
205 237
238 (defn play-noise
239 "read [noise-code, volume, duration] and play the noise. Duration is left in
240 A, and HL is advanced appropraitely."
241 ([]
242 [0x2A ;; load noise-code into A
243 0xE0
244 0x22 ;; write noise-code
245
246 0x2A ;; load volume
247 0xE0
248 0x21 ;; write volume
249
250 0x2A] ;; load duration into A
251 ))
252
253
206 ;; (defn play-note 254 ;; (defn play-note
207 ;; "Play the note referenced by HL in the appropiate channel. 255 ;; "Play the note referenced by HL in the appropiate channel.
208 ;; Leaves desired-duration in A." 256 ;; Leaves desired-duration in A."
209 257
210 ;; [0x2A ;; load volume/frequency-high info 258 ;; [0x2A ;; load volume/frequency-high info
224 ;; 0x18 ;; set frequency-low-bits 272 ;; 0x18 ;; set frequency-low-bits
225 273
226 ;; 0x2A ;; load duration 274 ;; 0x2A ;; load duration
227 ;; ]) 275 ;; ])
228 276
229 (defn music-step [sound-base-address] 277 (defn music-step [sound-base-address wave-duty noise?]
230 ;; C == current-ticks 278 ;; C == current-ticks
231 ;; A == desired-ticks 279 ;; A == desired-ticks
232 280
233 (flatten 281 (flatten
234 [;; restore variables from stack 282 [;; restore variables from stack
252 0xB9 ;; compare with current ticks 300 0xB9 ;; compare with current ticks
253 301
254 ;; if desired-ticks = current ticks 302 ;; if desired-ticks = current ticks
255 ;; go to next note ; set current set ticks to 0. 303 ;; go to next note ; set current set ticks to 0.
256 304
257 0x20 305 (if noise?
258 (+ (count (do-message 0)) 2) 306 [0x20
259 307 (+ 2 (count (play-noise)))
260 (do-message sound-base-address) 308 (play-noise)]
309
310 [0x20
311 (+ (count (do-message 0 0)) 2)
312 (do-message sound-base-address wave-duty)])
261 313
262 0x0E 314 0x0E
263 0x00 ;; 0->C (current-ticks) 315 0x00 ;; 0->C (current-ticks)
264 316
265 ;; save variables to stack 317 ;; save variables to stack
271 ])) 323 ]))
272 324
273 (def music-1 0x11) 325 (def music-1 0x11)
274 (def music-2 0x16) 326 (def music-2 0x16)
275 327
276 (defn music-kernel [] 328 (defn music-kernel [wave-duty-1 wave-duty-2]
277 (flatten 329 (flatten
278 [;; global initilization section 330 [;; global initilization section
279 (clear-music-registers) 331 (clear-music-registers)
280 332
281 0x3E 333 0x3E
311 0xF5 ;; push AF 363 0xF5 ;; push AF
312 0xC5 ;; push CB 364 0xC5 ;; push CB
313 0xE5 ;; push HL 365 0xE5 ;; push HL
314 366
315 367
368 ;; initialize frame 3 (noise)
369 0x21
370 0x00
371 0xA9 ;; 0xA9OO -> HL
372
373 0xF5 ;; push AF
374 0xC5 ;; push CB
375 0xE5 ;; push HL
376
316 ;; main music loop 377 ;; main music loop
317 378
318 0xE8 ;; SP + 6; activate frame 1 379 0xE8 ;; SP + 12; activate frame 1
319 6 380 12
320 (music-step music-1) 381 (music-step music-1 wave-duty-1 false)
321 ;;(repeat (count (music-step music-1)) 0x00)
322 382
323 0xE8 ;; SP - 6; activate frame 2 383 0xE8 ;; SP - 6; activate frame 2
324 (->signed-8-bit -6) 384 (->signed-8-bit -6)
325 ;;(repeat (count (music-step music-2)) 0x00) 385 (music-step music-2 wave-duty-2 false)
326 (music-step music-2) 386
327 387 0xE8 ;; SP - 6; activate frame 3
388 (->signed-8-bit -6)
389 (music-step nil nil true)
328 390
329 0x18 391 0x18
330 (->signed-8-bit (+ 392 (->signed-8-bit (+
331 ;; two music-steps 393 ;; two music-steps
332 (- (* 2 (count (music-step 0)))) 394 (- (* 2 (count (music-step 0 0 false))))
395 (- (count (music-step nil nil true)))
333 -2 ;; this jump instruction 396 -2 ;; this jump instruction
334 -2 ;; activate frame 1 397 -2 ;; activate frame 1
335 -2 ;; activate frame 2 398 -2 ;; activate frame 2
399 -2 ;; activate frame 3
336 ))])) 400 ))]))
337 401
338 (defn frequency-code->frequency 402 (defn frequency-code->frequency
339 [code] 403 [code]
340 (assert (<= 0 code 2047)) 404 (assert (<= 0 code 2047))
393 (defn commands 457 (defn commands
394 "return all events where #(= (:command %) command)" 458 "return all events where #(= (:command %) command)"
395 [command s] 459 [command s]
396 (filter #(= command (:command %)) s)) 460 (filter #(= command (:command %)) s))
397 461
398 (defn midi-track->mini-midi [#^File midi-file track-num] 462 (defn track-info [#^File midi-file]
399 (let [midi-events (parse-midi midi-file) 463 (let [events (parse-midi midi-file)
464 track-titles (commands :Title_t events)
465 track-info
466 (map #(read-string (read-string (:args %))) track-titles)
467 track-map
468 (zipmap track-info track-titles)]
469 track-map))
470
471 (defn target-tracks
472 "return the track-numbers in the form [voice-0 voice-1 noise]"
473 [#^File midi-file]
474 (let [track-data (track-info midi-file)
475 track-order
476 (zipmap (map :out (keys track-data))
477 (vals track-data))
478 channel-nums (map (comp :channel track-order) (range 3))]
479 channel-nums))
480
481 (defn midi-track->abstract-mini-midi
482 [#^File midi-file track-num]
483 (let [midi-events (parse-midi midi-file)
400 484
401 note-on-events (commands :Note_on_c midi-events) 485 note-on-events (commands :Note_on_c midi-events)
402 note-off-events (commands :Note_off_c midi-events) 486 note-off-events (commands :Note_off_c midi-events)
403 487
404 select-channel 488 select-channel
405 (fn [n s] 489 (fn [n s]
406 (sort-by :time (filter #(= n (:channel (:args %))) s))) 490 (sort-by :time (filter #(= n (:channel %)) s)))
407 491
408 channel-on (select-channel track-num note-on-events) 492 channel-on (select-channel track-num note-on-events)
409 493
410 channel-off (select-channel track-num note-off-events) 494 channel-off (select-channel track-num note-off-events)
411 495
416 500
417 notes 501 notes
418 (map 502 (map
419 (fn [note-on note-off] 503 (fn [note-on note-off]
420 {:frequency (midi-code->frequency (:note (:args note-on))) 504 {:frequency (midi-code->frequency (:note (:args note-on)))
505 :midi-code (:note (:args note-on))
421 :duration 506 :duration
422 (/ (* (/ tempo division) 507 (/ (* (/ tempo division)
423 (- (:time note-off) (:time note-on))) 508 (- (:time note-off) (:time note-on)))
424 1e6) ;; convert clock-pulses into seconds 509 1e6) ;; convert clock-pulses into seconds
425 :volume (int (/ (:velocity (:args note-on)) 10)) 510 :volume (int (/ (:velocity (:args note-on)) 10))
437 (concat [(assoc (silence 0) 522 (concat [(assoc (silence 0)
438 :time-stamp 0)] notes) 523 :time-stamp 0)] notes)
439 notes) 524 notes)
440 525
441 notes-with-silence 526 notes-with-silence
442 (filter (comp not zero? :duration) 527 (concat
443 (interleave silences notes))] 528 (filter (comp not zero? :duration)
529 (interleave silences notes))
530 [(silence 3)])]
531 notes-with-silence))
532
533 (defn midi-track->mini-midi-voice [#^File midi-file track-num]
534 (let [abstract-mini-midi
535 (midi-track->abstract-mini-midi midi-file track-num)]
536 (map
537 (fn [note-event]
538 (note-codes (:frequency note-event)
539 (:volume note-event)
540 (int (* (:duration note-event) 0x100))))
541 abstract-mini-midi)))
542
543 (def midi-code->gb-noise-code
544 {nil 0xFF
545 35 87
546 38 20
547 39 0
548 })
549
550 (defn noise-codes [code volume duration]
551 (assert (<= 0 volume 0xF))
552 (if (<= duration 0xFF)
553 [(midi-code->gb-noise-code code code)
554 (bit-shift-left volume 4)
555 duration]
556 (vec
557 (flatten
558 [(noise-codes code volume 0xFF)
559 (noise-codes code volume (- duration 0xFF))]))))
560
561 (defn midi-track->mini-midi-noise [#^File midi-file track-num]
562 (let [abstract-mini-midi
563 (midi-track->abstract-mini-midi midi-file track-num)]
444 (map 564 (map
445 (fn [note-event] 565 (fn [noise-event]
446 (note-codes (:frequency note-event) 566 (noise-codes (:midi-code noise-event)
447 (:volume note-event) 567 (:volume noise-event)
448 (int (* (:duration note-event) 0x100)))) 568 (int (* (:duration noise-event) 0x100))))
449 notes-with-silence))) 569 abstract-mini-midi)))
570
450 571
451 (defn midi->mini-midi [#^File midi-file] 572 (defn midi->mini-midi [#^File midi-file]
452 {:track-1 (flatten (midi-track->mini-midi midi-file 1)) 573 (let [targets (target-tracks midi-file)
453 :track-2 (flatten (midi-track->mini-midi midi-file 2))}) 574 duty-info (keys (track-info midi-file))]
575
576 {:voice-1 (midi-track->mini-midi-voice midi-file (nth targets 0))
577 :voice-2 (midi-track->mini-midi-voice midi-file (nth targets 1))
578 :noise (midi-track->mini-midi-noise midi-file (nth targets 2))
579 :duty (zipmap (map :out duty-info)
580 (map #(get % :duty 0) duty-info))}))
454 581
455 (defn play-midi [#^File midi-file] 582 (defn play-midi [#^File midi-file]
456 (let [track-1-target 0xA000 583 (let [voice-1-target 0xA000
457 track-2-target 0xB000 584 voice-2-target 0xB000
585 noise-target 0xA900
458 program-target 0xC000 586 program-target 0xC000
459 mini-midi (midi->mini-midi midi-file) 587 mini-midi (midi->mini-midi midi-file)
460 long-silence (flatten (note-codes 20 0 9001))] 588 long-silence (flatten (note-codes 20 0 20001))
589 long-noise-silence
590 (interleave (range 500) (repeat 0x00) (repeat 255))
591
592 voice-1 (flatten (:voice-1 mini-midi))
593 wave-duty-1 ((:duty mini-midi) 0 0)
594
595 voice-2 (flatten (:voice-2 mini-midi))
596 wave-duty-2 ((:duty mini-midi) 1 0)
597
598 noise (flatten (:noise mini-midi))
599 ]
461 600
462 (-> (second (music-base)) 601 (-> (second (music-base))
463 (set-memory-range track-1-target long-silence) 602 (set-memory-range voice-1-target long-silence)
464 (set-memory-range track-2-target long-silence) 603 (set-memory-range voice-2-target long-silence)
465 (set-memory-range track-1-target (:track-1 mini-midi)) 604 (set-memory-range noise-target long-noise-silence)
466 (set-memory-range track-2-target (:track-2 mini-midi)) 605 (set-memory-range voice-1-target voice-1)
467 (set-memory-range program-target (music-kernel)) 606 (set-memory-range voice-2-target voice-2)
607 (set-memory-range noise-target noise)
608 (set-memory-range
609 program-target
610 (music-kernel wave-duty-1 wave-duty-2))
468 (PC! program-target)))) 611 (PC! program-target))))
469 612
470 613 (defn test-noise []
471 614 (let [noise-pattern
615 (concat (interleave (range 0x100) (repeat 0xF0) (repeat 255))
616 (interleave (range 10) (repeat 0x00) (repeat 255)))]
617
618 (-> (second (music-base))
619 (set-memory-range 0xA900 (flatten noise-pattern))
620 (set-memory-range 0xC000 (music-kernel 0 0))
621 (PC! 0xC000))))
622
623 (defn test-play-noise [noise-code]
624 (Thread/sleep 300)
625 (println "playing noise:" noise-code)
626 (run-moves
627 (let [noise-pattern
628 (interleave (repeat 10 noise-code) (repeat 0xF0) (repeat 255))]
629 (-> (second (music-base))
630 (set-memory-range 0xA900 (flatten noise-pattern))
631 (set-memory-range 0xC000 (music-kernel 0 0))
632 (PC! 0xC000)))
633 (repeat 20 [])))
634
635 (defn test-all-noises []
636 (dorun (map test-play-noise (range 0x100))))
472 637
473 (def C4 (partial note-codes 261.63)) 638 (def C4 (partial note-codes 261.63))
474 (def D4 (partial note-codes 293.66)) 639 (def D4 (partial note-codes 293.66))
475 (def E4 (partial note-codes 329.63)) 640 (def E4 (partial note-codes 329.63))
476 (def F4 (partial note-codes 349.23)) 641 (def F4 (partial note-codes 349.23))
496 (-> (set-memory-range (second (music-base)) 661 (-> (set-memory-range (second (music-base))
497 program-target (music-kernel)) 662 program-target (music-kernel))
498 (set-memory-range music-target music-bytes) 663 (set-memory-range music-target music-bytes)
499 (PC! program-target)))) 664 (PC! program-target))))
500 665
501
502
503 ;; (defn test-note [music-bytes]
504 ;; (-> (set-memory-range (second (music-base))
505 ;; 0xC000 (concat (clear-music-registers)
506 ;; (play-note)
507 ;; (infinite-loop)))
508 ;; (set-memory-range 0xD000 music-bytes)
509 ;; (PC! 0xC000)
510 ;; (HL! 0xD000)
511 ;; ))
512
513
514 (defn run-program 666 (defn run-program
515 ([program] 667 ([program]
516 (let [target 0xC000] 668 (let [target 0xC000]
517 (-> (set-memory-range (second (music-base)) 669 (-> (set-memory-range (second (music-base))
518 target program) 670 target program)
533 (repeat 685 (repeat
534 500 686 500
535 [0xF0 687 [0xF0
536 0x05])])) 688 0x05])]))
537 689
538 690 (defn play-pony []
691 (println "playing" (.getName pony-csv))
692 (run-moves (play-midi pony-csv) (repeat 1800 [])))
693
694 (defn play-regret []
695 (println "playing" (.getName regret-csv))
696 (run-moves (play-midi regret-csv) (repeat 3380 [])))
697
698 (defn play-mother []
699 (println "playing" (.getName mother-csv))
700 (run-moves (play-midi mother-csv) (repeat 2200 [])))
701
702 (defn demo [] (play-mother) (play-regret) (play-pony))
703
704
705