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
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
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.