#lang racket
(require ffi/unsafe
(for-syntax (only-in ffi/unsafe regexp-replaces))
ffi/unsafe/define
ffi/unsafe/alloc
ffi/vector
data/queue)
(provide (all-defined-out))
(define libopenal
(ffi-lib "libopenal"))
(define-ffi-definer define/native libopenal)
(define AL_INVALID -1)
(define AL_NONE 0)
(define AL_FALSE 0)
(define AL_TRUE 1)
(define AL_SOURCE_RELATIVE #x202)
(define AL_CONE_INNER_ANGLE #x1001)
(define AL_CONE_OUTER_ANGLE #x1002)
(define AL_PITCH #x1003)
(define AL_POSITION #x1004)
(define AL_DIRECTION #x1005)
(define AL_VELOCITY #x1006)
(define AL_LOOPING #x1007)
(define AL_BUFFER #x1009)
(define AL_GAIN #x100A)
(define AL_MIN_GAIN #x100D)
(define AL_MAX_GAIN #x100E)
(define AL_ORIENTATION #x100F)
(define AL_SOURCE_STATE #x1010)
(define AL_INITIAL #x1011)
(define AL_PLAYING #x1012)
(define AL_PAUSED #x1013)
(define AL_STOPPED #x1014)
(define AL_BUFFERS_QUEUED #x1015)
(define AL_BUFFERS_PROCESSED #x1016)
(define AL_SEC_OFFSET #x1024)
(define AL_SAMPLE_OFFSET #x1025)
(define AL_BYTE_OFFSET #x1026)
(define AL_SOURCE_TYPE #x1027)
(define AL_STATIC #x1028)
(define AL_STREAMING #x1029)
(define AL_UNDETERMINED #x1030)
(define AL_FORMAT_MONO8 #x1100)
(define AL_FORMAT_MONO16 #x1101)
(define AL_FORMAT_STEREO8 #x1102)
(define AL_FORMAT_STEREO16 #x1103)
(define AL_REFERENCE_DISTANCE #x1020)
(define AL_ROLLOFF_FACTOR #x1021)
(define AL_CONE_OUTER_GAIN #x1022)
(define AL_MAX_DISTANCE #x1023)
(define AL_FREQUENCY #x2001)
(define AL_BITS #x2002)
(define AL_CHANNELS #x2003)
(define AL_SIZE #x2004)
(define AL_UNUSED #x2010)
(define AL_PENDING #x2011)
(define AL_PROCESSED #x2012)
(define AL_NO_ERROR AL_FALSE)
(define AL_INVALID_NAME #xA001)
(define AL_INVALID_ENUM #xA002)
(define AL_INVALID_VALUE #xA003)
(define AL_INVALID_OPERATION #xA004)
(define AL_OUT_OF_MEMORY #xA005)
(define AL_VENDOR #xB001)
(define AL_VERSION #xB002)
(define AL_RENDERER #xB003)
(define AL_EXTENSIONS #xB004)
(define AL_DOPPLER_FACTOR #xC000)
(define AL_DOPPLER_VELOCITY #xC001)
(define AL_SPEED_OF_SOUND #xC003)
(define AL_DISTANCE_MODEL #xD000)
(define AL_INVERSE_DISTANCE #xD001)
(define AL_INVERSE_DISTANCE_CLAMPED #xD002)
(define AL_LINEAR_DISTANCE #xD003)
(define AL_LINEAR_DISTANCE_CLAMPED #xD004)
(define AL_EXPONENT_DISTANCE #xD005)
(define AL_EXPONENT_DISTANCE_CLAMPED #xD006)
(define AL_ILLEGAL_ENUM AL_INVALID_ENUM)
(define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION)
(define-syntax (define-prop-definer stx)
(syntax-case stx ()
[(_ base symbol pre-args ...)
(let ([get-template (format "~a-~~a" (cadr (syntax->datum stx)))]
[set-template (format "set-~a-~~a!"
(cadr (syntax->datum stx)))])
#`(define-syntax (symbol stx)
(syntax-case stx ()
[(_ basename
getter-name setter-name native-getter native-setter)
#`(begin (define (getter-name pre-args ...)
(native-getter pre-args ... basename))
(define (setter-name pre-args ... . args)
(apply native-setter pre-args ...
basename args)))]
[(_ basename native-getter native-setter)
(let ([name (string-downcase
(regexp-replaces (cadr (syntax->datum stx))
'(["^AL_" ""]
["_" "-"])))])
(with-syntax
([getter-name (datum->syntax
stx
(string->symbol
(format #,get-template name)))]
[setter-name (datum->syntax
stx
(string->symbol
(format #,set-template name)))])
#'(symbol basename getter-name setter-name
native-getter native-setter)))])))]))
(define/native open-device
(_fun [devicename : _string] -> _pointer)
#:c-id alcOpenDevice
)
(define/native create-context
(_fun [device : _pointer] [attrlist : _pointer = #f] -> _pointer)
#:c-id alcCreateContext
)
(define/native set-current-context
(_fun [context : _pointer] -> _bool)
#:c-id alcMakeContextCurrent
)
(define/native destroy-context!
(_fun [context : _pointer] -> _void)
#:c-id alcDestroyContext)
(define/native get-last-error
(_fun [device : _pointer] -> _int)
#:c-id alcGetError
)
(define/native gen-buffers
(_fun [num-buffers : _int]
[buffers : (_list o _int num-buffers)]
-> _void
-> buffers)
#:c-id alGenBuffers)
(define/native delete-buffers!
(_fun (buffers) ::
[num-buffers : _int = (length buffers)]
[buffers : (_list i _int)]
-> _void)
#:c-id alDeleteBuffers)
(define/native buffer?
(_fun [bufid : _int] -> _bool)
#:c-id alIsBuffer)
(define/native buffer-data
(_fun [bufid : _int]
[format : _int]
[data : _bytes]
[size : _int = (bytes-length data)]
[freq : _int] -> _void)
#:c-id alBufferData)
(define/native gen-sources
(_fun [num-sources : _int]
[sources : (_list o _int num-sources)]
-> _void
-> sources)
#:c-id alGenSources)
(define/native delete-sources!
(_fun (sources) ::
[num-sources : _int = (length sources)]
[sources : (_list i _int)]
-> _void)
#:c-id alDeleteSources)
(define/native alSourcef
(_fun [sid : _int]
[param : _int]
[value : _float] -> _void))
(define/native alSource3f
(_fun [sid : _int]
[param : _int]
[value1 : _float]
[value2 : _float]
[value3 : _float] -> _void))
(define/native alSourcefv
(_fun [sid : _int]
[param : _int]
[values : (_list i _float)] -> _void))
(define/native alSourcei
(_fun [sid : _int]
[param : _int]
[value : _int] -> _void))
(define/native alSource3i
(_fun [sid : _int]
[param : _int]
[value1 : _int]
[value2 : _int]
[value3 : _int] -> _void))
(define/native alSourceiv
(_fun [sid : _int]
[param : _int]
[values : (_list i _int)] -> _void))
(define/native alGetSourcef
(_fun [sid : _int]
[param : _int]
[value : (_ptr o _float)] -> _void -> value))
(define/native alGetSource3f
(_fun [sid : _int]
[param : _int]
[value1 : (_ptr o _float)]
[value2 : (_ptr o _float)]
[value3 : (_ptr o _float)]
-> _void
-> (list value1 value2 value3)))
(define/native alGetSourcefv
(_fun [sid : _int]
[param : _int]
[values : (_ptr o _pointer)] -> _void -> values)) (define/native alGetSourcei
(_fun [sid : _int]
[param : _int]
[value : (_ptr o _int)] -> _void -> value))
(define/native alGetSource3i
(_fun [sid : _int]
[param : _int]
[value1 : (_ptr o _int)]
[value2 : (_ptr o _int)]
[value3 : (_ptr o _int)]
-> _void
-> (list value1 value2 value3)))
(define/native alGetSourceiv
(_fun [sid : _int]
[param : _int]
[values : (_ptr o _pointer)] -> _void -> values))
(define-prop-definer "source" define-source-prop sid)
(define-source-prop AL_PITCH alGetSourcef alSourcef)
(define-source-prop AL_GAIN alGetSourcef alSourcef)
(define-source-prop AL_MAX_DISTANCE alGetSourcef alSourcef)
(define-source-prop AL_ROLLOFF_FACTOR alGetSourcef alSourcef)
(define-source-prop AL_REFERENCE_DISTANCE alGetSourcef alSourcef)
(define-source-prop AL_MIN_GAIN alGetSourcef alSourcef)
(define-source-prop AL_MAX_GAIN alGetSourcef alSourcef)
(define-source-prop AL_CONE_OUTER_GAIN alGetSourcef alSourcef)
(define-source-prop AL_CONE_INNER_ANGLE alGetSourcef alSourcef)
(define-source-prop AL_CONE_OUTER_ANGLE alGetSourcef alSourcef)
(define-source-prop AL_POSITION alGetSource3f alSource3f)
(define-source-prop AL_VELOCITY alGetSource3f alSource3f)
(define-source-prop AL_DIRECTION alGetSource3f alSource3f)
(define-source-prop AL_SOURCE_RELATIVE alGetSourcei alSourcei)
(define-source-prop AL_SOURCE_TYPE alGetSourcei alSourcei)
(define-source-prop AL_LOOPING alGetSourcei alSourcei)
(define-source-prop AL_BUFFER alGetSourcei alSourcei)
(define-source-prop AL_SOURCE_STATE alGetSourcei alSourcei)
(define-source-prop AL_BUFFERS_QUEUED alGetSourcei alSourcei)
(define-source-prop AL_BUFFERS_PROCESSED alGetSourcei alSourcei)
(define-source-prop AL_SEC_OFFSET alGetSourcef alSourcef)
(define-source-prop AL_SAMPLE_OFFSET alGetSourcei alSourcei)
(define-source-prop AL_BYTE_OFFSET alGetSourcei alSourcei)
(define/native alListenerf
(_fun [param : _int]
[value : _float] -> _void))
(define/native alListener3f
(_fun [param : _int]
[value1 : _float]
[value2 : _float]
[value3 : _float] -> _void))
(define/native alListenerfv
(_fun [param : _int]
[values : (_list i _float)] -> _void))
(define/native alListeneri
(_fun [param : _int]
[value : _int] -> _void))
(define/native alListener3i
(_fun [param : _int]
[value1 : _int]
[value2 : _int]
[value3 : _int] -> _void))
(define/native alListeneriv
(_fun [param : _int]
[values : (_list i _int)] -> _void))
(define/native alGetListenerf
(_fun [param : _int]
[value : (_ptr o _float)] -> _void -> value))
(define/native alGetListener3f
(_fun [param : _int]
[value1 : (_ptr o _float)]
[value2 : (_ptr o _float)]
[value3 : (_ptr o _float)]
-> _void
-> (list value1 value2 value3)))
(define/native alGetListenerfv
(_fun [param : _int]
[values : (_ptr o _pointer)] -> _void -> values)) (define/native alGetListeneri
(_fun [param : _int]
[value : (_ptr o _int)] -> _void -> value))
(define/native alGetListener3i
(_fun [param : _int]
[value1 : (_ptr o _int)]
[value2 : (_ptr o _int)]
[value3 : (_ptr o _int)]
-> _void
-> (list value1 value2 value3)))
(define/native alGetListeneriv
(_fun [param : _int]
[values : (_ptr o _pointer)] -> _void -> values))
(define-prop-definer "listener" define-listener-prop)
(define-listener-prop AL_GAIN alGetListenerf alListenerf)
(define-listener-prop AL_POSITION alGetListener3f alListener3f)
(define-listener-prop AL_VELOCITY alGetListener3f alListener3f)
(define-listener-prop AL_ORIENTATION alGetListener3f alListener3f)
(define/native alBufferf
(_fun [bid : _int]
[param : _int]
[value : _float] -> _void))
(define/native alBuffer3f
(_fun [bid : _int]
[param : _int]
[value1 : _float]
[value2 : _float]
[value3 : _float] -> _void))
(define/native alBufferfv
(_fun [bid : _int]
[param : _int]
[values : (_list i _float)] -> _void))
(define/native alBufferi
(_fun [bid : _int]
[param : _int]
[value : _int] -> _void))
(define/native alBuffer3i
(_fun [bid : _int]
[param : _int]
[value1 : _int]
[value2 : _int]
[value3 : _int] -> _void))
(define/native alBufferiv
(_fun [bid : _int]
[param : _int]
[values : (_list i _int)] -> _void))
(define/native alGetBufferf
(_fun [bid : _int]
[param : _int]
[value : (_ptr o _float)] -> _void -> value))
(define/native alGetBuffer3f
(_fun [bid : _int]
[param : _int]
[value1 : (_ptr o _float)]
[value2 : (_ptr o _float)]
[value3 : (_ptr o _float)]
-> _void
-> (list value1 value2 value3)))
(define/native alGetBufferfv
(_fun [bid : _int]
[param : _int]
[values : (_ptr o _pointer)] -> _void -> values)) (define/native alGetBufferi
(_fun [bid : _int]
[param : _int]
[value : (_ptr o _int)] -> _void -> value))
(define/native alGetBuffer3i
(_fun [bid : _int]
[param : _int]
[value1 : (_ptr o _int)]
[value2 : (_ptr o _int)]
[value3 : (_ptr o _int)]
-> _void
-> (list value1 value2 value3)))
(define/native alGetBufferiv
(_fun [bid : _int]
[param : _int]
[values : (_ptr o _pointer)] -> _void -> values))
(define-prop-definer "buffer" define-buffer-prop)
(define-buffer-prop AL_FREQUENCY alGetBufferi error)
(define-buffer-prop AL_BITS alGetBufferi error)
(define-buffer-prop AL_CHANNELS alGetBufferi error)
(define-buffer-prop AL_SIZE alGetBufferi error)
(define/native source-queue-buffers!
(_fun (sid buffers) ::
[sid : _int]
[numids : _int = (length buffers)]
[buffers : (_list i _int)] -> _void)
#:c-id alSourceQueueBuffers)
(define/native source-unqueue-buffers!
(_fun (sid buffers) ::
[sid : _int]
[numids : _int = (length buffers)]
[buffers : (_list i _int)] -> _void)
#:c-id alSourceUnqueueBuffers)
(define/native play-source
(_fun [sid : _int] -> _void)
#:c-id alSourcePlay)
(define/native rewind-source
(_fun [sid : _int] -> _void)
#:c-id alSourceRewind)
(define/native pause-source
(_fun [sid : _int] -> _void)
#:c-id alSourcePause)
(define/native stop-source
(_fun [sid : _int] -> _void)
#:c-id alSourceStop)
(define/native get-current-context
(_fun -> [context : _pointer])
#:c-id alcGetCurrentContext)
(define/native get-device-from-context
(_fun [context : _pointer] -> [device : _pointer])
#:c-id alcGetContextsDevice)
(define/native close-device!
(_fun [device : _pointer] -> _bool)
#:c-id alcCloseDevice)
(define/native set-distance-model!
(_fun [model : _int] -> _void)
#:c-id alDistanceModel)
(define/native set-doppler-factor!
(_fun [value : _float] -> _void)
#:c-id alDopplerFactor)
(define/native set-speed-of-sound!
(_fun [value : _float] -> _void)
#:c-id alSpeedOfSound)
(define (stream-port-to-source port source format frequency
[at-end-of-loop (λ() #f)]
[num-buffers 5]
[buffer-size (* 4096 8)]
[poll-interval 0.1]
[cleanup (λ()(void))])
(define buffer-queue (make-queue))
(for ([buffer (in-list (gen-buffers num-buffers))])
(buffer-data buffer format (read-bytes buffer-size port) frequency)
(source-queue-buffers! source (list buffer))
(enqueue! buffer-queue buffer))
(define t
(thread
(λ()
(let loop ()
(if (zero? (source-buffers-processed source))
(begin (sleep poll-interval)
(loop))
(begin
(let ([buffer (dequeue! buffer-queue)])
(source-unqueue-buffers! source (list buffer))
(let ([buf (read-bytes buffer-size port)])
(if (eof-object? buf)
(begin
(when (at-end-of-loop) (loop)))
(begin
(buffer-data buffer format buf frequency)
(source-queue-buffers! source (list buffer))
(enqueue! buffer-queue buffer)
(loop))))))))
(let loop ()
(unless (= (source-buffers-processed source)
(source-buffers-queued source))
(sleep poll-interval)
(loop))))))
(thread (λ()
(sync (thread-dead-evt t))
(source-unqueue-buffers! source (queue->list buffer-queue))
(delete-buffers! (queue->list buffer-queue))
(cleanup)))
t)