#lang racket
(require (planet clements/portaudio:3:1)
(only-in ffi/unsafe cpointer? ptr-set! _sint16)
ffi/vector
racket/async-channel)
(define (nonnegative-real? n)
(and (real? n) (not (negative? n))))
(provide/contract (buffer-play (-> s16vector?
exact-integer?
(or/c false? exact-integer?)
nonnegative-real?
void?))
(buffer-loop (-> cpointer?
frames?
nonnegative-real?
void?))
[signal->signal/block/unsafe
(-> procedure? procedure?)]
[signal/16->signal/block/unsafe
(-> procedure? procedure?)]
[signal/block-play
(-> procedure? nonnegative-real?
(or/c nonnegative-real? false?)
(-> nonnegative-real?))]
[signal/block-play/unsafe (-> procedure? nonnegative-real? (or/c nonnegative-real? false?)
(-> nonnegative-real?))]
[stop-playing (-> void?)]
[channels exact-nonnegative-integer?])
(define channels 2)
(define (stop-playing)
(call-all-stop-thunks))
(define live-stream-channel (make-async-channel))
(define (call-all-stop-thunks)
(match (async-channel-try-get live-stream-channel)
[#f (void)]
[thunk (thunk)
(call-all-stop-thunks)]))
(define (buffer-play s16vec start finish sample-rate)
(define stop-sound (s16vec-play s16vec start finish sample-rate))
(async-channel-put
live-stream-channel
(lambda () (stop-sound))))
(define (signal/block-play block-filler sample-rate buffer-time)
(define actual-buffer-time (or buffer-time default-buffer-time))
(match-define (list stream-time stats stop-sound)
(stream-play block-filler actual-buffer-time sample-rate))
(async-channel-put
live-stream-channel
(lambda () (stop-sound)))
stream-time)
(define (signal/block-play/unsafe block-filler sample-rate buffer-time)
(define actual-buffer-time (or buffer-time default-buffer-time))
(match-define (list stream-time stats stop-sound)
(stream-play/unsafe block-filler actual-buffer-time sample-rate))
(async-channel-put
live-stream-channel
(lambda () (stop-sound)))
stream-time)
(define (signal->signal/block/unsafe sample-maker)
(define (signal/block/unsafe ptr frames)
(for ([frame (in-range 0 frames)])
(define sample (real->s16 (sample-maker)))
(define sample-num (* frame channels))
(ptr-set! ptr _sint16 sample-num sample)
(ptr-set! ptr _sint16 (add1 sample-num) sample)))
signal/block/unsafe)
(define (signal/16->signal/block/unsafe sample-maker)
(define (signal/block/unsafe ptr frames)
(for ([frame (in-range 0 frames)])
(define sample (sample-maker))
(define sample-num (* frame channels))
(ptr-set! ptr _sint16 sample-num sample)
(ptr-set! ptr _sint16 (add1 sample-num) sample)))
signal/block/unsafe)
(define default-buffer-time
(case (system-type)
[(windows) 0.06]
[(macosx unix) 0.05]))
(case (system-type)
[(windows) (host-api 'paWASAPI)]
[else #f])
(define s16max 32767)
(define -s16max (- s16max))
(define s16max/i (exact->inexact 32767))
(define (s16->real x)
(/ (exact->inexact x) s16max/i))
(define (real->s16 x)
(min s16max (max -s16max (inexact->exact (round (* s16max/i x))))))