#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["racket-sound/flac-decoder"] 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.