Files

222 lines
6.8 KiB
Racket
Raw Permalink Normal View History

2025-08-10 22:09:59 +02:00
#lang racket/base
(require (prefix-in fin: finalizer)
(prefix-in ffi: "libao-async-ffi.rkt")
2026-02-22 16:08:02 +01:00
ffi/unsafe
ffi/unsafe/custodian
2026-02-22 16:08:02 +01:00
data/queue
2026-04-09 13:04:42 +02:00
"private/utils.rkt"
2026-04-15 12:19:42 +02:00
(prefix-in rc: racket/contract)
2026-02-22 16:08:02 +01:00
)
2025-08-10 22:09:59 +02:00
(provide ao-open-live
2026-04-28 15:04:12 +02:00
ao-device-bits
ao-open-file
2025-08-10 22:09:59 +02:00
ao-play
ao-close
2026-02-22 17:37:15 +01:00
ao-at-second
2026-02-25 10:15:51 +01:00
ao-music-duration
2026-04-15 12:19:42 +02:00
ao-at-music-id
2026-02-22 23:15:22 +01:00
ao-bufsize-async
2026-02-23 01:23:49 +01:00
ao-clear-async
2026-02-25 13:50:22 +01:00
ao-pause
2026-04-21 10:10:29 +02:00
ao-set-volume!
ao-volume
2026-04-15 12:19:42 +02:00
ao-valid?
ao-valid-bits?
ao-valid-rate?
ao-valid-channels?
ao-valid-format?
ao-handle?
ao-supported-music-format?
2025-08-10 22:09:59 +02:00
)
2025-08-13 14:13:35 +02:00
(define device-number 1)
(define-struct ao-handle (handle-num
[bits #:auto #:mutable]
[bytes-per-sample #:auto #:mutable]
2026-04-28 15:04:12 +02:00
[dev-bits #:auto #:mutable]
[dev-bytes-per-sample #:auto #:mutable]
2025-08-13 14:13:35 +02:00
[byte-format #:auto #:mutable]
[channels #:auto #:mutable]
[rate #:auto #:mutable]
2026-02-22 17:37:15 +01:00
[async-player #:auto #:mutable]
2026-02-24 14:05:46 +01:00
[closed #:auto #:mutable]
2025-08-13 14:13:35 +02:00
)
#:auto-value #f
)
2026-04-15 12:19:42 +02:00
(define (ao-supported-music-format? f)
(and (symbol? f)
(or (eq? f 'flac)
(eq? f 'ao))))
(define (bytes-for-bits bits)
(/ bits 8))
2025-08-10 22:09:59 +02:00
2026-04-15 12:19:42 +02:00
(define (ao-valid-bits? bits)
(and (integer? bits) (or
(= bits 8)
(= bits 16)
(= bits 24)
(= bits 32))
)
)
(define (ao-valid-rate? rate)
(and (integer? rate)
2026-04-21 10:38:07 +02:00
(> rate 0)
2026-04-15 12:19:42 +02:00
(not (eq? (memq rate '(8000 11025 16000 22050 44100
2026-04-21 10:38:07 +02:00
48000 88200 96000 176400
2026-04-15 12:19:42 +02:00
192000 352800 384000)) #f))))
(define (ao-valid-channels? c)
(and (integer? c)
2026-04-15 12:23:50 +02:00
(>= c 1)))
2026-04-15 12:19:42 +02:00
(define (ao-valid-format? f)
(or (eq? f 'little-endian)
(eq? f 'big-endian)
(eq? f 'native-endian)))
(rc:define/contract (ao-open-live bits rate channels byte-format)
(rc:-> ao-valid-bits? ao-valid-rate? ao-valid-channels? ao-valid-format? ao-handle?)
(ao-open-file bits rate channels byte-format #f))
(define (valid-file-kind? f)
(or (string? f) (path? f) (eq? f #f)))
(rc:define/contract (ao-open-file bits rate channels byte-format filename)
(rc:-> ao-valid-bits? ao-valid-rate? ao-valid-channels? ao-valid-format? valid-file-kind? ao-handle?)
(let* ((handle (make-ao-handle device-number))
(file (if (eq? filename #f)
#f
(format "~a" filename)))
)
(fin:register-finalizer handle
(lambda (handle)
(ao-close handle)))
(set-ao-handle-bits! handle bits)
(set-ao-handle-bytes-per-sample! handle (bytes-for-bits bits))
(set-ao-handle-byte-format! handle byte-format)
(set-ao-handle-channels! handle channels)
(set-ao-handle-rate! handle rate)
(info-sound "ao-open-live ~a ~a ~a ~a ~a" bits rate channels byte-format file)
(let ((player (ffi:ao_create_async bits rate channels byte-format file)))
(set-ao-handle-async-player! handle player)
(if (eq? player #f)
(begin
(err-sound "ao-open-live - cannote create player")
(set-ao-handle-closed! handle #t)
handle)
2026-04-28 15:04:12 +02:00
(let ((out-bits (ffi:ao_real_output_bits_async player)))
(info-sound "ao-open-live - created player at ~a bits" out-bits)
(set-ao-handle-dev-bits! handle out-bits)
(set-ao-handle-dev-bytes-per-sample! handle (/ out-bits 8))
(set-ao-handle-closed! handle #f)
handle
)
)
2026-02-24 14:57:29 +01:00
)
)
2026-04-28 15:04:12 +02:00
)
2025-08-13 14:13:35 +02:00
2026-04-15 12:19:42 +02:00
(rc:define/contract (ao-close handle)
(rc:-> ao-handle? void?)
(void
(unless (eq? (ao-handle-async-player handle) #f)
(info-sound "ao-close - closing handle")
(ffi:ao_stop_async (ao-handle-async-player handle))
(set-ao-handle-async-player! handle #f)
)
)
)
2025-08-13 14:13:35 +02:00
2026-04-15 09:44:01 +02:00
(define (ao-valid? handle)
2026-04-15 12:19:42 +02:00
(and (ao-handle? handle)
(not (eq? (ao-handle-async-player handle) #f)))
)
(define (any? x)
#t)
2026-04-15 09:44:01 +02:00
2026-04-28 15:04:12 +02:00
(rc:define/contract (ao-device-bits handle)
(rc:-> ao-handle? integer?)
(ao-handle-dev-bits handle))
2026-04-15 12:19:42 +02:00
(rc:define/contract (ao-play handle music-id at-time-in-s music-duration-s buffer buf-len buf-type)
(rc:-> ao-handle? integer? number? number? any? integer? ao-supported-music-format? void?)
2025-08-13 14:13:35 +02:00
(let* ((bytes-per-sample (ao-handle-bytes-per-sample handle))
(bits (ao-handle-bits handle))
2026-04-10 08:32:55 +02:00
(rate (ao-handle-rate handle))
2025-08-13 14:13:35 +02:00
(channels (ao-handle-channels handle))
(endianess (ao-handle-byte-format handle))
(buf-info (ffi:make-BufferInfo_t buf-type bits rate channels endianess))
2025-08-13 14:13:35 +02:00
)
2026-04-15 09:44:01 +02:00
(unless (ao-valid? handle)
2026-04-15 09:52:00 +02:00
(err-sound "Cannot play on an invalid ao-device")
2026-04-15 09:44:01 +02:00
(error "Cannot play on an invalid ao-device"))
(ffi:ao_play_async (ao-handle-async-player handle)
2026-04-15 12:19:42 +02:00
music-id
(exact->inexact at-time-in-s)
(exact->inexact music-duration-s)
buf-len
buffer
buf-info)
2026-04-15 12:19:42 +02:00
2026-02-22 16:08:02 +01:00
)
)
2026-04-15 12:19:42 +02:00
(rc:define/contract (ao-pause handle pause)
(rc:-> ao-handle? boolean? void?)
2026-04-15 09:52:00 +02:00
(dbg-sound "ao-pause ~a" pause)
2026-04-10 08:32:55 +02:00
(ffi:ao_pause_async (ao-handle-async-player handle) (if (eq? pause #f) 0 1))
)
2026-02-25 13:47:51 +01:00
2026-04-15 12:19:42 +02:00
(rc:define/contract (ao-at-second handle)
(rc:-> ao-handle? number?)
2026-04-10 08:32:55 +02:00
(ffi:ao_is_at_second_async (ao-handle-async-player handle))
)
2026-04-15 12:19:42 +02:00
(rc:define/contract (ao-at-music-id handle)
(rc:-> ao-handle? integer?)
(ffi:ao_is_at_music_id_async (ao-handle-async-player handle))
)
2026-04-10 08:32:55 +02:00
2026-04-15 12:19:42 +02:00
(rc:define/contract (ao-music-duration handle)
(rc:-> ao-handle? number?)
2026-04-10 08:32:55 +02:00
(ffi:ao_music_duration_async (ao-handle-async-player handle))
)
2026-02-25 10:15:51 +01:00
2026-04-15 12:19:42 +02:00
(rc:define/contract (ao-bufsize-async handle)
(rc:-> ao-handle? integer?)
2026-04-10 08:32:55 +02:00
(ffi:ao_bufsize_async (ao-handle-async-player handle))
)
2026-02-22 23:15:22 +01:00
2026-04-21 10:10:29 +02:00
(rc:define/contract (ao-set-volume! handle percentage)
(rc:-> ao-handle? number? void?)
(ffi:ao_set_volume_async (ao-handle-async-player handle)
(if (integer? percentage)
(exact->inexact percentage)
percentage))
)
(rc:define/contract (ao-volume handle)
(rc:-> ao-handle? number?)
(ffi:ao_volume_async (ao-handle-async-player handle))
)
(rc:define/contract (ao-clear-async handle)
2026-04-15 12:19:42 +02:00
(rc:-> ao-handle? void?)
2026-04-10 08:32:55 +02:00
(ffi:ao_clear_async (ao-handle-async-player handle))
)
2026-02-23 01:23:49 +01:00
2025-08-10 22:09:59 +02:00