mp3 doc
This commit is contained in:
+54
-55
@@ -10,37 +10,27 @@
|
|||||||
|
|
||||||
@defmodule[racket-sound/mp3-decoder]
|
@defmodule[racket-sound/mp3-decoder]
|
||||||
|
|
||||||
This module provides an MP3 decoder implementation for
|
This module provides an MP3 decoder backend. It opens an MP3 file,
|
||||||
@racketmodname[racket-sound/audio-decoder]. It opens an MP3 file,
|
|
||||||
reports stream information through a callback, streams decoded PCM
|
reports stream information through a callback, streams decoded PCM
|
||||||
buffers, and supports stopping and seeking.
|
buffers, and supports stopping and seeking.
|
||||||
|
|
||||||
Compared to @racketmodname[racket-sound/flac-decoder], this module
|
The module is intended to be used through
|
||||||
stores its stream information directly in a mutable hash and updates
|
@racketmodname[racket-sound/audio-decoder], but its procedures can also
|
||||||
that hash in place during decoding.
|
be used directly.
|
||||||
|
|
||||||
@section{Handles}
|
|
||||||
|
|
||||||
@defproc[(mp3-handle? [v any/c]) boolean?]{
|
|
||||||
|
|
||||||
Returns @racket[#t] if @racket[v] is an MP3 decoder handle, and
|
|
||||||
@racket[#f] otherwise.
|
|
||||||
}
|
|
||||||
|
|
||||||
@section{Validation}
|
@section{Validation}
|
||||||
|
|
||||||
@defproc[(mp3-valid? [file any/c]) boolean?]{
|
@defproc[(mp3-valid? [mp3-file any/c]) boolean?]{
|
||||||
|
|
||||||
Returns @racket[#t].
|
Returns #t.
|
||||||
|
|
||||||
This procedure does not inspect @racket[file]. It exists to satisfy the
|
The current implementation does not inspect mp3-file. This procedure
|
||||||
reader interface expected by
|
exists to satisfy the reader interface used by
|
||||||
@racketmodname[racket-sound/audio-decoder].
|
@racketmodname[racket-sound/audio-decoder].
|
||||||
|
|
||||||
In practice, basic validation such as file existence and extension
|
Basic validation such as file existence and extension matching is
|
||||||
checking is already performed by
|
performed in the higher-level module. This procedure therefore acts as
|
||||||
@racketmodname[racket-sound/audio-decoder]. This procedure therefore
|
an additional hook and currently accepts all inputs.
|
||||||
acts only as an additional hook and currently accepts all inputs.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@section{Opening}
|
@section{Opening}
|
||||||
@@ -48,17 +38,16 @@ acts only as an additional hook and currently accepts all inputs.
|
|||||||
@defproc[(mp3-open [mp3-file* (or/c path? string?)]
|
@defproc[(mp3-open [mp3-file* (or/c path? string?)]
|
||||||
[cb-stream-info procedure?]
|
[cb-stream-info procedure?]
|
||||||
[cb-audio procedure?])
|
[cb-audio procedure?])
|
||||||
(or/c mp3-handle? #f)]{
|
(or/c struct? #f)]{
|
||||||
|
|
||||||
Opens an MP3 decoder for @racket[mp3-file*].
|
Opens an MP3 decoder for mp3-file*.
|
||||||
|
|
||||||
If @racket[mp3-file*] is a path, it is converted with
|
If mp3-file* is a path, it is converted with path->string. If the file
|
||||||
@racket[path->string]. If the file does not exist, the result is
|
does not exist, the result is #f.
|
||||||
@racket[#f].
|
|
||||||
|
|
||||||
Otherwise a decoder handle is created and initialized. During
|
Otherwise a decoder handle is created and initialized. During
|
||||||
initialization, stream information is collected and stored in a
|
initialization, stream information is collected and stored in a mutable
|
||||||
mutable hash in the handle.
|
hash in the handle.
|
||||||
|
|
||||||
The stream-info callback is invoked once, immediately after
|
The stream-info callback is invoked once, immediately after
|
||||||
initialization:
|
initialization:
|
||||||
@@ -67,22 +56,22 @@ initialization:
|
|||||||
(cb-stream-info info)
|
(cb-stream-info info)
|
||||||
]
|
]
|
||||||
|
|
||||||
where @racket[info] is a mutable hash containing at least:
|
where info is a mutable hash containing at least:
|
||||||
|
|
||||||
@itemlist[#:style 'compact
|
@itemlist[#:style 'compact
|
||||||
@item{@racket['duration] --- stream duration in seconds;}
|
@item{'duration}
|
||||||
@item{@racket['sample-rate] --- samples per second per channel;}
|
@item{'sample-rate}
|
||||||
@item{@racket['channels] --- number of channels;}
|
@item{'channels}
|
||||||
@item{@racket['bits-per-sample] --- bits per sample;}
|
@item{'bits-per-sample}
|
||||||
@item{@racket['bytes-per-sample] --- bytes per sample;}
|
@item{'bytes-per-sample}
|
||||||
@item{@racket['total-samples] --- total PCM sample count.}]
|
@item{'total-samples}]
|
||||||
}
|
}
|
||||||
|
|
||||||
@section{Reading}
|
@section{Reading}
|
||||||
|
|
||||||
@defproc[(mp3-read [handle mp3-handle?]) any/c]{
|
@defproc[(mp3-read [handle struct?]) any/c]{
|
||||||
|
|
||||||
Starts the decode loop for @racket[handle].
|
Starts the decode loop for handle.
|
||||||
|
|
||||||
The loop repeatedly decodes audio chunks and invokes the audio
|
The loop repeatedly decodes audio chunks and invokes the audio
|
||||||
callback:
|
callback:
|
||||||
@@ -91,20 +80,23 @@ callback:
|
|||||||
(cb-audio info buffer size)
|
(cb-audio info buffer size)
|
||||||
]
|
]
|
||||||
|
|
||||||
Before each callback, the @racket[info] hash is updated in place with:
|
Before each callback, the info hash is updated in place with:
|
||||||
|
|
||||||
@itemlist[#:style 'compact
|
@itemlist[#:style 'compact
|
||||||
@item{@racket['sample] --- current PCM sample position;}
|
@item{'sample}
|
||||||
@item{@racket['current-time] --- current playback time in seconds.}]
|
@item{'current-time}]
|
||||||
|
|
||||||
|
The loop also checks for a pending seek request. If a seek has been
|
||||||
|
requested, the stored target sample position is forwarded to the
|
||||||
|
decoder backend and the request is cleared.
|
||||||
|
|
||||||
The loop terminates when either:
|
The loop terminates when either:
|
||||||
|
|
||||||
@itemlist[#:style 'compact
|
@itemlist[#:style 'compact
|
||||||
@item{the backend reports end-of-stream, or}
|
@item{the backend reports end-of-stream}
|
||||||
@item{a stop has been requested via @racket[mp3-stop].}]
|
@item{a stop has been requested via mp3-stop}]
|
||||||
|
|
||||||
If a stop is detected, the procedure returns
|
If a stop is detected, the procedure returns 'stopped-reading.
|
||||||
@racket['stopped-reading].
|
|
||||||
|
|
||||||
After termination, the underlying decoder is closed and released.
|
After termination, the underlying decoder is closed and released.
|
||||||
|
|
||||||
@@ -113,24 +105,32 @@ The return value is otherwise unspecified.
|
|||||||
|
|
||||||
@section{Seeking}
|
@section{Seeking}
|
||||||
|
|
||||||
@defproc[(mp3-seek [handle mp3-handle?]
|
@defproc[(mp3-seek [handle struct?]
|
||||||
[percentage number?])
|
[percentage number?])
|
||||||
void?]{
|
void?]{
|
||||||
|
|
||||||
Seeks within the stream by percentage of the total length.
|
Requests a seek within the stream.
|
||||||
|
|
||||||
The @racket[percentage] argument is interpreted as a value between
|
The percentage argument represents a position relative to the full
|
||||||
@racket[0] and @racket[100]. The target position is computed from the
|
audio stream, where 0 is the start and 100 is the end. The value may be
|
||||||
value stored under @racket['total-samples] in the stream-info hash.
|
fractional.
|
||||||
|
|
||||||
If the total sample count is unavailable, this procedure has no effect.
|
If the total number of samples is available in the handle, the
|
||||||
|
procedure computes an absolute target sample and stores it in the
|
||||||
|
handle as a pending seek request.
|
||||||
|
|
||||||
|
The actual seek operation is performed later by mp3-read in its decode
|
||||||
|
loop.
|
||||||
|
|
||||||
|
If the total number of samples is unavailable or equal to -1, this
|
||||||
|
procedure has no effect.
|
||||||
}
|
}
|
||||||
|
|
||||||
@section{Stopping}
|
@section{Stopping}
|
||||||
|
|
||||||
@defproc[(mp3-stop [handle mp3-handle?]) void?]{
|
@defproc[(mp3-stop [handle struct?]) void?]{
|
||||||
|
|
||||||
Requests termination of an active @racket[mp3-read] loop.
|
Requests termination of an active mp3-read loop.
|
||||||
|
|
||||||
The procedure sets an internal stop flag and waits until the read loop
|
The procedure sets an internal stop flag and waits until the read loop
|
||||||
has terminated, sleeping briefly between checks.
|
has terminated, sleeping briefly between checks.
|
||||||
@@ -144,6 +144,5 @@ is updated in place during playback.
|
|||||||
The audio buffer passed to the callback is managed by the decoder and
|
The audio buffer passed to the callback is managed by the decoder and
|
||||||
should be treated as transient data.
|
should be treated as transient data.
|
||||||
|
|
||||||
Although the handle contains a field related to deferred seeking, the
|
Seeking is implemented as a request stored in the handle and executed
|
||||||
current implementation performs seeking directly in
|
by the decode loop, not directly by mp3-seek.
|
||||||
@racket[mp3-seek].
|
|
||||||
Reference in New Issue
Block a user