view clojure/com/aurellem/run/music.clj @ 417:0b6624c1291c

made basic tone player.
author Robert McIntyre <rlm@mit.edu>
date Mon, 16 Apr 2012 14:08:56 -0500
parents
children f211cd655ccb
line wrap: on
line source
1 (ns com.aurellem.run.music
2 (:use (com.aurellem.gb saves gb-driver util constants
3 items vbm characters money
4 rlm-assembly))
5 (:use (com.aurellem.run util title save-corruption
6 bootstrap-0 bootstrap-1))
7 (:import [com.aurellem.gb.gb_driver SaveState]))
10 (def music-base new-kernel)
15 (defn store [n address]
16 (flatten
17 [0xF5
18 0xE5
20 0x3E
21 n
23 0x21
24 (reverse (disect-bytes-2 address))
26 0x77
28 0xE1
29 0xF1]))
31 (defn infinite-loop []
32 [0x18 0xFE])
36 (def divider-register 0xFF04)
39 (defrecord Bit-Note [frequency volume duration duty])
41 (defn clear-music-registers []
42 (flatten
43 [(store (Integer/parseInt "00000000" 2) 0xFF10)
44 (store (Integer/parseInt "00000000" 2) 0xFF11)
45 (store (Integer/parseInt "00000000" 2) 0xFF12)
46 (store (Integer/parseInt "00000000" 2) 0xFF13)
47 (store (Integer/parseInt "00000000" 2) 0xFF14)
49 (store (Integer/parseInt "00000000" 2) 0xFF16) ;; pattern duty 000000
50 (store (Integer/parseInt "00000000" 2) 0xFF17) ;; volume 0000
51 (store (Integer/parseInt "00000000" 2) 0xFF18) ;; frequency-low
52 (store (Integer/parseInt "00000000" 2) 0xFF19) ;; 00000 frequency-high
54 (store (Integer/parseInt "00000000" 2) 0xFF1A)
55 (store (Integer/parseInt "00000000" 2) 0xFF1B)
56 (store (Integer/parseInt "00000000" 2) 0xFF1C)
57 (store (Integer/parseInt "00000000" 2) 0xFF1D)
58 (store (Integer/parseInt "00000000" 2) 0xFF1E)
60 (store (Integer/parseInt "00000000" 2) 0xFF20)
61 (store (Integer/parseInt "00000000" 2) 0xFF21)
62 (store (Integer/parseInt "00000000" 2) 0xFF22)
63 (store (Integer/parseInt "00000000" 2) 0xFF23)]))
65 (defn play-note
66 "Play the note referenced by HL in the appropiate channel.
67 Leaves desired-duration in A."
68 []
69 [0x2A ;; load volume/frequency-high info
70 0xF5 ;; push A
71 0xE6
72 (Integer/parseInt "11110000" 2) ;; volume mask
73 0xE0
74 0x17 ;; set volume
75 0xF1 ;; pop A
76 0xE6
77 (Integer/parseInt "00000111" 2) ;; frequency-high mask
78 0xE0
79 0x19 ;; set frequency-high
81 0x2A ;; load frequency low-bits
82 0xE0
83 0x18 ;; set frequency-low-bits
85 0x7E ;; load duration
86 ;;0x2B ;;
87 ;;0x2B
88 ]) ;; HL-2 -> HL
90 (defn music-step []
91 (flatten
92 [(play-note)
93 0xF5 ;; push A
94 0xF0
95 0x05 ;; load current ticks
96 0x90 ;; B holds previous sub-ticks, subtract it from A
97 ;; if A-B caused a carry, then (B > A) is true, and
98 ;; A = current-sub-tics, B = previous-sub-ticks, so
99 ;; current-sub-ticks < previous-sub-ticks, which means that the
100 ;; timer counter HAS overflowed.
101 0x30 ;; increment C only if last result caused carry
102 0x01
103 0x00;;0x0C
105 0x47 ;; update sub-ticks (A->B)
107 0xF1 ;; pop AF, now A contains desired-ticks
109 0xB9 ;; compare with current ticks
111 ;; if desired-ticks = current ticks
112 ;; go to next note ; set current set ticks to 0.
114 0x20
115 0x05
117 0x23
118 0x23
119 0x23 ;; HL + 3 -> HL
121 0x0E
122 0x00])) ;; 0->C (current-ticks)
124 (defn music-kernel []
125 (flatten
126 [(clear-music-registers)
127 0x21
128 0x00
129 0xD0 ;; set HL to 0xD000 == music-start
130 0x0E
131 0x00 ;; 0->C
132 0x06
133 0x00 ;; 0->B
135 0x3E
136 0x00
137 0xE0
138 0x06 ;; set TMA to 0
140 0x3E
141 (Integer/parseInt "00000111" 2)
142 0xE0
143 0x07 ;; set TAC to 16384 Hz
145 (music-step)
146 0x18
147 (->signed-8-bit (+ (- (count (music-step)))
148 -2))]))
151 (defn play-music [steps music-bytes]
152 (let [program-target 0xC000
153 music-target 0xD000]
154 (-> (set-memory-range (second (music-base))
155 program-target (music-kernel))
156 (set-memory-range music-target music-bytes)
157 (PC! program-target))))
160 (defn test-note [music-bytes]
161 (-> (set-memory-range (second (music-base))
162 0xC000 (concat (clear-music-registers)
163 (play-note)
164 (infinite-loop)))
165 (set-memory-range 0xD000 music-bytes)
166 (PC! 0xC000)
167 (HL! 0xD000)
168 ))
171 (defn run-program
172 ([program] (run-program program 90))
173 ([program steps]
174 (let [target 0xC000]
175 (-> (set-memory-range (second (music-base))
176 target program)
177 (PC! target)))))