#lang racket
(require "rsound.rkt"
"util.rkt"
data/heap
ffi/unsafe
ffi/vector
"private/s16vector-add.rkt"
rackunit)
(provide (all-defined-out))
(define s16-size 2)
(define (rsound-play-at-intervals rsound interval)
(define rsound-len (rsound-frames rsound))
(define the-signal
(lambda (t)
(define t-rel (modulo t interval))
(cond [(< t-rel (rsound-frames rsound)) (rsound-ith/left rsound t-rel)]
[else 0])))
(signal-play the-signal (rsound-sample-rate rsound)))
(signal-play (sine-wave 440 44100) 4100)
(rsound-play-at-intervals ding 4100)
(struct entry (sound start finish) #:transparent)
(define (make-unplayed-heap)
(make-heap (lambda (a b)
(<= (entry-start a) (entry-start b)))))
(define (queue-for-playing! heap sound start)
(heap-add! heap (entry sound start (+ start (rsound-frames sound)))))
(define (heap->signal/block unplayed)
(define playing (make-heap (lambda (a b) (<= (entry-finish a) (entry-finish b)))))
(define playing-vec (vector))
(define last-t #f)
(define (get-last-t) last-t)
(define (signal/block cpointer t len)
(set! last-t (+ t len))
(define sounds-removed? (clear-ended-sounds playing t))
(define sounds-added? (add-new-sounds unplayed playing (+ t len)))
(when (or sounds-removed? sounds-added?)
(set! playing-vec (heap->vector playing)))
(combine-onto! cpointer t len playing-vec))
(values
signal/block
get-last-t))
(define (combine-onto! cpointer t len playing-vec)
(memset cpointer 0 (* channels s16-size len))
(for ([e (in-vector playing-vec)])
(add-from-buf! cpointer t len e)))
(define (add-from-buf! cpointer t len e)
(match-define (entry sound start finish) e)
(define copy-start (max t start))
(define copy-finish (min (+ t len) finish))
(define copy-len (- copy-finish copy-start))
(define copy-len-samples (* copy-len channels))
(define src-start (- copy-start start))
(define src-start-ptr (ptr-add (s16vector->cpointer (rsound-data sound))
(* channels src-start)
_sint16))
(define tgt-start (- copy-start t))
(define tgt-start-ptr (ptr-add cpointer
(* channels tgt-start)
_sint16))
(s16buffer-add!/c tgt-start-ptr
src-start-ptr
copy-len-samples))
(define (clear-ended-sounds playing-heap current-time)
(let loop ([removed? #f])
(cond [(= (heap-count playing-heap) 0) removed?]
[else
(define earliest-ending (heap-min playing-heap))
(cond [(<= (entry-finish earliest-ending) current-time)
(heap-remove-min! playing-heap)
(loop #t)]
[else removed?])])))
(define (add-new-sounds queued-heap playing-heap current-time)
(let loop ([added? #f])
(cond [(= (heap-count queued-heap) 0) added?]
[else
(define earliest-to-play (heap-min queued-heap))
(cond [(<= (entry-start earliest-to-play) current-time)
(heap-add! playing-heap earliest-to-play)
(heap-remove-min! queued-heap)
(loop #t)]
[else added?])])))
(let ()
(define tgt (make-s16vector (* channels 10) 15))
(define src1 (rsound (make-s16vector (* channels 200) 1) 200 44100))
(define entry1 (entry src1 50 250))
(define entry2 (entry src1 65 265))
(combine-onto! (s16vector->cpointer tgt)
60
10
(vector entry1 entry2))
(check-equal? (s16vector->list tgt)
(list 1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2)))
(let ()
(define h (make-unplayed-heap))
(queue-for-playing! h (clip ding 0 10000) 20000)
(queue-for-playing! h ding 18000)
(check-equal? (heap-count h) 2)
(check-equal? (heap-min h) (entry ding 18000 (+ 18000 44100)))
(heap-remove-min! h)
(check rsound-equal?
(entry-sound (heap-min h))
(clip ding 0 10000))
(check-equal? (entry-start (heap-min h)) 20000)
(check-equal? (entry-finish (heap-min h)) 30000))
(let ()
(define playing-heap (make-heap (lambda (a b)
(<= (entry-finish a) (entry-finish b)))))
(heap-add-all! playing-heap (list (entry 'a 14 29)
(entry 'b 16 21)
(entry 'c 5 25)
(entry 'd 3 25)))
(check-equal? (heap-count playing-heap) 4)
(check-equal? (heap-min playing-heap) (entry 'b 16 21))
(check-equal? (clear-ended-sounds playing-heap 22) #t)
(check-equal? (heap-count playing-heap) 3)
(check-equal? (clear-ended-sounds playing-heap 25) #t)
(check-equal? (heap-count playing-heap) 1)
(check-equal? (clear-ended-sounds playing-heap 30) #t)
(check-equal? (heap-count playing-heap) 0)
(check-equal? (clear-ended-sounds playing-heap 40) #f))
(let ()
(define queued-heap (make-unplayed-heap))
(heap-add-all! queued-heap (list (entry 'a 14 29)
(entry 'b 16 21)
(entry 'c 5 25)
(entry 'd 3 25)))
(define playing-heap (make-heap
(lambda (a b)
(<= (entry-finish a) (entry-finish b)))))
(check-equal? (heap-count queued-heap) 4)
(check-equal? (heap-min queued-heap) (entry 'd 3 25))
(check-equal? (add-new-sounds queued-heap playing-heap 0) #f)
(check-equal? (heap-count queued-heap) 4)
(check-equal? (heap-count playing-heap) 0)
(check-equal? (add-new-sounds queued-heap playing-heap 3) #t)
(check-equal? (heap-count queued-heap) 3)
(check-equal? (heap-count playing-heap) 1)
(check-equal? (add-new-sounds queued-heap playing-heap 5) #t)
(check-equal? (heap-count queued-heap) 2)
(check-equal? (heap-count playing-heap) 2)
(check-equal? (add-new-sounds queued-heap playing-heap 16) #t)
(check-equal? (heap-count queued-heap) 0)
(check-equal? (heap-count playing-heap) 4)
(check-equal? (add-new-sounds queued-heap playing-heap 20) #f))
(let ()
(define src1 (rsound (make-s16vector (* channels 200) 1) 200 44100))
(define entry1 (entry src1 50 250))
(define entry2 (entry src1 65 265))
(define dst1 (make-s16vector (* channels 10) 0))
(check-equal? (s16vector->list dst1) (list 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0))
(add-from-buf! (s16vector->cpointer dst1) 45 10 entry1)
(check-equal? (s16vector->list dst1) (list 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1))
(define dst2 (make-s16vector 20 0))
(add-from-buf! (s16vector->cpointer dst2) 60 10 entry1)
(add-from-buf! (s16vector->cpointer dst2) 60 10 entry2)
(check-equal? (s16vector->list dst2) (list 1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2))
(define dst3 (make-s16vector 20 0))
(define src3 (rsound (make-s16vector 10 2) 5 44100))
(define entry3 (entry src3 70 75))
(add-from-buf! (s16vector->cpointer dst3) 68 10 entry1)
(add-from-buf! (s16vector->cpointer dst3) 68 10 entry3)
(check-equal? (s16vector->list dst3) (list 1 1 1 1
3 3 3 3 3 3 3 3 3 3
1 1 1 1 1 1))
)
(let ()
(define s1 (rsound (make-s16vector 20 2) 10 44100))
(define s2 (rsound (make-s16vector 4 3) 2 44100))
(define s3 (rsound (make-s16vector 30 4) 15 44100))
(define unplayed-heap (make-unplayed-heap))
(queue-for-playing! unplayed-heap s1 15)
(queue-for-playing! unplayed-heap s1 17)
(queue-for-playing! unplayed-heap s3 37)
(queue-for-playing! unplayed-heap s2 41)
(define tgt (make-s16vector 20 123))
(define tgt-ptr (s16vector->cpointer tgt))
(define-values (test-signal/block last-time) (heap->signal/block unplayed-heap))
(test-signal/block tgt-ptr 0 10)
(check-equal? (s16vector->list tgt)
(list 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0))
(check-equal? (last-time) 10)
(test-signal/block tgt-ptr 10 10)
(check-equal? (s16vector->list tgt)
(list 0 0 0 0 0 0 0 0 0 0
2 2 2 2 4 4 4 4 4 4))
(test-signal/block tgt-ptr 20 10)
(check-equal? (s16vector->list tgt)
(list 4 4 4 4 4 4 4 4 4 4
2 2 2 2 0 0 0 0 0 0))
(test-signal/block tgt-ptr 30 10)
(check-equal? (s16vector->list tgt)
(list 0 0 0 0 0 0 0 0 0 0
0 0 0 0 4 4 4 4 4 4))
(test-signal/block tgt-ptr 40 10)
(check-equal? (s16vector->list tgt)
(list 4 4 7 7 7 7 4 4 4 4
4 4 4 4 4 4 4 4 4 4))
(check-equal? (last-time) 50))