rlm@530
|
1 (ns com.aurellem.run.final-cut
|
rlm@530
|
2 (:use (com.aurellem.gb saves gb-driver util constants
|
rlm@530
|
3 items vbm characters money
|
rlm@530
|
4 rlm-assembly))
|
rlm@530
|
5 (:use (com.aurellem.run util sound music title save-corruption
|
rlm@530
|
6 bootstrap-0 bootstrap-1
|
rlm@530
|
7 ram-display
|
rlm@530
|
8 ))
|
rlm@530
|
9 (:require clojure.string)
|
rlm@530
|
10 (:import [com.aurellem.gb.gb_driver SaveState])
|
rlm@530
|
11 (:import java.awt.image.BufferedImage)
|
rlm@530
|
12 (:import java.io.File)
|
rlm@530
|
13 (:import com.aurellem.gb.WaveWriter))
|
rlm@530
|
14
|
rlm@530
|
15
|
rlm@542
|
16 (def render-dir (File. user-home "proj/vba-clojure/render/test"))
|
rlm@530
|
17
|
rlm@546
|
18 (defn write-move-image! [move target-file]
|
rlm@546
|
19 (let [actual-keys (set move)
|
rlm@546
|
20 keys [:a :b :start :select :u :d :l :r]
|
rlm@546
|
21 button-on-name ["-size" "5x5" "xc:red"]
|
rlm@546
|
22 button-off-name ["-size" "5x5" "xc:white"]]
|
rlm@546
|
23 (apply
|
rlm@546
|
24 clojure.java.shell/sh
|
rlm@546
|
25 (flatten
|
rlm@546
|
26 ["convert"
|
rlm@546
|
27 "-size" "64x5" "xc:white"
|
rlm@546
|
28 (map
|
rlm@546
|
29 (fn [index]
|
rlm@546
|
30 (let [position ["-geometry"
|
rlm@546
|
31 (str "+" (* index 8)
|
rlm@546
|
32 "+" "0") "-composite"]]
|
rlm@546
|
33 (if (actual-keys (keys index))
|
rlm@546
|
34 [button-on-name position]
|
rlm@546
|
35 [button-off-name position])))
|
rlm@546
|
36 (range (count keys)))
|
rlm@546
|
37 (.getCanonicalPath target-file)]))))
|
rlm@544
|
38
|
rlm@530
|
39 (defn render-files!
|
rlm@530
|
40 ([^File target-dir initial-state moves]
|
rlm@530
|
41 (let [ram-map-dir (File. target-dir "ram-map")
|
rlm@530
|
42 frames-dir (File. target-dir "frames")
|
rlm@546
|
43 moves-dir (File. target-dir "moves")
|
rlm@530
|
44 audio-file (File. target-dir "audio.wav")
|
rlm@533
|
45 _ (.mkdir target-dir)
|
rlm@533
|
46 _ (.mkdir ram-map-dir)
|
rlm@533
|
47 _ (.mkdir frames-dir)
|
rlm@546
|
48 _ (.mkdir moves-dir)
|
rlm@530
|
49 wave-writer (WaveWriter. audio-file)
|
rlm@544
|
50 moves (vec moves)
|
rlm@544
|
51 desired-fps 60
|
rlm@544
|
52 seconds-per-frame (/ 1.0 desired-fps)
|
rlm@544
|
53
|
rlm@544
|
54 ]
|
rlm@530
|
55 (set-state! initial-state)
|
rlm@544
|
56 ;; clear sound buffer
|
rlm@544
|
57 (sound-bytes)
|
rlm@544
|
58 (try
|
rlm@544
|
59 (dorun
|
rlm@544
|
60 (reduce
|
rlm@544
|
61 (fn [[total-audio-samples
|
rlm@544
|
62 total-video-samples] move]
|
rlm@544
|
63 (run-moves @current-state (vector move))
|
rlm@544
|
64 (let [sound (sound-bytes)
|
rlm@544
|
65 total-audio-samples (+ total-audio-samples
|
rlm@544
|
66 (count sound))
|
rlm@544
|
67 total-audio-time
|
rlm@544
|
68 (*
|
rlm@544
|
69 (/ total-audio-samples 4)
|
rlm@544
|
70 (/ 44100))
|
rlm@544
|
71
|
rlm@544
|
72 total-video-time (* total-video-samples
|
rlm@544
|
73 seconds-per-frame)
|
rlm@530
|
74
|
rlm@544
|
75 av-diff (- total-audio-time
|
rlm@544
|
76 total-video-time)
|
rlm@544
|
77 write-video!
|
rlm@544
|
78 (fn [index]
|
rlm@544
|
79 ;; write screenshot
|
rlm@546
|
80 (write-move-image!
|
rlm@546
|
81 move
|
rlm@546
|
82 (File. moves-dir (format "%07d.png" index)))
|
rlm@544
|
83
|
rlm@544
|
84 (write-png!
|
rlm@544
|
85 @current-state
|
rlm@544
|
86 (File. frames-dir (format "%07d.png" index)))
|
rlm@544
|
87
|
rlm@544
|
88 ;; write ram-image
|
rlm@544
|
89 (write-ram-image!
|
rlm@544
|
90 @current-state
|
rlm@544
|
91 (File. ram-map-dir (format "%07d.png" index))))]
|
rlm@544
|
92 ;;(println "audio-samples:" (count sound))
|
rlm@544
|
93
|
rlm@544
|
94 ;; record audio
|
rlm@544
|
95 (.process wave-writer sound gb-sound-format)
|
rlm@544
|
96
|
rlm@544
|
97 ;; duplicate or drop frames depending on
|
rlm@544
|
98 ;; desired-fps
|
rlm@544
|
99 (if (> (Math/abs av-diff) (* 2 seconds-per-frame))
|
rlm@544
|
100 (if (< 0 av-diff)
|
rlm@544
|
101 ;; audio has gone past video, duplicate video.
|
rlm@544
|
102 (do (println
|
rlm@544
|
103 "duplicating frame, av-diff is" av-diff)
|
rlm@544
|
104 (write-video! (+ 1 total-video-samples))
|
rlm@544
|
105 (write-video! (+ 2 total-video-samples))
|
rlm@544
|
106 [total-audio-samples
|
rlm@544
|
107 (+ 2 total-video-samples)])
|
rlm@544
|
108 ;; video has gone past audio, drop frame.
|
rlm@544
|
109 (do (println
|
rlm@544
|
110 "dropping frame, av-diff is" av-diff)
|
rlm@544
|
111 [total-audio-samples
|
rlm@544
|
112 total-video-samples]))
|
rlm@544
|
113 ;; no frame dropping or duplication required.
|
rlm@544
|
114 (do ;;(println "all normal")
|
rlm@544
|
115 (write-video! (+ 1 total-video-samples))
|
rlm@544
|
116 [total-audio-samples
|
rlm@544
|
117 (+ 1 total-video-samples)]))))
|
rlm@544
|
118 [0 0 0] moves))
|
rlm@544
|
119 (finally
|
rlm@544
|
120 (do
|
rlm@544
|
121 (println "cleanup audio.")
|
rlm@544
|
122 (.cleanup wave-writer))))))
|
rlm@544
|
123 ([initial-state moves]
|
rlm@544
|
124 (render-files! render-dir initial-state moves))
|
rlm@544
|
125 ([moves]
|
rlm@544
|
126 (render-files! (root) moves)))
|
rlm@530
|
127
|
rlm@531
|
128 (defn file-names [#^File dir]
|
rlm@531
|
129 (mapv #(.getCanonicalPath %) (next (sort (file-seq dir)))))
|
rlm@531
|
130
|
rlm@531
|
131 (defn composite-frames-command
|
rlm@546
|
132 [move-image screenshot ram-map target]
|
rlm@546
|
133 ["convert"
|
rlm@546
|
134 "-size" "318x276" "xc:white"
|
rlm@546
|
135 move-image "-geometry" "+30+225" "-composite"
|
rlm@546
|
136 screenshot "-geometry" "+10+10" "-composite"
|
rlm@546
|
137 ram-map "-geometry" "+180+10" "-composite"
|
rlm@546
|
138 target])
|
rlm@531
|
139
|
rlm@531
|
140 (defn generate-composite-frames!
|
rlm@532
|
141 [^File rendered-dir moves]
|
rlm@532
|
142 (let [final-frames (File. rendered-dir "final")
|
rlm@532
|
143 _ (.mkdir final-frames)
|
rlm@532
|
144 screenshots (file-names (File. rendered-dir "frames"))
|
rlm@532
|
145 ram-maps (file-names (File. rendered-dir "ram-map"))
|
rlm@532
|
146 targets (map #(.getCanonicalPath
|
rlm@532
|
147 (File. final-frames (format "%07d.bmp" %)))
|
rlm@532
|
148 (range (count screenshots)))]
|
rlm@532
|
149 (dorun
|
rlm@532
|
150 (map
|
rlm@532
|
151 (comp
|
rlm@532
|
152 (partial apply clojure.java.shell/sh)
|
rlm@532
|
153 flatten
|
rlm@532
|
154 (partial apply composite-frames-command)
|
rlm@532
|
155 (fn [a b c d] (println c) [a b c d]))
|
rlm@532
|
156 screenshots ram-maps targets moves))))
|
rlm@531
|
157
|
rlm@532
|
158
|
rlm@532
|
159 (defn final-cut! [^File render-dir]
|
rlm@532
|
160 (let [movie (File. render-dir "final.ogg")
|
rlm@544
|
161 final-audio (File. render-dir "final.wav")
|
rlm@532
|
162 final (File. render-dir "final")]
|
rlm@532
|
163 (.delete movie)
|
rlm@532
|
164 (clojure.java.shell/sh
|
rlm@544
|
165 "sox" (.getCanonicalPath (File. render-dir "audio.wav"))
|
rlm@544
|
166 (.getCanonicalPath final-audio))
|
rlm@544
|
167 (clojure.java.shell/sh
|
rlm@543
|
168 "ffmpeg" "-r" "60" ;; maybe 59.7 ???!
|
rlm@532
|
169 "-i" (str (.getCanonicalPath final) "/" "%07d.bmp")
|
rlm@544
|
170 "-i" (.getCanonicalPath final-audio)
|
rlm@532
|
171 "-b:a" "128k"
|
rlm@532
|
172 "-b:v" "9000k"
|
rlm@532
|
173 "-c:a" "libvorbis"
|
rlm@532
|
174 "-c:v" "libtheora"
|
rlm@546
|
175 "-g" "200"
|
rlm@532
|
176 (.getCanonicalPath movie)) nil))
|
rlm@532
|
177
|
rlm@531
|
178
|
rlm@532
|
179 (comment
|
rlm@531
|
180
|
rlm@532
|
181 ;; step 1
|
rlm@532
|
182
|
rlm@532
|
183 (render-files!
|
rlm@532
|
184 render-dir (root)
|
rlm@532
|
185 (take 9000 (first (control-checkpoint))))
|
rlm@531
|
186
|
rlm@532
|
187 ;; step 2
|
rlm@532
|
188
|
rlm@532
|
189 (generate-composite-frames!
|
rlm@532
|
190 render-dir
|
rlm@532
|
191 (take 9000 (first (control-checkpoint))))
|
rlm@532
|
192
|
rlm@532
|
193 ;; step 3
|
rlm@532
|
194 (final-cut! render-dir)
|
rlm@532
|
195 ) |