Skip to content

TSdlAudioStream

Represents an audio stream.

TSdlAudioStream is an audio conversion interface.

  • It can handle resampling data in chunks without generating artifacts, when it doesn't have the complete buffer available.
  • It can handle incoming data in any variable size.
  • It can handle input/output format changes on the fly.
  • It can remap audio channels between inputs and outputs.
  • You push data as you have it, and pull it when you need it
  • It can also function as a basic audio data queue even if you just have sound that needs to pass from one place to another.
  • You can hook callbacks up to them when more data is added or requested, to manage data on-the-fly.

Audio streams are the core of the SDL3 audio interface. You create one or more of them, bind them to an opened audio device, and feed data to them (or for recording, consume data from them).

Definition

Unit: Neslib.Sdl3.Audio

type TSdlAudioStream = record ... end;

Properties

Name Description
Available The number of converted/resampled bytes available.
Device The currently-bound device of the stream
FrequencyRatio The frequency ratio of the audio stream.
Gain The gain of an audio stream.
InputChannelMap Get the current input channel map of the audio stream.
IsPaused Whether the audio device associated with a stream is paused.
OutputChannelMap Get the current output channel map of the audio stream.
Properties The properties associated with an audio stream.
Queued Get the number of bytes currently queued.

Constructors

Name Description
Create(TSdlAudioDeviceID, PSdlAudioSpec, TSdlAudioStreamCallback, Pointer) Convenience constructor for straightforward audio init for the common case.
Create(TSdlAudioSpec, TSdlAudioSpec) Create a new audio stream.
Create(TSdlAudioSpec) Create a new audio stream.

Operators

Name Description
Equal(TSdlAudioStream, TSdlAudioStream) Used to compare against another TSdlAudioStream.
Equal(TSdlAudioStream, Pointer) Used to compare against nil.
Implicit Used to set the value to nil.
NotEqual(TSdlAudioStream, TSdlAudioStream) Used to compare against another TSdlAudioStream.
NotEqual(TSdlAudioStream, Pointer) Used to compare against nil.

Methods

Name Description
Clear Clear any pending data in the stream.
Flush Tell the stream that you're done sending data, and anything being buffered should be converted/resampled and made available immediately.
Free Free the audio stream.
GetData Get converted/resampled data from the stream.
GetFormat Query the current format of the stream.
Lock Lock the audio stream for serialized access.
Pause Pause audio playback on the audio device associated with this audio stream.
PutData Add data to the stream.
Resume Unpause audio playback on the audio device associated with this audio stream.
SetFormat Change the input and output formats of the audio stream.
SetGetCallback Set a callback that runs when data is requested from an audio stream.
SetPutCallback Set a callback that runs when data is added to an audio stream.
Unbind Unbinds this audio stream from its audio device.
Unlock Unlock the audio stream for serialized access.

Property Descriptions

Available

The number of converted/resampled bytes available.

The stream may be buffering data behind the scenes until it has enough to resample correctly, so this number might be lower than what you expect, or even be zero. Add more data or flush the stream if you need the data now.

If the stream has so much data that it would overflow an int, the return value is clamped to a maximum value, but no queued data is lost; if there are gigabytes of data queued, the app might need to read some of it with GetData before this function's return value is no longer clamped.

property Available: Integer read GetAvailable

Type: Integer

Exceptions

ESdlError: Raised on failure.

See Also

Remarks

It is safe to use this property from any thread


Device

The currently-bound device of the stream

This reports the audio device that an audio stream is currently bound to.

If not bound, or invalid, this returns zero, which is not a valid device ID.

property Device: TSdlAudioDevice read GetDevice

Type: TSdlAudioDevice

See Also

Remarks

It is safe to use this property from any thread


FrequencyRatio

The frequency ratio of the audio stream.

The frequency ratio is used to adjust the rate at which input data is consumed. Changing this effectively modifies the speed and pitch of the audio. A value greater than 1.0 will play the audio faster, and at a higher pitch. A value less than 1.0 will play the audio slower, and at a lower pitch.

This is applied during GetData, and can be continuously changed to create various effects.

property FrequencyRatio: Single read GetFrequencyRatio write SetFrequencyRatio

Type: Single

Exceptions

ESdlError: Raised on failure.

Remarks

It is safe to use this property from any thread


Gain

The gain of an audio stream.

The gain of a stream is its volume; a larger gain means a louder output, with a gain of zero being silence.

Audio streams default to a gain of 1.0 (no change in output).

This is applied during GetData, and can be continuously changed to create various effects.

