diff 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
line wrap: on
line diff
     1.1 --- a/clojure/com/aurellem/run/music.clj	Tue Apr 17 06:53:48 2012 -0500
     1.2 +++ b/clojure/com/aurellem/run/music.clj	Mon Apr 23 04:45:55 2012 -0500
     1.3 @@ -62,6 +62,44 @@
     1.4      (store (Integer/parseInt "00000000" 2) 0xFF22)
     1.5      (store (Integer/parseInt "00000000" 2) 0xFF23)]))
     1.6  
     1.7 +
     1.8 +;; mini-midi syntax
     1.9 +
    1.10 +;; codes
    1.11 +;; note-code == 0x00
    1.12 +;; change-duty-code = 0x01
    1.13 +;; silence-code = 0x02
    1.14 +
    1.15 +;; silence format
    1.16 +;;  2 bytes
    1.17 +;;  [silence-code (0x02)]
    1.18 +;;  [duration-8-bits]
    1.19 +
    1.20 +;; note data format
    1.21 +;;  4 bytes
    1.22 +;;  [note-code (0x00)]
    1.23 +;;  [volume-4-bits 0 frequency-high-3-bits]
    1.24 +;;  [frequengy-low-8-bits]
    1.25 +;;  [duration-8-bits]
    1.26 +
    1.27 +;; change-duty-format
    1.28 +;;  2 bytes
    1.29 +;;  [change-duty-code (0x01)]
    1.30 +;;  [new-duty]
    1.31 +
    1.32 +(defn do-message
    1.33 +  "Read the message which starts at the current value of HL and do
    1.34 +   what it says. Duration is left in A, and HL is advanced
    1.35 +   appropraitely."
    1.36 +  []
    1.37 +
    1.38 +  )
    1.39 +
    1.40 +
    1.41 +
    1.42 +
    1.43 +
    1.44 +
    1.45  (defn play-note
    1.46    "Play the note referenced by HL in the appropiate channel.
    1.47     Leaves desired-duration in A."
    1.48 @@ -82,14 +120,12 @@
    1.49     0xE0
    1.50     0x18   ;; set frequency-low-bits
    1.51  
    1.52 -   0x7E   ;; load duration
    1.53 -   0x2B   ;; 
    1.54 -   0x2B   ;; HL-2 -> HL
    1.55 +   0x2A   ;; load duration
    1.56     ]) 
    1.57  
    1.58  (defn music-step []
    1.59    (flatten
    1.60 -   [(play-note)
    1.61 +   [
    1.62      0xF5 ;; push A
    1.63      0xF0
    1.64      0x05 ;; load current ticks
    1.65 @@ -112,33 +148,13 @@
    1.66      ;;   go to next note ; set current set ticks to 0.
    1.67  
    1.68      0x20
    1.69 -    0x05
    1.70 +    (+ (count (play-note)) 2)
    1.71  
    1.72 -    0x23
    1.73 -    0x23
    1.74 -    0x23 ;; HL + 3 -> HL
    1.75 +    (play-note)
    1.76      
    1.77      0x0E
    1.78      0x00])) ;; 0->C (current-ticks)
    1.79  
    1.80 -(defn test-timer []
    1.81 -  (flatten
    1.82 -   [0x3E
    1.83 -    0x01
    1.84 -    0xE0
    1.85 -    0x06 ;; set TMA to 0
    1.86 -    
    1.87 -    0x3E
    1.88 -    (Integer/parseInt "00000100" 2)
    1.89 -    0xE0
    1.90 -    0x07 ;; set TAC to 16384 Hz and activate timer
    1.91 -    
    1.92 -    (repeat
    1.93 -     500
    1.94 -     [0xF0
    1.95 -      0x05])]))
    1.96 -
    1.97 -
    1.98  (defn music-kernel []
    1.99    (flatten
   1.100     [(clear-music-registers)
   1.101 @@ -161,9 +177,10 @@
   1.102      0xE0
   1.103      0x07 ;; set TAC to 65536 Hz and activate timer
   1.104  
   1.105 -    0xF0
   1.106 -    0x07
   1.107 -    
   1.108 +
   1.109 +    0xAF ;; initialiaze A to zero
   1.110 +
   1.111 +
   1.112      (music-step)
   1.113      0x18
   1.114      (->signed-8-bit (+ (- (count (music-step)))
   1.115 @@ -188,8 +205,59 @@
   1.116     0xA6 0x55 0xFF
   1.117     0x00 0x00 0xFF
   1.118     ])
   1.119 -   
   1.120 -   
   1.121 +
   1.122 +(defn frequency-code->frequency
   1.123 +  [code]
   1.124 +  (assert (<= 0 code 2047))
   1.125 +  (/ 131072 (- 2048 code)))
   1.126 +
   1.127 +(defn clamp [x low high]
   1.128 +  (cond  (> x high) high
   1.129 +         (< x low)  low
   1.130 +         true x))
   1.131 +
   1.132 +(defn frequency->frequency-code
   1.133 +  [frequency]
   1.134 +  (clamp
   1.135 +   (Math/round
   1.136 +    (float
   1.137 +     (/ (- (* 2048 frequency) 131072) frequency)))
   1.138 +   0x00 2048))
   1.139 +    
   1.140 +(defn note-codes [frequency volume duration]
   1.141 +  (assert (<= 0 volume 0xF))
   1.142 +  (assert (<= 0 duration 0xFF))
   1.143 +  (let [frequency-code
   1.144 +        (frequency->frequency-code frequency)
   1.145 +        volume&high-frequency
   1.146 +        (+ (bit-shift-left volume 4)
   1.147 +           (bit-shift-right frequency-code 8))
   1.148 +        low-frequency
   1.149 +        (bit-and 0xFF frequency-code)]
   1.150 +    [volume&high-frequency
   1.151 +     low-frequency
   1.152 +     duration]))
   1.153 +
   1.154 +(def C4 (partial note-codes 261.63))
   1.155 +(def D4 (partial note-codes 293.66))
   1.156 +(def E4 (partial note-codes 329.63))
   1.157 +(def F4 (partial note-codes 349.23))
   1.158 +(def G4 (partial note-codes 392))
   1.159 +(def A4 (partial note-codes 440))
   1.160 +(def B4 (partial note-codes 493.88))
   1.161 +(def C5 (partial note-codes 523.3))
   1.162 +
   1.163 +(def scale
   1.164 +  (flatten
   1.165 +   [(C4 0xF 0x40)
   1.166 +    (D4 0xF 0x40)
   1.167 +    (E4 0xF 0x40)
   1.168 +    (F4 0xF 0x40)
   1.169 +    (G4 0xF 0x40)
   1.170 +    (A4 0xF 0x40)
   1.171 +    (B4 0xF 0x40)
   1.172 +    (C5 0xF 0x40)]))
   1.173 +                 
   1.174  (defn play-music [music-bytes]
   1.175    (let [program-target 0xC000
   1.176          music-target 0xD000]
   1.177 @@ -220,3 +288,19 @@
   1.178  (defn trippy []
   1.179    (run-moves (play-music many-notes ) (repeat 8000 [])))
   1.180  
   1.181 +(defn test-timer []
   1.182 +  (flatten
   1.183 +   [0x3E
   1.184 +    0x01
   1.185 +    0xE0
   1.186 +    0x06 ;; set TMA to 0
   1.187 +    
   1.188 +    0x3E
   1.189 +    (Integer/parseInt "00000100" 2)
   1.190 +    0xE0
   1.191 +    0x07 ;; set TAC to 16384 Hz and activate timer
   1.192 +    
   1.193 +    (repeat
   1.194 +     500
   1.195 +     [0xF0
   1.196 +      0x05])]))