From cd11bb77f933e69746aead10d277d7262b58fa21 Mon Sep 17 00:00:00 2001 From: Hans Dijkema Date: Tue, 21 Apr 2026 10:38:07 +0200 Subject: [PATCH] libao documentation --- libao.rkt | 3 +- scrbl/libao.scrbl | 211 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 scrbl/libao.scrbl diff --git a/libao.rkt b/libao.rkt index 7cba78c..11143f7 100644 --- a/libao.rkt +++ b/libao.rkt @@ -65,8 +65,9 @@ (define (ao-valid-rate? rate) (and (integer? rate) + (> rate 0) (not (eq? (memq rate '(8000 11025 16000 22050 44100 - 48000 88200 96000 1764000 + 48000 88200 96000 176400 192000 352800 384000)) #f)))) (define (ao-valid-channels? c) diff --git a/scrbl/libao.scrbl b/scrbl/libao.scrbl new file mode 100644 index 0000000..06ea729 --- /dev/null +++ b/scrbl/libao.scrbl @@ -0,0 +1,211 @@ +#lang scribble/manual + +@(require racket/base + (for-label racket/base + "../libao.rkt")) + +@title{libao} +@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] + +@defmodule["libao.rkt"] + +This module provides a small high-level interface to an asynchronous +audio output backend. It opens a live output device, queues audio +buffers for playback, reports playback position, supports pause and +buffer clearing, and exposes a small set of validation predicates. + +The central value is an @racket[ao-handle], created by +@racket[ao-open-live]. An @racket[ao-handle] stores the playback +configuration together with a native asynchronous player handle. + +@section{Audio handles} + +@defproc[(ao-handle? [v any/c]) boolean?]{ + +Returns @racket[#t] if @racket[v] is an @racket[ao-handle] value, and +@racket[#f] otherwise. +} + +@defproc[(ao-valid? [handle ao-handle?]) boolean?]{ + +Returns @racket[#t] if @racket[handle] still has a native asynchronous +player, and @racket[#f] otherwise. + +A handle becomes invalid after @racket[ao-close], or when +@racket[ao-open-live] failed to create the native player. +} + +@section{Validation predicates} + +@defproc[(ao-valid-bits? [bits any/c]) boolean?]{ + +Returns @racket[#t] if @racket[bits] is one of @racket[8], +@racket[16], @racket[24], or @racket[32], and @racket[#f] otherwise. +} + +@defproc[(ao-valid-rate? [rate any/c]) boolean?]{ + +Returns @racket[#t] if @racket[rate] is one of the sample rates +accepted by this module, and @racket[#f] otherwise. + +The accepted rates are: + +@itemlist[#:style 'compact + @item{@racket[8000], @racket[11025], @racket[16000], @racket[22050],} + @item{@racket[44100], @racket[48000], @racket[88200], @racket[96000],} + @item{@racket[176400], @racket[192000], @racket[352800], and} + @item{@racket[384000].}] +} + +@defproc[(ao-valid-channels? [channels any/c]) boolean?]{ + +Returns @racket[#t] if @racket[channels] is an integer greater than or +equal to @racket[1], and @racket[#f] otherwise. +} + +@defproc[(ao-valid-format? [format any/c]) boolean?]{ + +Returns @racket[#t] if @racket[format] is one of +@racket['little-endian], @racket['big-endian], or +@racket['native-endian], and @racket[#f] otherwise. +} + +@defproc[(ao-supported-music-format? [format any/c]) boolean?]{ + +Returns @racket[#t] if @racket[format] is one of @racket['flac], +@racket['mp3], or @racket['ao], and @racket[#f] otherwise. + +This value is used by @racket[ao-play] to describe the format of the +buffer being queued. +} + +@section{Opening and closing} + +@defproc[(ao-open-live [bits ao-valid-bits?] + [rate ao-valid-rate?] + [channels ao-valid-channels?] + [byte-format ao-valid-format?]) + ao-handle?]{ + +Creates an audio output handle for live playback. + +The handle stores the given sample size, sample rate, channel count, +and byte format. It then tries to create a native asynchronous player. + +If the native player is created successfully, the returned handle is +valid. If player creation fails, the function still returns an +@racket[ao-handle], but that handle is marked closed and is not valid +for playback. + +A finalizer is registered for the handle and calls @racket[ao-close] +when the handle is reclaimed. +} + +@defproc[(ao-close [handle ao-handle?]) void?]{ + +Stops playback for @racket[handle] and releases the native player +reference stored in the handle. + +If the handle already has no native player, this procedure has no +effect. +} + +@section{Playback} + +@defproc[(ao-play [handle ao-handle?] + [music-id integer?] + [at-time-in-s number?] + [music-duration-s number?] + [buffer any/c] + [buf-len integer?] + [buf-type ao-supported-music-format?]) + void?]{ + +Queues audio data for asynchronous playback. + +The @racket[music-id] argument identifies the music stream associated +with the buffer. The arguments @racket[at-time-in-s] and +@racket[music-duration-s] describe the position and duration, in +seconds, associated with the buffer. The arguments @racket[buffer] and +@racket[buf-len] provide the audio data and its length. The +@racket[buf-type] argument specifies the buffer format. + +The buffer description passed to the native layer is completed with the +sample size, sample rate, channel count, and byte format stored in +@racket[handle]. + +If @racket[handle] is not valid, this procedure raises an exception. +} + +@defproc[(ao-pause [handle ao-handle?] + [pause boolean?]) + void?]{ + +Pauses or resumes asynchronous playback for @racket[handle]. + +A true value pauses playback. @racket[#f] resumes playback. +} + +@defproc[(ao-clear-async [handle ao-handle?]) void?]{ + +Clears buffered asynchronous playback data for @racket[handle]. +} + +@section{Playback state} + +@defproc[(ao-at-second [handle ao-handle?]) number?]{ + +Returns the current playback position, in seconds, as reported by the +native asynchronous player. +} + +@defproc[(ao-at-music-id [handle ao-handle?]) integer?]{ + +Returns the music identifier currently reported by the native +asynchronous player. +} + +@defproc[(ao-music-duration [handle ao-handle?]) number?]{ + +Returns the duration of the current music stream, in seconds, as +reported by the native asynchronous player. +} + +@defproc[(ao-bufsize-async [handle ao-handle?]) integer?]{ + +Returns the current buffered size in bytes for the asynchronous player. +} + +@section{Volume control} + +@defproc[(ao-set-volume! [handle ao-handle?] + [percentage number?]) + void?]{ + +Sets the playback volume for @racket[handle]. + +If @racket[percentage] is an exact integer, it is converted to an +inexact number before it is passed to the native layer. +} + +@defproc[(ao-volume [handle ao-handle?]) number?]{ + +Returns the current playback volume as reported by the native +asynchronous player. +} + +@section{Notes} + +This module is a higher-level wrapper around the asynchronous FFI layer. +It stores the playback configuration in the handle, and reuses that +configuration for each call to @racket[ao-play]. + +The module does not expose the handle fields directly. The public API +is intentionally small: create a handle, queue buffers, inspect +position and buffer state, pause or clear playback, adjust volume, and +close the handle. + +A typical usage pattern is to open one live handle for a given stream +format, queue decoded buffers with @racket[ao-play], and query the +playback position with @racket[ao-at-second] while playback proceeds +asynchronously. \ No newline at end of file