property Gain: Single read GetGain write SetGain

Type: Single

Exceptions

ESdlError: Raised on failure.

Remarks

It is safe to use this property from any thread


InputChannelMap

Get the current input channel map of the audio stream.

Channel maps are optional; most things do not need them, instead passing data in the order that SDL expects.

Audio streams default to no remapping applied. This is represented by returning nil, and does not signify an error.

The input channel map reorders data that is added to a stream via PutData. Future calls to PutData must provide data in the new channel order.

Each item in the array represents an input channel, and its value is the channel that it should be remapped to. To reverse a stereo signal's left and right values, you'd have an array of { 1, 0 }. It is legal to remap multiple channels to the same thing, so { 1, 1 } would duplicate the right channel to both channels of a stereo signal. An element in the channel map set to -1 instead of a valid channel will mute that channel, setting it to a silence value.

You cannot change the number of channels through a channel map, just reorder/mute them.

Data that was previously queued in the stream will still be operated on in the order that was current when it was added, which is to say you can put the end of a sound file in one order to a stream, change orders for the next sound file, and start putting that new data while the previous sound file is still queued, and everything will still play back correctly.

Audio streams default to no remapping applied. Passing a nil channel map is legal, and turns off remapping.

If the length of the array is not equal to the current number of channels in the audio stream's format, this will fail. This is a safety measure to make sure a race condition hasn't changed the format while this call is setting the channel map.

Unlike attempting to change the stream's format, the input channel map on a stream bound to a recording device is permitted to change at any time; any data added to the stream from the device after this call will have the new mapping, but previously-added data will still have the prior mapping.

property InputChannelMap: TArray<Integer> read GetInputChannelMap write SetInputChannelMap

Type: TArray<Integer>

Remarks

It is safe to use this property from any thread


IsPaused

Whether the audio device associated with a stream is paused.

Unlike in SDL2, audio devices start in an unpaused state, since an app has to bind a stream before any audio will flow.

You can also set this property to pause/unpause the stream.

property IsPaused: Boolean read GetIsPaused write SetIsPaused

Type: Boolean

Exceptions

ESdlError: Raised on failure.

See Also

Remarks

It is safe to use this property from any thread


OutputChannelMap

Get the current output channel map of the audio stream.

Channel maps are optional; most things do not need them, instead passing data in the order that SDL expects.

Audio streams default to no remapping applied. This is represented by returning nil, and does not signify an error.

The output channel map reorders data that leaving a stream via GetData.

Each item in the array represents an input channel, and its value is the channel that it should be remapped to. To reverse a stereo signal's left and right values, you'd have an array of { 1, 0 }. It is legal to remap multiple channels to the same thing, so { 1, 1 } would duplicate the right channel to both channels of a stereo signal. An element in the channel map set to -1 instead of a valid channel will mute that channel, setting it to a silence value.

You cannot change the number of channels through a channel map, just reorder/mute them.

The output channel map can be changed at any time, as output remapping is applied during GetData.

Audio streams default to no remapping applied. Passing a nil channel map is legal, and turns off remapping.

If the length of the array is not equal to the current number of channels in the audio stream's format, this will fail. This is a safety measure to make sure a race condition hasn't changed the format while this call is setting the channel map.

Unlike attempting to change the stream's format, the output channel map on a stream bound to a recording device is permitted to change at any time; any data added to the stream after this call will have the new mapping, but previously-added data will still have the prior mapping. When the channel map doesn't match the hardware's channel layout, SDL will convert the data before feeding it to the device for playback.

property OutputChannelMap: TArray<Integer> read GetOutputChannelMap write SetOutputChannelMap

Type: TArray<Integer>

Remarks

It is safe to use this property from any thread


Properties

The properties associated with an audio stream.

property Properties: TSdlProperties read GetProperties

Type: TSdlProperties

Exceptions

ESdlError: Raised on failure.

Remarks

It is safe to use this property from any thread


Queued

Get the number of bytes currently queued.

This is the number of bytes put into a stream as input, not the number that can be retrieved as output. Because of several details, it's not possible to calculate one number directly from the other. If you need to know how much usable data can be retrieved right now, you should use Available.

Note that audio streams can change their input format at any time, even if there is still data queued in a different format, so the returned byte count will not necessarily match the number of sample frames available. Users of this API should be aware of format changes they make when feeding a stream and plan accordingly.

Queued data is not converted until it is consumed by GetData, so this value should be representative of the exact data that was put into the stream.

