Main Content

audioDeviceWriter

Play to sound card

Description

The audioDeviceWriter System object™ writes audio samples to an audio output device. Properties of the audio device writer specify the driver, the device, and device attributes such as sample rate, bit depth, and buffer size.

See Audio I/O: Buffering, Latency, and Throughput for a detailed explanation of the audio device writer data flow.

To stream data to an audio device:

  1. Create the audioDeviceWriter object and set its properties.

  2. Call the object with arguments, as if it were a function.

To learn more about how System objects work, see What Are System Objects?

Creation

Description

deviceWriter = audioDeviceWriter returns a System object, deviceWriter, that writes audio samples to an audio output device in real time.

deviceWriter = audioDeviceWriter(sampleRateValue) sets the SampleRate property to sampleRateValue.

deviceWriter = audioDeviceWriter(___,Name,Value) sets each property Name to the specified Value. Unspecified properties have default values.

Example: deviceWriter = audioDeviceWriter(48000,'BitDepth','8-bit integer') creates a System object, deviceWriter, that operates at a 48 kHz sample rate and an 8-bit integer bit depth.

Properties

expand all

Unless otherwise indicated, properties are nontunable, which means you cannot change their values after calling the object. Objects lock when you call them, and the release function unlocks them.

If a property is tunable, you can change its value at any time.

For more information on changing property values, see System Design in MATLAB Using System Objects.

Driver used to access your audio device, specified as 'DirectSound', 'ASIO', or 'WASAPI'.

  • ASIO™ drivers do not come pre-installed on Windows® machines. To use the 'ASIO' driver option, install an ASIO driver outside of MATLAB®.

    Note

    If Driver is specified as 'ASIO', use asiosettings to set the sound card buffer size to the buffer size of your audioDeviceWriter System object.

  • WASAPI drivers are supported for exclusive-mode only.

ASIO and WASAPI drivers do not provide sample rate conversion. For ASIO and WASAPI drivers, set SampleRate to a sample rate supported by your audio device.

This property applies only on Windows machines. Linux® machines always use the ALSA driver. Mac machines always use the CoreAudio driver.

To specify nondefault Driver values, you must have an Audio Toolbox™ license.

Data Types: char | string

Device used to play audio samples, specified as a character vector or string scalar. Use getAudioDevices to list available devices for the selected driver.

Data Types: char | string

Sample rate of signal sent to audio device, in Hz, specified as a positive integer. The range of SampleRate depends on your audio hardware.

Data Types: single | double | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64

Data type used by the device, specified as a character vector or string scalar. Before performing digital-to-analog conversion, the input data is cast to a data type specified by BitDepth.

To specify a nondefault BitDepth, you must have an Audio Toolbox license.

Data Types: char | string

Option to support variable frame size, specified as true or false.

  • false –– If the audioDeviceWriter object is locked, the input must have the same frame size at each call. The buffer size of your audio device is the same as the input frame size.

  • true –– If the audioDeviceWriter object is locked, the input frame size can change at each call. The buffer size of your audio device is specified through the BufferSize property.

Data Types: char

Buffer size of audio device, specified as a positive integer.

Note

If Driver is specified as 'ASIO', open the ASIO UI to set the sound card buffer size to the BufferSize value of your audioDeviceWriter System object.

Dependencies

To enable this property, set SupportVariableSizeInput to true.

Data Types: single | double | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64

Source of mapping between columns of input matrix and channels of audio output device, specified as 'Auto' or 'Property'.

  • 'Auto' –– Default settings determine the mapping between columns of input matrix and channels of audio output device. For example, suppose that your input is a matrix with four columns, and your audio device has four channels available. Column 1 of your input data writes to channel 1 of your device, column 2 of your input data writes to channel 2 of your device, and so on.

  • 'Property' –– The ChannelMapping property determines the mapping between columns of input matrix and channels of audio output device.

Data Types: char | string

Nondefault mapping between columns of input matrix and channels of output device, specified as a scalar or vector of valid channel indices. See the Specify Channel Mapping for audioDeviceWriter example for more information.

To selectively map between columns of the input matrix and your sound card's output channels, you must have an Audio Toolbox license.

Dependencies

To enable this property, set ChannelMappingSource to 'Property'.

Data Types: single | double | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64

Usage

Description

numUnderrun = deviceWriter(audioToDevice) writes one frame of audio samples, audioToDevice, to the selected audio device and returns the number of audio samples underrun since the last call to deviceWriter.

example

Note:  When you call the audioDeviceWriter System object, the audio device specified by the Device property is locked. An audio device can be locked by only one audioDeviceWriter at a time. To release the audio device, call release on your audioDeviceWriter System object.

Input Arguments

expand all

Audio signal to write to device, specified as a matrix. The columns of the matrix are treated as independent audio channels.

