Browse Source

Ogre resources, audio resampling

* Ogre materials are now loading, though my Monkey material is
incompatible with Ogre 2
* Convert audio from recording format to playback format. This was
necessary because I record at 48kHz but playback is at
44.1kHz. Without this conversion, recorded audio would sound lower,
because it was being played at a slower rate
Macoy Madson 1 month ago
3 changed files with 100 additions and 19 deletions
  1. +16
  2. +1
  3. +83

+ 16
- 6
src/OgreInitialize.cake View File

@ -58,11 +58,11 @@
(defun-local registerHlms ()
(var resourcePath (in Ogre String) "data/")
(var cf (in Ogre ConfigFile))
(on-call cf load (+ resourcePath "resources2.cfg"))
(var config (in Ogre ConfigFile))
(on-call config load (+ resourcePath "resources2.cfg"))
(var rootHlmsFolder (in Ogre String)
(+ resourcePath (on-call cf getSetting "DoNotUseAsResource" "Hlms" "")))
(+ resourcePath (on-call config getSetting "DoNotUseAsResource" "Hlms" "")))
(cond ((on-call rootHlmsFolder empty)
(set rootHlmsFolder "./"))
@ -224,10 +224,20 @@
(on-call-ptr compositorManager addWorkspace
g_sceneManager (on-call-ptr g_window getTexture) camera workspaceName true)
(on-call (call (in Ogre ResourceGroupManager getSingleton)) addResourceLocation
(var resource-group-manager (& (in Ogre ResourceGroupManager))
(call (in Ogre ResourceGroupManager getSingleton)))
(on-call resource-group-manager addResourceLocation
"data/Models" "FileSystem" "Models")
(on-call (call (in Ogre ResourceGroupManager getSingleton)) addResourceLocation
"data/Materials" "FileSystem" "Materials")
(scope ;; Materials
;; I had to read before figuring out
;; groups needed to be initialized and loaded in order to work (at least, materials do)
(on-call resource-group-manager createResourceGroup "Materials")
(on-call resource-group-manager addResourceLocation
"data/Materials" "FileSystem" "Materials")
(on-call resource-group-manager initialiseResourceGroup "Materials"
true) ;; changeLocaleTemporarily: See comment above initialiseResourceGroup
(on-call resource-group-manager loadResourceGroup "Materials"))
;; (call (in Ogre WindowEventUtilities addWindowEventListener)
;; g_window (addr g_myWindowEventListener))

+ 1
- 1
test/AudioPlot.gnuplot View File

@ -38,7 +38,7 @@ set key textcolor rgb text_color
set object rectangle from screen 0,0 to screen 1,1 behind fillcolor rgb background_color fillstyle solid noborder
set yrange [0:255]
plot 'out.dat' with lines
plot 'out.dat' with lines, 'converted.dat' with lines
# Let the user interact with it, e.g. right click drag to zoom in
pause mouse close

+ 83
- 12
test/src/VocalGame.cake View File

@ -19,17 +19,21 @@
(var audio-input-write-head int 0)
(var audio-input-read-head int 0)
;; (var enable-audio bool false)
(var enable-audio bool true)
;; Outputs to a format that can be plotted with gnuplot:
;; gnuplot> plot 'out.dat' with lines
(defun-local audio-dump-recorded-buffer ()
(var dest-file (* FILE) (fopen "out.dat" "w"))
(defun-local audio-dump-recorded-buffer (output-filename (* (const char))
buffer (* Uint8) buffer-size int)
(var dest-file (* FILE) (fopen output-filename "w"))
(unless dest-file
(printf "Could not open file to write data\n")
(var i int 0)
(while (< i (array-size audio-input-buffer))
(fprintf dest-file "%d %d\n" i (at i audio-input-buffer))
(while (< i buffer-size)
(fprintf dest-file "%d %d\n" i (at i buffer))
(incr i))
(fclose dest-file))
@ -128,7 +132,10 @@
(free device-names))
(defun-local initialize-audio (output-device-out (* SDL_AudioDeviceID)
input-device-out (* SDL_AudioDeviceID) &return bool)
input-device-out (* SDL_AudioDeviceID)
output-device-spec-out (* SDL_AudioSpec)
input-device-spec-out (* SDL_AudioSpec)
&return bool)
(var audio-driver (* (const char)) (SDL_GetCurrentAudioDriver))
(scope ;; Drivers
(printf "Available drivers:\n")
@ -185,7 +192,8 @@
(if (>= output-device-id valid-device-start-num)
(set selected-output-device device-name)
(block (set selected-output-device device-name)
(set (deref output-device-spec-out) obtained-output-spec))
(block (sdl-print-error)
(sdl-audio-free-device-list devices num-devices)
(return false))))
@ -224,6 +232,7 @@
(sdl-audio-free-device-list capture-devices num-capture-devices)
(return false))
(set (deref input-device-spec-out) obtained-input-spec)
(set selected-input-device device-name)
(when selected-input-device ;; print final settings
@ -265,10 +274,14 @@
(var output-device SDL_AudioDeviceID 0)
(var input-device SDL_AudioDeviceID 0)
(unless (initialize-audio (addr output-device) (addr input-device))
(sdl-shutdown window)
(sdl-audio-close output-device input-device)
(return 1))
(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)))
;; 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)
@ -316,6 +329,63 @@
(set audio-is-recording (at SDL_SCANCODE_SPACE currentKeyStates))
(when (and (!= prev-recording-value audio-is-recording)
(not audio-is-recording))
(scope ;; Convert audio to playback format.
;; This was necessary in my case because my microphone records at 48kHz, but my sound card
;; expects 44.1kHz output
;; Audio Streams are worth looking at in the future, so it's not all one big batch process
(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)
;; 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))
;; 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
(* (field audio-conversion-settings len)
(field audio-conversion-settings len_mult)))
(printf "Converted buffer size: %d bytes because %d len %d len_mult\n"
(field audio-conversion-settings len)
(field audio-conversion-settings len_mult))
(set (field audio-conversion-settings buf)
(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))
(set (at i (field audio-conversion-settings buf)) (at i audio-input-buffer))
(incr i)))
(unless (= 0 (SDL_ConvertAudio (addr audio-conversion-settings)))
(set exit-reason "Failed to convert audio")
(free (field audio-conversion-settings buf))
;; TODO: This shouldn't be byte size, it should be sample count, to support other formats
(audio-dump-recorded-buffer "converted.dat"
(field audio-conversion-settings buf)
;; Remove the extra buffer used by the converter
(/ converted-buffer-size-bytes
(field audio-conversion-settings len_mult)))
(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))
(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
;; samples and play back fewer. Because I use the same buffer, it means I don't have
;; 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))
(set (at i audio-input-buffer) 127))
(incr i)))
(free (field audio-conversion-settings buf)))
;; Normalize audio
;; Note: peak in both low and high, never greater than range / 2
(var highest-peak Uint8 0)
@ -326,7 +396,7 @@
(set highest-peak (abs current-value)))
(incr i))
(when highest-peak
;; Get within 90% of the peak, to avoid clipping
;; Get within 90% of the max, to avoid clipping
(var desired-high-peak (const int) (* (/ 256 2) 0.9f))
(var scaling-factor float (/ desired-high-peak (type-cast highest-peak float)))
(printf "Scaling recording %.4f because desired = %d and highest was %d\n"
@ -374,7 +444,8 @@
(set exit-reason "Failed to render frame")
(audio-dump-recorded-buffer "out.dat"
audio-input-buffer (array-size audio-input-buffer))
(sdl-audio-close output-device