Browse Source
* Update Cakelisp for parentheses around deref and addr, resolving ambiguities * Added audio output to VocalGame. I had a few false starts due to not having my good device selected as default. The current version won't work on any other machine because I hard-coded the audio devicepitch-detection
5 changed files with 250 additions and 8 deletions
@ -1 +1 @@ |
|||
Subproject commit 4bacdedb037aee9f23bef9029746f2b045e159cf |
|||
Subproject commit 1dba3db6cc71a9efce8ee4328f4f31a557ca03c0 |
@ -0,0 +1,238 @@ |
|||
(set-cakelisp-option cakelisp-src-dir "Dependencies/cakelisp/src") |
|||
(set-cakelisp-option executable-output "test/VocalGame") |
|||
|
|||
(import "src/OgreCore.cake" |
|||
"src/SDL.cake") |
|||
;; TODO: Should this happen automatically, because import automatically adds current working dir? |
|||
;; Should it add working dir? |
|||
(add-c-search-directory ".") |
|||
|
|||
(c-import "SDL.h" "SDL_syswm.h" "SDL_timer.h" |
|||
"<math.h>") |
|||
;; TODO: Somehow inherit this from SDL.cake? |
|||
(module-use-sdl-build-options) |
|||
|
|||
(defun-local audio-callback (userdata (* void) stream (* Uint8) stream-length int) |
|||
;; (printf "Audio len %d\n" stream-length) |
|||
(static-var up bool false) |
|||
(set up (not up)) |
|||
(var i int 0) |
|||
(var pi (const float) 3.14159f) |
|||
(var num-channels int 2) |
|||
(var samples-per-channel int (/ stream-length num-channels)) |
|||
(while (< i stream-length) |
|||
(var mono-sample int 0) |
|||
;; Square |
|||
;; (set mono-sample (? up 255 0)) |
|||
;; Triangle |
|||
;; (set mono-sample (mod (/ i 4) 255)) |
|||
;; Sine |
|||
;; Map to 0-255 |
|||
(set mono-sample (+ 127 (* 127 |
|||
;; Map to -1 to +1 |
|||
(sin |
|||
;; Map from position in buffer to 2pi range |
|||
(/ (* i 2 pi) (type-cast samples-per-channel float)))))) |
|||
|
|||
;; Channels are interleaved, e.g. LRLR, not LLRR |
|||
(var channel int 0) |
|||
(while (< channel num-channels) |
|||
(set (at (+ i channel) stream) mono-sample) |
|||
;; (printf "[%d][%d] %d\n" (+ i channel) channel (at i stream)) |
|||
(incr channel)) |
|||
(set i (+ i num-channels)))) |
|||
|
|||
;; Allocates both names and array |
|||
;; Returns number of devices in device-names-out |
|||
(defun-local sdl-audio-get-devices (device-names-out (* (* (* (const char)))) |
|||
is-capture bool &return int) |
|||
(var num-devices int (SDL_GetNumAudioDevices is-capture)) |
|||
(set (deref device-names-out) (type-cast |
|||
(calloc (sizeof (type (* (const char)))) num-devices) |
|||
(* (* (const char))))) |
|||
(printf "Available %s devices:\n" (? is-capture "recording" "playback")) |
|||
(var i int 0) |
|||
(while (< i num-devices) |
|||
(var device-name (* (const char)) (SDL_GetAudioDeviceName i is-capture)) |
|||
(when device-name |
|||
(printf "\t[%d] %s\n" i device-name) |
|||
(set (at i (deref device-names-out)) (strdup device-name))) |
|||
(incr i)) |
|||
(return num-devices)) |
|||
|
|||
(defun-local sdl-audio-free-device-list (device-names (* (* (const char))) num-devices int) |
|||
(var i int 0) |
|||
(while (< i num-devices) |
|||
(free (type-cast (at i device-names) (* void))) |
|||
(incr i)) |
|||
(free device-names)) |
|||
|
|||
(defun-local initialize-audio (&return bool) |
|||
(scope ;; Drivers |
|||
(printf "Available drivers:\n") |
|||
(var num-drivers int (SDL_GetNumAudioDrivers)) |
|||
(var i int 0) |
|||
(while (< i num-drivers) |
|||
(var driver-name (* (const char)) (SDL_GetAudioDriver i)) |
|||
(when driver-name |
|||
(printf "\t[%d] %s\n" i driver-name)) |
|||
(incr i)) |
|||
(var audio-driver (* (const char)) (SDL_GetCurrentAudioDriver)) |
|||
(unless audio-driver |
|||
(printf "No audio driver found") |
|||
(return false)) |
|||
(printf "Active audio driver: %s\n" audio-driver)) |
|||
|
|||
(var is-capture bool false) |
|||
|
|||
(var devices (* (* (const char))) null) |
|||
(var num-devices int (sdl-audio-get-devices (addr devices) is-capture)) |
|||
(unless num-devices (return false)) |
|||
|
|||
(scope ;; Capture devices |
|||
(var capture-devices (* (* (const char))) null) |
|||
(var num-capture-devices int (sdl-audio-get-devices (addr capture-devices) true)) |
|||
(unless num-capture-devices (return false)) |
|||
(sdl-audio-free-device-list capture-devices num-capture-devices)) |
|||
|
|||
(var desired-spec SDL_AudioSpec (array 0)) |
|||
(set (field desired-spec freq) 44100) |
|||
(set (field desired-spec format) AUDIO_U8) |
|||
(set (field desired-spec channels) 2) ;; 1 = Mono 2 = Stereo |
|||
;; 86 times per second. ~11ms delay (I think) |
|||
(set (field desired-spec samples) 512) |
|||
(set (field desired-spec callback) audio-callback) |
|||
|
|||
(var selected-device (* (const char)) nullptr) |
|||
(var internal-device-id SDL_AudioDeviceID 0) |
|||
(var obtained-spec SDL_AudioSpec (array 0)) |
|||
(scope |
|||
;; Use my HDMI output device |
|||
(var macoy-device int 2) |
|||
(unless (< macoy-device num-devices) |
|||
(sdl-audio-free-device-list devices num-devices) |
|||
(return false)) |
|||
|
|||
(var device-name (* (const char)) (at 2 devices)) |
|||
(var valid-device-start-num (const int) 2) |
|||
(set internal-device-id (SDL_OpenAudioDevice |
|||
;; null = reasonable default (doesn't work in my case) |
|||
;; null |
|||
device-name |
|||
false ;; iscapture |
|||
(addr desired-spec) (addr obtained-spec) |
|||
(bit-or SDL_AUDIO_ALLOW_FREQUENCY_CHANGE |
|||
SDL_AUDIO_ALLOW_SAMPLES_CHANGE |
|||
SDL_AUDIO_ALLOW_CHANNELS_CHANGE))) |
|||
(if (<= internal-device-id valid-device-start-num) |
|||
(set selected-device device-name) |
|||
(sdl-print-error))) |
|||
|
|||
;; Pick the first working device |
|||
;; This doesn't actually make sense for my case, where the first device does open |
|||
;; (var i int 0) |
|||
;; (while (< i num-devices) |
|||
;; (var device-name (* (const char)) (at i devices)) |
|||
;; (var valid-device-start-num (const int) 2) |
|||
;; (set internal-device-id (SDL_OpenAudioDevice |
|||
;; ;; null = reasonable default (doesn't work in my case) |
|||
;; device-name |
|||
;; false ;; iscapture |
|||
;; (addr desired-spec) (addr obtained-spec) |
|||
;; (bit-or SDL_AUDIO_ALLOW_FREQUENCY_CHANGE |
|||
;; SDL_AUDIO_ALLOW_SAMPLES_CHANGE |
|||
;; SDL_AUDIO_ALLOW_CHANNELS_CHANGE))) |
|||
;; (if (>= internal-device-id |
|||
;; valid-device-start-num) |
|||
;; (block |
|||
;; (set selected-device device-name) |
|||
;; (break)) |
|||
;; (block |
|||
;; (sdl-print-error) |
|||
;; (incr i)))) |
|||
|
|||
(when selected-device ;; print final settings |
|||
(printf "Final settings:\n") |
|||
(printf "device: %s\n" selected-device) |
|||
(printf "freq: %d\n" (field obtained-spec freq)) |
|||
(printf "format: %d\n" (field obtained-spec format)) |
|||
(printf "channels: %d\n" (field obtained-spec channels)) |
|||
(printf "samples: %d\n" (field obtained-spec samples)) |
|||
;; Start playing |
|||
;; Important note: SDL_PauseAudio works on the default device, NOT the opened one |
|||
;; This tripped me up when my audio wasn't actually getting played on my opened one |
|||
(SDL_PauseAudioDevice internal-device-id 0)) |
|||
|
|||
(sdl-audio-free-device-list devices num-devices) |
|||
(return selected-device)) |
|||
|
|||
(defun main (&return int) |
|||
(var window (* SDL_Window) null) |
|||
(unless (sdl-initialize (addr window)) |
|||
(return 1)) |
|||
|
|||
(unless (initialize-audio) |
|||
(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) |
|||
(return 1)) |
|||
|
|||
(var monkey-mesh mesh-handle (ogre-load-mesh "Suzanne.mesh")) |
|||
(var monkey-node scene-node (ogre-node-from-item monkey-mesh)) |
|||
|
|||
(var exit-reason (* (const char)) null) |
|||
|
|||
(var x float 0.f) |
|||
(var y float 0.f) |
|||
(var z float 0.f) |
|||
(var move-speed float 10.f) |
|||
|
|||
(var counter-num-ticks-per-second (const Uint64) (SDL_GetPerformanceFrequency)) |
|||
(var last-frame-perf-count Uint64 (* 0.016f counter-num-ticks-per-second)) |
|||
|
|||
;; Main loop |
|||
(while (not exit-reason) |
|||
(var event SDL_Event) |
|||
(while (SDL_PollEvent (addr event)) |
|||
(when (= (field event type) SDL_QUIT) |
|||
(set exit-reason "Window closed"))) |
|||
|
|||
;; Note: this requires SDL_PollEvent in order to be up-to-date |
|||
(var currentKeyStates (* (const Uint8)) (SDL_GetKeyboardState null)) |
|||
(when (at SDL_SCANCODE_ESCAPE currentKeyStates) |
|||
(set exit-reason "Escape pressed")) |
|||
|
|||
(var delta-position ([] 3 float) (array 0)) |
|||
(when (at SDL_SCANCODE_RIGHT currentKeyStates) |
|||
(set (at 0 delta-position) (+ (at 0 delta-position) move-speed))) |
|||
(when (at SDL_SCANCODE_LEFT currentKeyStates) |
|||
(set (at 0 delta-position) (- (at 0 delta-position) move-speed))) |
|||
(when (at SDL_SCANCODE_UP currentKeyStates) |
|||
(set (at 1 delta-position) (+ (at 1 delta-position) move-speed))) |
|||
(when (at SDL_SCANCODE_DOWN currentKeyStates) |
|||
(set (at 1 delta-position) (- (at 1 delta-position) move-speed))) |
|||
|
|||
(var current-counter-ticks Uint64 (SDL_GetPerformanceCounter)) |
|||
(var frame-diff-ticks Uint64 (- current-counter-ticks last-frame-perf-count)) |
|||
(var delta-time float (/ frame-diff-ticks |
|||
(type-cast counter-num-ticks-per-second float))) |
|||
;; (printf "%lu %f\n" frame-diff-ticks delta-time) |
|||
|
|||
(set x (+ x (* delta-time (at 0 delta-position)))) |
|||
(set y (+ y (* delta-time (at 1 delta-position)))) |
|||
(set z (+ z (* delta-time (at 2 delta-position)))) |
|||
(ogre-node-set-position (addr monkey-node) x y z) |
|||
|
|||
(set last-frame-perf-count (SDL_GetPerformanceCounter)) |
|||
|
|||
(unless (ogre-render-frame) |
|||
(set exit-reason "Failed to render frame") |
|||
(break))) |
|||
|
|||
(ogre-shutdown) |
|||
(sdl-shutdown window) |
|||
(when exit-reason |
|||
(printf "Exit reason: %s\n" exit-reason)) |
|||
(return 0)) |
Loading…
Reference in new issue