If audioToDevice is of data type 'double' or 'single', the audio device writer clips values outside the range [–1, 1]. For other data types, the allowed input range is [min, max] of the specified data type.

Data Types: single | double | int16 | int32 | uint8

Output Arguments

expand all

Number of samples by which the audio device writer queue was underrun since the last call to deviceWriter.

Data Types: uint32

Object Functions

To use an object function, specify the System object as the first input argument. For example, to release system resources of a System object named obj, use this syntax:

release(obj)

expand all

getAudioDevicesList available audio devices
infoGet audio device information
cloneCreate duplicate System object
isLockedDetermine if System object is in use
releaseRelease resources and allow changes to System object property values and input characteristics
resetReset internal states of System object
stepRun System object algorithm
setupOne-time set up tasks for System objects

Examples

collapse all

Read an MP3 audio file and play it through your default audio output device.

Create a dsp.AudioFileReader object with default settings. Use the audioinfo function to return a structure containing information about the audio file.

fileReader = dsp.AudioFileReader('speech_dft.mp3');
fileInfo = audioinfo('speech_dft.mp3')
fileInfo = struct with fields:
             Filename: '/mathworks/devel/bat/filer/batfs2566-0/Bdoc24b.2725827/build/runnable/matlab/toolbox/dsp/dsp/samples/speech_dft.mp3'
    CompressionMethod: 'MP3'
          NumChannels: 1
           SampleRate: 22050
         TotalSamples: 112320
             Duration: 5.0939
                Title: []
              Comment: []
               Artist: []
              BitRate: 64

Create an audioDeviceWriter object and specify the sample rate.

deviceWriter = audioDeviceWriter('SampleRate',fileInfo.SampleRate);

Call setup to reduce the computational load of initialization in an audio stream loop.

setup(deviceWriter,zeros(fileReader.SamplesPerFrame,...
    fileInfo.NumChannels))

Use the info function to obtain the characteristic information about the device writer.

info(deviceWriter)
ans = struct with fields:
                   Driver: 'ALSA'
               DeviceName: 'ALSAdefault'
    MaximumOutputChannels: 32

In an audio stream loop, read an audio signal frame from the file, and write the frame to your device.

while ~isDone(fileReader)
    audioData = fileReader();
    deviceWriter(audioData);
end

Close the input file and release the device.

release(fileReader)
release(deviceWriter)

Latency due to the output device buffer is the time delay of writing one frame of data. Modify default properties of your audioDeviceWriter System object™ to reduce latency due to device buffer size.

Create a dsp.AudioFileReader System object to read an audio file with default settings.

fileReader = dsp.AudioFileReader('speech_dft.mp3');

Create an audioDeviceWriter System object and specify the sample rate to match that of the audio file reader.

deviceWriter = audioDeviceWriter(...
    'SampleRate',fileReader.SampleRate);

Calculate the latency due to your device buffer, in seconds.

bufferLatency = fileReader.SamplesPerFrame/deviceWriter.SampleRate %#ok
bufferLatency = 
0.0464

Set the SamplesPerFrame property of your dsp.AudioFileReader System object to 256. Calculate the buffer latency in seconds.

fileReader.SamplesPerFrame = 256;
bufferLatency = fileReader.SamplesPerFrame/deviceWriter.SampleRate
bufferLatency = 
0.0116

Underrun refers to output signal silence, which occurs when the audio stream loop does not keep pace with the output device. Determine the underrun of an audio stream loop, add artificial computational load to the audio stream loop, and then modify properties of your audioDeviceWriter object to decrease underrun. Your results depend on your computer.

Create a dsp.AudioFileReader object, and specify the file to read. Use the audioinfo function to return a structure containing information about the audio file.

fileReader = dsp.AudioFileReader('speech_dft.mp3');
fileInfo = audioinfo('speech_dft.mp3');

Create an audioDeviceWriter object. Use the SampleRate of the file reader as the SampleRate of the device writer. Call setup to reduce the computational load of initialization in an audio stream loop.

deviceWriter = audioDeviceWriter('SampleRate',fileReader.SampleRate);
setup(deviceWriter,zeros(fileReader.SamplesPerFrame,...
    fileInfo.NumChannels))

Run your audio stream loop with input from file and output to device. Print the total samples underrun and the underrun in seconds.

totalUnderrun = 0;
while ~isDone(fileReader)
    input = fileReader();
    numUnderrun = deviceWriter(input);
    totalUnderrun = totalUnderrun + numUnderrun;
end
fprintf('Total samples underrun: %d.\n',totalUnderrun)
Total samples underrun: 0.
fprintf('Total seconds underrun: %d.\n',double(totalUnderrun)/double(deviceWriter.SampleRate))
Total seconds underrun: 0.

Release your dsp.AudioFileReader and audioDeviceWriter objects and set your counter variable to zero.

