libao documentation

This commit is contained in:
2026-04-21 10:38:07 +02:00
parent 57fe9ab48a
commit cd11bb77f9
2 changed files with 213 additions and 1 deletions

View File

@@ -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)

211
scrbl/libao.scrbl Normal file
View File

@@ -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.