If the stream has so much data that it would overflow an int, the return value is clamped to a maximum value, but no queued data is lost; if there are gigabytes of data queued, the app might need to read some of it with GetData before this function's return value is no longer clamped.

property Queued: Integer read GetQueued

Type: Integer

Exceptions

ESdlError: Raised on failure.

See Also

Remarks

It is safe to use this property from any thread


Constructor Descriptions

Create

Convenience constructor for straightforward audio init for the common case.

If all your app intends to do is provide a single source of PCM audio, this constructor allows you to do all your audio setup in a single call.

This is also intended to be a clean means to migrate apps from SDL2.

This constructor will open an audio device, create a stream and bind it. Unlike other methods of setup, the audio device will be closed when this stream is destroyed, so the app can treat the returned stream as the only object needed to manage audio playback.

Also unlike other functions, the audio device begins paused. This is to map more closely to SDL2-style behavior, since there is no extra step here to bind a stream to begin audio flowing. The audio device should be resumed with Resume.

This constructor works with both playback and recording devices.

The ASpec parameter represents the app's side of the audio stream. That is, for recording audio, this will be the output format, and for playing audio, this will be the input format. If spec is nil, the system will choose the format, and the app can use GetFormat to obtain this information later.

If you don't care about opening a specific audio device, you can (and probably should), use TSdlAudioDeviceID.DefaultPlaybackDevice for playback and TSdlAudioDeviceID.DefaultRecordingDevice for recording.

One can optionally provide a callback function; if nil, the app is expected to queue audio data for playback (or unqueue audio data if capturing). Otherwise, the callback will begin to fire once the device is unpaused.

Destroying the returned stream with Free will also close the audio device associated with this stream.

constructor Create(const ADeviceID: TSdlAudioDeviceID; const ASpec: PSdlAudioSpec = nil; const ACallback: TSdlAudioStreamCallback = nil; const AUserData: Pointer = nil); overload

Parameters

ADeviceID: TSdlAudioDeviceID : An audio device to open, or TSdlAudioDeviceID.DefaultPlaybackDevice or TSdlAudioDeviceID.DefaultRecordingDevice.

ASpec: PSdlAudioSpec = nil : (Optional) Audio stream's data format. Can be nil.

ACallback: TSdlAudioStreamCallback = nil : (Optional) Callback where the app will provide new data for playback, or receive new data for recording. Can be nil, in which case the app will need to call PutData or GetData as necessary.

AUserData: Pointer = nil : (Optional) App-controlled pointer passed to callback. Can be nil. Ignored if callback is nil.

Exceptions

ESdlError: Raised on failure.

See Also

Remarks

It is safe to call this constructor from any thread


Create

Create a new audio stream.

constructor Create(const ASrcSpec, ADstSpec: TSdlAudioSpec); overload

Parameters

ASrcSpec: TSdlAudioSpec : The format details of the input audio.

ADstSpec: TSdlAudioSpec : The format details of the output audio.

Exceptions

ESdlError: Raised on failure.

See Also

Remarks

It is safe to call this constructor from any thread


Create

Create a new audio stream.

constructor Create(const ASpec: TSdlAudioSpec); overload

Parameters

ASpec: TSdlAudioSpec : The format details of the (input) audio.

Exceptions

ESdlError: Raised on failure.

See Also

Remarks

It is safe to call this constructor from any thread


Operator Descriptions

Equal(TSdlAudioStream, TSdlAudioStream)

Used to compare against another TSdlAudioStream.

class operator Equal(const ALeft, ARight: TSdlAudioStream): Boolean; inline; static

Parameters

ALeft: TSdlAudioStream

ARight: TSdlAudioStream

Returns

Boolean


Equal(TSdlAudioStream, Pointer)

Used to compare against nil.

class operator Equal(const ALeft: TSdlAudioStream; const ARight: Pointer): Boolean; inline; static

Parameters

ALeft: TSdlAudioStream

ARight: Pointer

Returns

Boolean


Implicit(Pointer)

Used to set the value to nil.

class operator Implicit(const AValue: Pointer): TSdlAudioStream; inline; static

Parameters

AValue: Pointer

Returns

TSdlAudioStream


NotEqual(TSdlAudioStream, TSdlAudioStream)

Used to compare against another TSdlAudioStream.

class operator NotEqual(const ALeft, ARight: TSdlAudioStream): Boolean; inline; static

Parameters

ALeft: TSdlAudioStream

ARight: TSdlAudioStream

Returns

Boolean


NotEqual(TSdlAudioStream, Pointer)