release(fileReader)
release(deviceWriter)
totalUnderrun = 0;

Use pause to mimic an algorithm that takes 0.075 seconds to process. The pause causes the audio stream loop to go slower than the device, which results in periods of silence in the output audio signal.

while ~isDone(fileReader)
    input = fileReader();
    numUnderrun = deviceWriter(input);
    totalUnderrun = totalUnderrun + numUnderrun;
    pause(0.075)
end
fprintf('Total samples underrun: %d.\n',totalUnderrun)
Total samples underrun: 68608.
fprintf('Total seconds underrun: %d.\n',double(totalUnderrun)/double(deviceWriter.SampleRate))
Total seconds underrun: 3.111474e+00.

Release your audioDeviceReader and dsp.AudioFileWriter and set the counter variable to zero.

release(fileReader)
release(deviceWriter)
totalUnderrun = 0;

Set the frame size of your audio stream loop to 2048. Because the SupportVariableSizeInput property of your audioDeviceWriter System object is set to false, the buffer size of your audio device is the same size as the input frame size. Increasing your device buffer size decreases underrun.

fileReader = dsp.AudioFileReader('speech_dft.mp3');
fileReader.SamplesPerFrame = 2048;
fileInfo = audioinfo('speech_dft.mp3');

deviceWriter = audioDeviceWriter('SampleRate',fileReader.SampleRate);
setup(deviceWriter,zeros(fileReader.SamplesPerFrame,fileInfo.NumChannels))

Calculate the total underrun.

while ~isDone(fileReader)
    input = fileReader();
    numUnderrun = deviceWriter(input);
    totalUnderrun = totalUnderrun + numUnderrun;
    pause(0.075)
end
fprintf('Total samples underrun: %d.\n',totalUnderrun)
Total samples underrun: 0.
fprintf('Total seconds underrun: %d.\n',double(totalUnderrun)/double(deviceWriter.SampleRate))
Total seconds underrun: 0.

The increased frame size reduces the total underrun of your audio stream loop. However, increasing the frame size also increases latency. Other approaches to reduce underrun include:

  • Increasing the buffer size independent of input frame size. To increase buffer size independent of input frame size, you must first set SupportVariableSizeInput to true. This approach also increases latency.

  • Decreasing the sample rate. Decreasing the sample rate reduces both latency and underrun at the cost of signal resolution.

  • Choosing an optimal driver and device for your system.

Specify nondefault channel mapping for an audioDeviceWriter object. This example is hardware specific. It assumes that your computer has a default audio output device with two available channels.

Create an audioDeviceWriter object with default settings.

deviceWriter = audioDeviceWriter;

By default, the audioDeviceWriter object writes the maximum number of channels available, corresponding to the columns of the input matrix. Use info to get the maximum number of channels of your device.

info(deviceWriter)
ans = struct with fields:
                   Driver: 'DirectSound'
               DeviceName: 'Primary Sound Driver'
    MaximumOutputChannels: 2

If deviceWriter is called with one column of data, two channels are written to your audio output device. Both channels correspond to the one column of data.

Use the audioOscillator object to output a tone to your audioDeviceWriter object. Your object, sineGenerator, returns a vector when called.

sineGenerator = audioOscillator;

Write the sine tone to your audio device. If you are using headphones, you can hear the tone from both channels.

count = 0;
while count < 500
    sine = sineGenerator();
    deviceWriter(sine);
    count = count + 1;
end

If your audioDeviceWriter object is called with two columns of data, two channels are written to your audio output device. The first column corresponds to channel 1 of your audio output device, and the second column corresponds to channel 2 of your audio output device.

Write a two-column matrix to your audio output device. Column 1 corresponds to the sine tone, and column 2 corresponds to a static signal. If you are using headphones, you can hear the tone from one speaker and the static from the other speaker.

count = 0;
while count < 500
    sine = sineGenerator();
    static = randn(length(sine),1);
    deviceWriter([sine,static]);
    count = count + 1;
end

Specify alternative mappings between channels of your device and columns of the output matrix by indicating the output channel number at an index corresponding to the input column. Set ChannelMappingSource to 'Property'. Indicate that the first column of your input data writes to channel 2 of your output device, and that the second column of your input data writes to channel 1 of your output device. To modify the channel mapping, you must first unlock the audioDeviceReader object.

release(deviceWriter)
deviceWriter.ChannelMappingSource = 'Property';
deviceWriter.ChannelMapping = [2,1];

Play your audio signals with reversed mapping. If you are using headphones, notice that the tone and static have switched speakers.

count = 0;
while count < 500
    sine = sineGenerator();
    static = randn(length(sine),1);
    deviceWriter([sine,static]);
    count = count + 1;
end

Extended Capabilities

Version History

Introduced in R2016a

expand all