audio-decoder
1 Reader registration
make-audio-reader
audio-register-reader!
2 Audio handles
audio-handle?
audio-kind
3 Known extensions and validation
audio-known-exts?
audio-valid-ext?
audio-file-valid?
4 Opening and callbacks
audio-open
5 Reading, seeking, and stopping
audio-read
audio-seek
audio-stop
6 Using custom decoders
9.1

audio-decoder🔗ℹ

Hans Dijkema <hans@dijkewijk.nl>

 (require "racket-sound/audio-decoder")
  package: racket-sound

This module provides a small abstraction layer over concrete audio decoders. A backend is selected from the filename extension and is then used through a uniform interface for opening, reading, seeking, and stopping.

The module includes built-in readers for FLAC and MP3, and it allows additional backends to be registered with audio-register-reader!.

1 Reader registration🔗ℹ

A reader descriptor stores the extensions handled by a backend together with the procedures used to validate, open, read, seek, and stop that backend, plus an audio-output type.

procedure

(make-audio-reader exts    
  valid?    
  open    
  reader    
  seeker    
  stopper    
  ao-type)  struct?
  exts : (listof string?)
  valid? : procedure?
  open : procedure?
  reader : procedure?
  seeker : procedure?
  stopper : procedure?
  ao-type : symbol?
Creates a reader descriptor.

The exts list contains the filename extensions handled by the reader, without a leading dot. Matching is case-insensitive.

The procedures are used as follows:

  • valid? checks whether a file is valid for this reader;

  • open opens a decoder for a file;

  • reader reads or continues decoding;

  • seeker seeks within the audio stream;

  • stopper stops an active decode loop.

The ao-type value describes the buffer format exposed to the audio output layer. The source comments mention values such as 'flac and 'ao. The value 'ao means that the buffer can be used directly by the audio-output backend.

procedure

(audio-register-reader! type reader)  void?

  type : symbol?
  reader : struct?
Registers reader under type.

The extensions declared in reader are appended to the list returned by audio-known-exts?, and the reader becomes available to audio-open.

This procedure is the extension point for custom audio decoders.

2 Audio handles🔗ℹ

procedure

(audio-handle? v)  boolean?

  v : any/c
Returns #t if v is an audio handle, and #f otherwise.

procedure

(audio-kind handle)  symbol?

  handle : audio-handle?
Returns the reader type stored in handle.

For the built-in readers this is either 'flac or 'mp3.

3 Known extensions and validation🔗ℹ

procedure

(audio-known-exts?)  (listof string?)

Returns the list of known filename extensions.

The initial list contains "flac" and "mp3". Additional extensions are added when readers are registered with audio-register-reader!.

procedure

(audio-valid-ext? ext)  boolean?

  ext : any/c
Returns #t if ext denotes a known filename extension, and #f otherwise.

The argument is converted to a string. If it starts with a dot, that dot is removed. Matching is case-insensitive.

procedure

(audio-file-valid? file)  boolean?

  file : (or/c string? path?)
Returns #t if file has a known extension and the matching registered reader reports the file as valid.

This procedure first derives the filename extension and checks it with audio-valid-ext?. If the extension is known, it then looks up the matching reader and calls that reader’s validity procedure.

4 Opening and callbacks🔗ℹ

procedure

(audio-open audio-file    
  cb-stream-info    
  cb-audio)  audio-handle?
  audio-file : (or/c string? path?)
  cb-stream-info : procedure?
  cb-audio : procedure?
Opens an audio decoder for audio-file.

If audio-file is a path, it is converted to a string before it is passed to the backend open procedure.

This procedure raises an exception if the file is not considered a valid audio file, if the file does not exist, or if no registered reader can be found for the file.

The returned handle stores the selected reader type, the two callback procedures, the reader descriptor, and the driver-specific handle returned by the backend open procedure.

The callback procedures are wrapped before they are passed to the backend.

The stream-info callback is called as:

(cb-stream-info audio-type ao-type handle meta)

where:

  • audio-type is the registered reader type, such as 'flac or 'mp3;

  • ao-type is the audio-output type stored in the reader, such as 'flac or 'ao;

  • handle is the generic audio-handle;

  • meta is a hash table with stream metadata.

According to the source comments, meta must contain at least:

  • 'duration duration of the audio in seconds, possibly fractional;

  • 'bits-per-sample number of audio bits per sample;

  • 'channels number of audio channels;

  • 'sample-rate number of samples per second per channel;

  • 'total-samples total number of samples in the audio.

The audio callback is called as:

(cb-audio audio-type ao-type handle buf-info buffer buf-size)

where:

  • audio-type is the registered reader type;

  • ao-type is the audio-output type stored in the reader;

  • handle is the generic audio-handle;

  • buf-info is a hash table describing the audio buffer;

  • buffer is a native buffer containing audio data;

  • buf-size is the size of that buffer in bytes.

According to the source comments, the buffer is to be owned and released by the decoder driver. The comments also note that the ao-async backend copies the data.

According to the source comments, buf-info must contain at least:

  • 'duration duration of the audio in seconds, possibly fractional;

  • 'bits-per-sample number of audio bits per sample;

  • 'channels number of audio channels;

  • 'sample-rate number of samples per second per channel;

  • 'total-samples total number of samples in the audio;

  • 'sample the current sample to which the audio buffer applies.

5 Reading, seeking, and stopping🔗ℹ

procedure

(audio-read handle)  void?

  handle : audio-handle?
Calls the registered reader procedure for handle.

The concrete reader procedure receives the driver-specific handle stored in the generic audio handle. Any result value produced by the backend is discarded.

procedure

(audio-seek handle percentage)  void?

  handle : audio-handle?
  percentage : number?
Calls the registered seek procedure for handle.

The percentage argument is passed unchanged to the backend seek procedure.

In this abstraction layer, the parameter represents a relative position in the full audio stream. A backend registered through audio-register-reader! is expected to follow that interpretation.

procedure

(audio-stop handle)  void?

  handle : audio-handle?
Calls the registered stop procedure for handle.

The concrete stop procedure receives the driver-specific handle stored in the generic audio handle.

6 Using custom decoders🔗ℹ

Custom audio decoders can be integrated by constructing a reader descriptor with make-audio-reader and registering it with audio-register-reader!.

A backend integrated through this interface should provide:

  • a list of handled filename extensions;

  • a file-validity procedure;

  • an open procedure that accepts a file path, a stream-info callback, and an audio callback;

  • a read procedure that accepts the driver-specific handle;

  • a seek procedure that accepts the driver-specific handle and a numeric relative position;

  • a stop procedure that accepts the driver-specific handle;

  • an audio-output type symbol describing the kind of buffers the backend produces.

Once registered, files with matching extensions can be opened through audio-open in the same way as the built-in FLAC and MP3 backends.