Used to compare against nil.

class operator NotEqual(const ALeft: TSdlAudioStream; const ARight: Pointer): Boolean; inline; static

Parameters

ALeft: TSdlAudioStream

ARight: Pointer

Returns

Boolean


Method Descriptions

Clear

Clear any pending data in the stream.

This drops any queued data, so there will be nothing to read from the stream until more is added.

procedure Clear; inline

Exceptions

ESdlError: Raised on failure.

See Also

Remarks

It is safe to call this method from any thread


Flush

Tell the stream that you're done sending data, and anything being buffered should be converted/resampled and made available immediately.

It is legal to add more data to a stream after flushing, but there may be audio gaps in the output. Generally this is intended to signal the end of input, so the complete output becomes available.

procedure Flush; inline

Exceptions

ESdlError: Raised on failure.

See Also

Remarks

It is safe to call this method from any thread


Free

Free the audio stream.

This will release all allocated data, including any audio that is still queued. You do not need to manually clear the stream first.

If this stream was bound to an audio device, it is unbound during this call. If this stream was created using a device, the audio device that was opened alongside this stream's creation will be closed, too.

procedure Free; inline

See Also

Remarks

It is safe to call this method from any thread


GetData(Pointer, Integer)

Get converted/resampled data from the stream.

The input/output data format/channels/samplerate is specified when creating the stream, and can be changed after creation by setting calling SetFormat.

Note that any conversion and resampling necessary is done during this call, and PutData simply queues unconverted data for later. This is different than SDL2, where that work was done while inputting new data to the stream and requesting the output just copied the converted data.

function GetData(const ABuffer: Pointer; const ASize: Integer): Integer; inline

Exceptions

ESdlError: Raised on failure.

Parameters

ABuffer: Pointer : A buffer to fill with audio data.

ASize: Integer : The maximum number of bytes to fill.

Returns

Integer: The number of bytes read from the stream.

See Also

Remarks

It is safe to call this method from any thread, but if the stream has a callback set, the caller might need to manage extra locking.


GetFormat(PSdlAudioSpec, PSdlAudioSpec)

Query the current format of the stream.

procedure GetFormat(const ASrcSpec, ADstSpec: PSdlAudioSpec); inline

Exceptions

ESdlError: Raised on failure.

Parameters

ASrcSpec: PSdlAudioSpec : Where to store the input audio format, or nil if not needed.

ADstSpec: PSdlAudioSpec : Where to store the output audio format, or nil if not needed.

See Also

Remarks

It is safe to call this method from any thread


Lock

Lock the audio stream for serialized access.

Each audio stream has an internal mutex it uses to protect its data structures from threading conflicts. This function allows an app to lock that mutex, which could be useful if registering callbacks on this stream.

One does not need to lock a stream to use in it most cases, as the stream manages this lock internally. However, this lock is held during callbacks, which may run from arbitrary threads at any time, so if an app needs to protect shared data during those callbacks, locking the stream guarantees that the callback is not running while the lock is held.

procedure Lock; inline

Exceptions

ESdlError: Raised on failure.

See Also

Remarks

It is safe to call this method from any thread


Pause

Pause audio playback on the audio device associated with this audio stream.

This method pauses audio processing for a given device. Any bound audio streams will not progress, and no audio will be generated. Pausing one device does not prevent other unpaused devices from running.

Pausing a device can be useful to halt all audio without unbinding all the audio streams. This might be useful while a game is paused, or a level is loading, etc.

procedure Pause; inline

Exceptions

ESdlError: Raised on failure.

See Also

Remarks

It is safe to call this method from any thread


PutData(Pointer, Integer)

Add data to the stream.

This data must match the format/channels/samplerate specified in the latest call to SetFormat, or the format specified when creating the stream if it hasn't been changed.

Note that this call simply copies the unconverted data for later. This is different than SDL2, where data was converted during the Put call and the Get call would just dequeue the previously-converted data.

procedure PutData(const ABuffer: Pointer; const ASize: Integer); inline

Exceptions

ESdlError: Raised on failure.

Parameters

ABuffer: Pointer : A pointer to the audio data to add.

ASize: Integer : The number of bytes to write to the stream.

See Also

Remarks

It is safe to call this method from any thread, but if the stream has a callback set, the caller might need to manage extra locking.


Resume

Unpause audio playback on the audio device associated with this audio stream.

This method unpauses audio processing for a given device that has previously been paused. Once unpaused, any bound audio streams will begin to progress again, and audio can be generated.

