#lang racket/base
(require ffi/vector
ffi/unsafe
(rename-in racket/contract [-> c->])
racket/runtime-path
"portaudio.rkt"
(only-in racket/match match-define))
(define-runtime-path lib "lib/")
(define (frames? n)
(and (exact-integer? n)
(<= 0 n)))
(define nat? exact-nonnegative-integer?)
(define false? not)
(provide/contract
[make-copying-info (c-> s16vector? nat? (or/c false? nat?) cpointer?)]
[copying-callback cpointer?]
[copying-info-free cpointer?]
[make-streaming-info (c-> integer? (list/c cpointer? cpointer?))]
[all-done? (c-> cpointer? boolean?)]
[call-buffer-filler (c-> cpointer? procedure? any)]
[streaming-callback cpointer?]
[stream-fails (c-> cpointer? integer?)]
[streaming-info-free cpointer?])
(provide stream-rec-buffer
stream-rec-buffer-frames
stream-rec-last-frame-read
set-stream-rec-last-frame-written!
set-stream-rec-last-offset-written!
)
(define channels 2)
(define s16max 32767)
(define sample-bytes (ctype-sizeof _sint16))
(define (frames->bytes f) (* channels sample-bytes f))
(define (bytes->frames b) (/ b (* channels sample-bytes)))
(define-cstruct _copying-rec
([sound _pointer]
[cur-sample _ulong]
[num-samples _ulong]))
(define (make-copying-info s16vec start-frame maybe-stop-frame)
(define stop-frame (or maybe-stop-frame
(/ (s16vector-length s16vec) channels)))
(define frames-to-copy (- stop-frame start-frame))
(define copied-sound (dll-malloc (frames->bytes frames-to-copy)))
(define src-ptr (ptr-add (s16vector->cpointer s16vec)
(frames->bytes start-frame)))
(memcpy copied-sound src-ptr (frames->bytes frames-to-copy))
(define copying-info (cast (dll-malloc (ctype-sizeof _copying-rec))
_pointer
_copying-rec-pointer))
(set-copying-rec-sound! copying-info copied-sound)
(set-copying-rec-cur-sample! copying-info 0)
(set-copying-rec-num-samples! copying-info (* frames-to-copy channels))
copying-info)
(define-cstruct _stream-rec
( [buffer-frames _int]
[buffer _pointer]
[last-frame-read _uint]
[last-offset-read _uint]
[last-frame-written _uint]
[last-offset-written _uint]
[fault-count _int]
[all-done _pointer]))
(define (stream-fails stream-rec)
(stream-rec-fault-count stream-rec))
(define (make-streaming-info buffer-frames)
(define info (cast (dll-malloc (ctype-sizeof _stream-rec))
_pointer
_stream-rec-pointer))
(set-stream-rec-buffer-frames! info buffer-frames)
(set-stream-rec-buffer! info (dll-malloc (frames->bytes buffer-frames)))
(set-stream-rec-last-frame-read! info 0)
(set-stream-rec-last-offset-read! info 0)
(set-stream-rec-last-frame-written! info 0)
(set-stream-rec-last-offset-written! info 0)
(set-stream-rec-fault-count! info 0)
(define all-done-cell (malloc 'raw 4))
(ptr-set! all-done-cell _uint32 0)
(set-stream-rec-all-done! info all-done-cell)
(list info all-done-cell))
(define (all-done? all-done-ptr)
(not (= (ptr-ref all-done-ptr _uint32) 0)))
(define (call-buffer-filler stream-info filler)
(define buffer (stream-rec-buffer stream-info))
(define buffer-frames (stream-rec-buffer-frames stream-info))
(define buffer-bytes (frames->bytes buffer-frames))
(define last-frame-read (stream-rec-last-frame-read stream-info))
(define last-offset-read (stream-rec-last-offset-read stream-info))
(define last-frame-to-write (+ last-frame-read buffer-frames))
(define last-offset-to-write last-offset-read)
(define last-frame-written (stream-rec-last-frame-written stream-info))
(define last-offset-written (stream-rec-last-offset-written stream-info))
(define underflow? (< last-frame-written last-frame-read))
(define first-frame-to-write (cond [underflow? last-frame-read]
[else last-frame-written]))
(define first-offset-to-write (cond [underflow? last-offset-read]
[else last-offset-written]))
(unless (= first-frame-to-write last-frame-to-write)
(cond [(<= last-offset-to-write first-offset-to-write)
(define frames-to-end
(bytes->frames (- buffer-bytes first-offset-to-write)))
(filler (ptr-add buffer first-offset-to-write)
frames-to-end
first-frame-to-write)
(filler buffer
(bytes->frames last-offset-to-write)
(+ first-frame-to-write frames-to-end))]
[else
(filler (ptr-add buffer first-offset-to-write)
(- last-frame-to-write first-frame-to-write)
first-frame-to-write)])
(set-stream-rec-last-frame-written! stream-info last-frame-to-write)
(set-stream-rec-last-offset-written! stream-info last-offset-to-write)))
(define callbacks-lib (ffi-lib (build-path lib
(system-library-subpath)
"callbacks")))
(define-cstruct _bogus-struct
([datum _uint16]))
(define copying-callback
(cast
(get-ffi-obj "copyingCallback" callbacks-lib _bogus-struct)
_bogus-struct-pointer
_pa-stream-callback))
(define streaming-callback
(cast
(get-ffi-obj "streamingCallback" callbacks-lib _bogus-struct)
_bogus-struct-pointer
_pa-stream-callback))
(define copying-info-free
(cast
(get-ffi-obj "freeCopyingInfo" callbacks-lib _bogus-struct)
_bogus-struct-pointer
_pa-stream-finished-callback))
(define streaming-info-free
(cast
(get-ffi-obj "freeStreamingInfo" callbacks-lib _bogus-struct)
_bogus-struct-pointer
_pa-stream-finished-callback))
(define dll-malloc
(get-ffi-obj "dll_malloc" callbacks-lib (_fun _uint -> _pointer)))