@ -6,7 +6,7 @@
&comptime-only "Dependencies/cakelisp/runtime/Macros.cake")
;; TODO: Should this happen automatically, because import automatically adds current working dir?
;; Should it add working dir?
(add-c-search-directory ".")
(add-c-search-directory module ".")
(c-import "SDL.h" "SDL_syswm.h" "SDL_timer.h"
"<math.h>" "<stdio.h>" "<string.h>")
@ -15,7 +15,8 @@
;; These are read and written to from different threads (currently, without locking)
(var audio-is-recording bool false)
(var audio-input-buffer ([] 44100 Uint8) (array 0))
(var audio-input-buffer (* Uint8) null)
(var audio-input-buffer-size int 0)
(var audio-input-write-head int 0)
(var audio-input-read-head int 0)
@ -38,12 +39,19 @@
(fclose dest-file))
(defun-local audio-input-buffer-initialize ()
(set audio-input-buffer-size 44100)
(set audio-input-buffer (type-cast (calloc audio-input-buffer-size (sizeof Uint8))
(* Uint8)))
(var i int 0)
(while (< i (array-size audio-input-buffer))
(while (< i audio-input-buffer-size )
;; TODO: Use silence value from SDL audio spec
(set (at i audio-input-buffer) 127)
(incr i)))
(defun-local audio-input-buffer-destroy ()
(free audio-input-buffer)
(set audio-input-buffer null))
(defun-local audio-output-callback (userdata (* void) stream (* Uint8) stream-length int)
;; (printf "Audio len %d\n" stream-length)
(static-var up bool false)
@ -72,7 +80,7 @@
(set mono-sample 127) ;; Silence
(block ;; Else, play the recording
(var recording-index int (+ (/ i num-channels) audio-input-read-head))
(set recording-index (mod recording-index (array-size audio-input-buffer) ))
(set recording-index (mod recording-index audio-input-buffer-size ))
(set mono-sample (at recording-index audio-input-buffer))))
;; Channels are interleaved, e.g. LRLR, not LLRR
@ -84,7 +92,7 @@
(set i (+ i num-channels)))
(set audio-input-read-head
(mod (+ audio-input-read-head samples-per-channel)
(array-size audio-input-buffer) )))
audio-input-buffer-size )))
;; Note: If input is sampled at a different rate, playback will be at a lower pitch. Use SDL's
;; audio conversion functions to handle that properly
@ -98,7 +106,7 @@
(var i int 0)
(while (< i stream-length)
(set (at audio-input-write-head audio-input-buffer) (at i stream))
(if (= audio-input-write-head (- (array-size audio-input-buffer) 1))
(if (= audio-input-write-head (- audio-input-buffer-size 1))
(set audio-input-write-head 0)
(incr audio-input-write-head))
(incr i)))
@ -269,32 +277,56 @@
(when (>= output-device 2) (SDL_CloseAudioDevice output-device))
(when (>= input-device 2) (SDL_CloseAudioDevice input-device)))
(defun main (&return int)
(var window (* SDL_Window) null)
(unless (sdl-initialize (addr window))
(return 1))
(var g-window (* SDL_Window) null)
(var g-output-device SDL_AudioDeviceID 0)
(var g-input-device SDL_AudioDeviceID 0)
(var g-output-device-spec SDL_AudioSpec)
(var g-input-device-spec SDL_AudioSpec)
(audio-input-buffer-initialize)
(var output-device SDL_AudioDeviceID 0)
(var input-device SDL_AudioDeviceID 0)
(var output-device-spec SDL_AudioSpec)
(var input-device-spec SDL_AudioSpec)
(when enable-audio
(unless (initialize-audio (addr output-device) (addr input-device)
(addr output-device-spec) (addr input-device-spec))
(sdl-shutdown window)
(sdl-audio-close output-device input-device)
(return 1)))
(var monkey-mesh mesh-handle)
(var monkey-node scene-node)
(var reload-sentinel int 2)
;; TODO: Automatically make entry point
(defun reloadableEntryPoint (&return bool)
(var result int (app-main))
(cond ((= 0 result)
(return false))
((= 1 result)
(return false))
((= reload-sentinel result)
(return true)))
(return false))
(var initialized bool false)
(defun app-main (&return int)
(unless initialized
;; (defun main (&return int)
(unless (sdl-initialize (addr g-window))
(return 1))
;; Ogre uses exceptions for error handling, so we can't gracefully close without getting all that
;; stuff set up (which I don't really want to do; it belongs in Gamelib)
(unless (ogre-initialize-sdl)
(sdl-audio-close output-device
input-device)
(return 1))
(audio-input-buffer-initialize)
(var monkey-mesh mesh-handle (ogre-load-mesh "Suzanne.mesh"))
(var monkey-node scene-node (ogre-node-from-item monkey-mesh))
;; Ogre uses exceptions for error handling, so we can't gracefully close without getting all that
;; stuff set up (which I don't really want to do; it belongs in Gamelib)
(unless (ogre-initialize-sdl)
(return 1))
(set monkey-mesh (ogre-load-mesh "Suzanne.mesh"))
(set monkey-node (ogre-node-from-item monkey-mesh))
(set initialized true))
;; Audio needs to be re-initialized due to reload removing callbacks
;; TODO: Some way to avoid the big wait time required when initializing audio would be good
(when enable-audio
(unless (initialize-audio (addr g-output-device) (addr g-input-device)
(addr g-output-device-spec) (addr g-input-device-spec))
(sdl-shutdown g-window)
(sdl-audio-close g-output-device g-input-device)
(return 1)))
(var exit-reason (* (const char)) null)
@ -318,6 +350,15 @@
(when (at SDL_SCANCODE_ESCAPE currentKeyStates)
(set exit-reason "Escape pressed"))
(when (at SDL_SCANCODE_R currentKeyStates)
(printf "\nReloading\n\n")
;; Our audio callbacks are going away!
;; The SDL_QueueAudio() API would make this easier to deal with, but then I need to manage
;; an audio thread on my own
(sdl-audio-close g-output-device
g-input-device)
(return reload-sentinel))
(var delta-position ([] 3 float) (array 0))
(when (at SDL_SCANCODE_RIGHT currentKeyStates)
(set (at 0 delta-position) (+ (at 0 delta-position) move-speed)))
@ -339,14 +380,14 @@
(var audio-conversion-settings SDL_AudioCVT)
(SDL_BuildAudioCVT (addr audio-conversion-settings)
;; Src
(field input-device-spec format)
(field input-device-spec channels)
(field input-device-spec freq)
(field g- input-device-spec format)
(field g- input-device-spec channels)
(field g- input-device-spec freq)
;; Dest
(field output-device-spec format)
1 ;; (field output-device-spec channels) ;; We convert to stereo in playback callback
(field output-device-spec freq))
(set (field audio-conversion-settings len) (array-size audio-input-buffer) )
(field g- output-device-spec format)
1 ;; (field g- output-device-spec channels) ;; We convert to stereo in playback callback
(field g- output-device-spec freq))
(set (field audio-conversion-settings len) audio-input-buffer-size )
;; TODO: Does the buffer really nead to be 8x the src? Am I doing something wrong with my len?
;; Could be conversion to float then 2x that for resampling = 4x * 2x = 8x
(var converted-buffer-size-bytes int
@ -360,7 +401,7 @@
(type-cast (malloc converted-buffer-size-bytes) (* Uint8)))
(scope ;; Copy src to in-place conversion buffer
(var i int 0)
(while (< i (array-size audio-input-buffer) )
(while (< i audio-input-buffer-size )
(set (at i (field audio-conversion-settings buf)) (at i audio-input-buffer))
(incr i)))
(unless (= 0 (SDL_ConvertAudio (addr audio-conversion-settings)))
@ -376,7 +417,7 @@
(scope ;; Copy back to destination buffer. Note: this could drop samples, because it should
;; use the converted buffer size instead of the fixed array size!
(var i int 0)
(while (< i (array-size audio-input-buffer) )
(while (< i audio-input-buffer-size )
(set (at i audio-input-buffer)
(at i (type-cast (field audio-conversion-settings buf) (* Uint8))))
;; TODO: If my sample rate is higher when recorded, that means I need to record more
@ -384,7 +425,7 @@
;; enough samples at the lower playback rate, and start hitting buffer workspace.
;; Zero them out for now. I should record with enough samples to make it exactly fit
;; after conversion
(when (>= i (- (array-size audio-input-buffer) 3900))
(when (>= i (- audio-input-buffer-size 3900))
(set (at i audio-input-buffer) 127))
(incr i)))
(free (field audio-conversion-settings buf)))
@ -393,7 +434,7 @@
;; Note: peak in both low and high, never greater than range / 2
(var highest-peak Uint8 0)
(var i int 0)
(while (< i (array-size audio-input-buffer) )
(while (< i audio-input-buffer-size )
(var current-value int (- (type-cast (at i audio-input-buffer) int) 127))
(when (< highest-peak (abs current-value))
(set highest-peak (abs current-value)))
@ -411,7 +452,7 @@
(set scaling-factor scaling-limit))
(when scaling-factor
(set i 0)
(while (< i (array-size audio-input-buffer) )
(while (< i audio-input-buffer-size )
(var current-value int (- (type-cast (at i audio-input-buffer) int) 127))
(set (at i audio-input-buffer) (type-cast
;; Map back to 0-255
@ -429,7 +470,7 @@
;; Visualize audio playback
(var audio-read-head-to-world float (* 20.f
(/ audio-input-read-head
(type-cast (array-size audio-input-buffer) float))))
(type-cast audio-input-buffer-size float))))
(var audio-volume-to-world float (* 7.f
(/ (- (at audio-input-read-head audio-input-buffer) 127)
127.f)))
@ -448,12 +489,14 @@
(break)))
(audio-dump-recorded-buffer "out.dat"
audio-input-buffer (array-size audio-input-buffer) )
audio-input-buffer audio-input-buffer-size )
(ogre-shutdown)
(sdl-audio-close output-device
input-device)
(sdl-shutdown window)
(sdl-audio-close g-output-device
g-input-device)
(sdl-shutdown g-window)
(audio-input-buffer-destroy)
(when exit-reason
(printf "Exit reason: %s\n" exit-reason))