@ -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" )
( return ) )
( 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 @@
SDL_AUDIO_ALLOW_SAMPLES_CHANGE
SDL_AUDIO_ALLOW_CHANNELS_CHANGE ) ) )
( 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-print-error )
( 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 @@
( audio-input-buffer-initialize )
( 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"
converted-buffer-size-bytes
( 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 ) )
( break ) )
;; 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" )
( break ) ) )
( audio-dump-recorded-buffer )
( audio-dump-recorded-buffer "out.dat"
audio-input-buffer ( array-size audio-input-buffer ) )
( ogre-shutdown )
( sdl-audio-close output-device