Remember, some constructors open the device in a paused state, so this method call is required for audio playback to begin on such device.

procedure Resume; inline

Exceptions

ESdlError: Raised on failure.

See Also

Remarks

It is safe to call this method from any thread


SetFormat(PSdlAudioSpec, PSdlAudioSpec)

Change the input and output formats of the audio stream.

Future calls to and Available and GetData will reflect the new format, and future calls to PutData must provide data in the new input formats.

Data that was previously queued in the stream will still be operated on in the format that was current when it was added, which is to say you can put the end of a sound file in one format to a stream, change formats for the next sound file, and start putting that new data while the previous sound file is still queued, and everything will still play back correctly.

If a stream is bound to a device, then the format of the side of the stream bound to a device cannot be changed (ASrcSpec for recording devices, ADstSpec for playback devices). Attempts to make a change to this side will be ignored, but this will not report an error. The other side's format can be changed.

procedure SetFormat(const ASrcSpec, ADstSpec: PSdlAudioSpec); inline

Exceptions

ESdlError: Raised on failure.

Parameters

ASrcSpec: PSdlAudioSpec : The new format of the audio input or nil to leave it unchanged.

ADstSpec: PSdlAudioSpec : The new format of the audio output or nil to leave it unchanged.

See Also

Remarks

It is safe to call this method from any thread


SetGetCallback(TSdlAudioStreamCallback, Pointer)

Set a callback that runs when data is requested from an audio stream.

This callback is called before data is obtained from the stream, giving the callback the chance to add more on-demand.

The callback can (optionally) call PutData to add more audio to the stream during this call; if needed, the request that triggered this callback will obtain the new data immediately.

The callback's AAdditionalAmount argument is roughly how many bytes of unconverted data (in the stream's input format) is needed by the caller, although this may overestimate a little for safety. This takes into account how much is already in the stream and only asks for any extra necessary to resolve the request, which means the callback may be asked for zero bytes, and a different amount on each call.

The callback is not required to supply exact amounts; it is allowed to supply too much or too little or none at all. The caller will get what's available, up to the amount they requested, regardless of this callback's outcome.

Clearing or flushing an audio stream does not call this callback.

This function obtains the stream's lock, which means any existing callback (get or put) in progress will finish running before setting the new callback.

Setting a nil function turns off the callback.

procedure SetGetCallback(const ACallback: TSdlAudioStreamCallback; const AUserData: Pointer); inline

Exceptions

ESdlError: Raised on failure.

Parameters

ACallback: TSdlAudioStreamCallback : The new callback function to call when data is requested from the stream.

AUserData: Pointer : An opaque pointer provided to the callback for its own personal use.

See Also

Remarks

It is safe to call this method from any thread


SetPutCallback(TSdlAudioStreamCallback, Pointer)

Set a callback that runs when data is added to an audio stream.

This callback is called after the data is added to the stream, giving the callback the chance to obtain it immediately.

The callback can (optionally) call GetData to obtain audio from the stream during this call.

The callback's AAdditionalAmount argument is how many bytes of converted data (in the stream's output format) was provided by the caller, although this may underestimate a little for safety. This value might be less than what is currently available in the stream, if data was already there, and might be less than the caller provided if the stream needs to keep a buffer to aid in resampling. Which means the callback may be provided with zero bytes, and a different amount on each call.

The callback may use Available to see the total amount currently available to read from the stream, instead of the total provided by the current call.

The callback is not required to obtain all data. It is allowed to read less or none at all. Anything not read now simply remains in the stream for later access.

Clearing or flushing an audio stream does not call this callback.

This function obtains the stream's lock, which means any existing callback (get or put) in progress will finish running before setting the new callback.

Setting a nil function turns off the callback.

procedure SetPutCallback(const ACallback: TSdlAudioStreamCallback; const AUserData: Pointer); inline

Exceptions

ESdlError: Raised on failure.

Parameters

ACallback: TSdlAudioStreamCallback : The new callback function to call when data is added to the stream.

AUserData: Pointer : an opaque pointer provided to the callback for its own personal use.

See Also

Remarks

It is safe to call this method from any thread


Unbind

Unbinds this audio stream from its audio device.

procedure Unbind; inline

See Also

Remarks

It is safe to call this method from any thread


Unlock

Unlock the audio stream for serialized access.

This unlocks an audio stream after a call to Lock.

procedure Unlock; inline

Exceptions

ESdlError: Raised on failure.

See Also

Remarks

You should only call this from the same thread that previously called Lock.