-
This commit is contained in:
155
scrbl/flac-decoder.scrbl
Normal file
155
scrbl/flac-decoder.scrbl
Normal file
@@ -0,0 +1,155 @@
|
||||
#lang scribble/manual
|
||||
|
||||
@(require racket/base
|
||||
(for-label racket/base
|
||||
racket/path
|
||||
"../flac-decoder.rkt"
|
||||
"../flac-definitions.rkt"))
|
||||
|
||||
@title{flac-decoder}
|
||||
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
|
||||
|
||||
@defmodule["flac-decoder.rkt"]
|
||||
|
||||
This module provides a small decoder interface on top of the FLAC
|
||||
FFI layer. It opens a decoder for a file, reads stream metadata,
|
||||
reads audio frames, exposes the current decoder state, and allows
|
||||
an active read loop to be stopped. It also re-exports the bindings
|
||||
from @racketmodname["flac-definitions.rkt"].
|
||||
|
||||
A decoder handle stores the native decoder handler together with
|
||||
optional callbacks for stream metadata and decoded audio.
|
||||
|
||||
@section{Procedures}
|
||||
|
||||
@defproc[(flac-open [flac-file* (or/c path? string?)]
|
||||
[cb-stream-info (or/c procedure? #f)]
|
||||
[cb-audio (or/c procedure? #f)])
|
||||
(or/c flac-handle? #f)]{
|
||||
|
||||
Opens a FLAC decoder for @racket[flac-file*]. If a path is given,
|
||||
it is converted with @racket[path->string]. If the file does not
|
||||
exist, the result is @racket[#f].
|
||||
|
||||
Otherwise a native decoder handler is created with
|
||||
@racket[flac-ffi-decoder-handler], initialized with the file, and
|
||||
wrapped in a @racket[flac-handle]. The given callbacks are stored
|
||||
in the handle.
|
||||
|
||||
When metadata of type @racket['streaminfo] is processed and
|
||||
@racket[cb-stream-info] is a procedure, it is called with a
|
||||
@racket[flac-stream-info] value.
|
||||
|
||||
When decoded audio data is processed and @racket[cb-audio] is a
|
||||
procedure, it is called as
|
||||
@racket[(cb-audio header buffers)], where @racket[header] is a
|
||||
mutable hash containing the frame header fields plus
|
||||
@racket['duration], and @racket[buffers] is the decoded channel
|
||||
data returned by the FFI layer.
|
||||
}
|
||||
|
||||
@defproc[(flac-stream-state [handle flac-handle?])
|
||||
(or/c 'search-for-metadata
|
||||
'read-metadata
|
||||
'search-for-frame-sync
|
||||
'read-frames
|
||||
'end-of-stream
|
||||
'ogg-error
|
||||
'seek-error
|
||||
'aborted
|
||||
'memory-allocation-error
|
||||
'uninitialized
|
||||
'end-of-link)]{
|
||||
|
||||
Returns the current decoder state reported by the native decoder
|
||||
handler.
|
||||
}
|
||||
|
||||
@defproc[(flac-read [handle flac-handle?])
|
||||
(or/c 'stopped-reading
|
||||
'end-of-stream)]{
|
||||
|
||||
Reads the stream by repeatedly calling the native decoder with
|
||||
@racket['process-single].
|
||||
|
||||
Before reading starts, the handle fields @racket[stop-reading]
|
||||
and @racket[reading] are set to @racket[#f] and @racket[#t]. If a
|
||||
stop has been requested with @racket[flac-stop], reading ends
|
||||
with @racket['stopped-reading] and @racket[reading] is reset to
|
||||
@racket[#f].
|
||||
|
||||
Whenever pending metadata is available, it is processed with
|
||||
@racket[process-meta]. For metadata of type
|
||||
@racket['streaminfo], a @racket[flac-stream-info] value is
|
||||
constructed, stored in the handle, and passed to the
|
||||
stream-info callback.
|
||||
|
||||
Whenever pending frame data is available, it is processed with
|
||||
@racket[process-frame]. The frame header is converted to a
|
||||
mutable hash, extended with a @racket['duration] entry taken
|
||||
from @racket[flac-duration], and passed together with the
|
||||
decoded buffers to the audio callback.
|
||||
|
||||
For each processed frame, the module also updates
|
||||
@racket[last-buffer], @racket[last-buf-len], and @racket[kinds].
|
||||
|
||||
The procedure prints diagnostic messages for state changes,
|
||||
metadata, stream errors, and stop handling.
|
||||
}
|
||||
|
||||
@defproc[(flac-read-meta [handle flac-handle?])
|
||||
(or/c flac-stream-info? #f)]{
|
||||
|
||||
Advances the decoder until the state becomes one of
|
||||
@racket['read-metadata], @racket['end-of-stream],
|
||||
@racket['aborted], @racket['memory-allocation-error], or
|
||||
@racket['uninitialized].
|
||||
|
||||
If the resulting state is @racket['read-metadata], pending
|
||||
metadata is processed and the stored stream info is returned.
|
||||
Otherwise the result is @racket[#f].
|
||||
|
||||
Only metadata of type @racket['streaminfo] is converted into a
|
||||
@racket[flac-stream-info] value by this module.
|
||||
}
|
||||
|
||||
@defproc[(flac-stop [handle flac-handle?]) void?]{
|
||||
|
||||
Requests termination of an active @racket[flac-read] loop by
|
||||
setting the handle field @racket[stop-reading] to @racket[#t].
|
||||
The procedure then waits until the handle field
|
||||
@racket[reading] becomes @racket[#f], sleeping for 10 ms between
|
||||
checks.
|
||||
|
||||
The procedure prints timing information before and after the
|
||||
wait.
|
||||
}
|
||||
|
||||
@section{Diagnostic bindings}
|
||||
|
||||
@defthing[kinds hash?]{
|
||||
|
||||
A mutable hash used to record the frame number kinds encountered
|
||||
during decoding. The keys are the values found in the
|
||||
frame-header field @racket['number-type].
|
||||
}
|
||||
|
||||
@defthing[last-buffer (or/c #f list?)]{
|
||||
|
||||
The most recently decoded buffer set produced by frame
|
||||
processing.
|
||||
}
|
||||
|
||||
@defthing[last-buf-len (or/c #f exact-integer?)]{
|
||||
|
||||
The block size of the most recently processed frame.
|
||||
}
|
||||
|
||||
@section{Notes}
|
||||
|
||||
The frame-header hash passed to the audio callback is produced
|
||||
by @racket[flac-ffi-frame-header]. In this module it is extended
|
||||
with a @racket['duration] field before the callback is called.
|
||||
|
||||
All bindings from @racketmodname["flac-definitions.rkt"] are
|
||||
re-exported.
|
||||
Reference in New Issue
Block a user