agentsclimarketplace

Matlab play record audio

Skill matlab/matlab-agentic-toolkit/skills-catalog/signal-processing/matlab-play-record-audio

The MATLAB Agentic Toolkit brings trusted MATLAB capabilities to AI agents, making engineering and scientific workflows agent-ready.

Install
npx -y skills add matlab/matlab-agentic-toolkit --skill matlab-play-record-audio

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.

What its author says it does

Copied from the file, not written here

Reference for MATLAB audiostreamer (Audio Toolbox R2025a+). Without this skill, agents consistently default to legacy audioDeviceWriter/audioDeviceReader or base MATLAB sound(), producing less capable code. Use when writing code for audio playback, recording, full-duplex device I/O, real-time audio measurements, or audio I/O processing with callbacks. Also use when debugging audiostreamer errors, dropouts, or latency issues, or migrating from audioDeviceReader, audioDeviceWriter, audioPlayerRecorder, or audioplayer/audiorecorder.

The file declares its own license as MathWorks BSD-3-Clause. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

20.8 KB, as published. Nobody here has run it

audiostreamer — MATLAB Audio Device I/O (R2025a+)

audiostreamer is the unified replacement for audioDeviceWriter, audioDeviceReader, and audioPlayerRecorder. It provides player-only, recorder-only, or full-duplex modes with callbacks, pre-buffering, transport control, and measurement helpers.

Version requirements: audiostreamer requires Audio Toolbox R2025a or later. The start and write methods were added in R2026a.

When to Use

  • Playing audio through a sound card or USB audio device
  • Recording audio from a microphone or audio interface
  • Full-duplex playback + recording (e.g., acoustic measurements, loopback tests)
  • Listing or selecting audio devices and drivers
  • Any workflow that involves audio hardware I/O in MATLAB

When NOT to Use

  • Playing a single isolated soundsound or soundsc is fine for one-shot playback of a short clip with no sequencing. For sequential playback (e.g., before/after comparison), use audiostreamer — its play() calls queue automatically, whereas overlapping sound calls play simultaneously.
  • Code generation (codegen)audiostreamer does not yet support codegen; use legacy APIs if targeting codegen
  • Simulink models — Simulink still uses the existing audio I/O blocks, not audiostreamer
  • Audio Toolbox not available — fall back to sound/soundsc, audioplayer/audiorecorder, or audioDeviceWriter (DSP System Toolbox) if the user lacks Audio Toolbox
  • File I/O only — reading/writing audio files without device playback or recording uses audioread/audiowrite, not this skill
  • DAQ hardware — National Instruments or similar data acquisition devices use DAQ Toolbox and the daq object
  • MIDI-only devices — MIDI control uses mididevice/midicontrols, not audiostreamer

Construction

Use Name-Value pairs for Mode and SampleRate (positional shorthand exists but does not support tab-completion):

The default Mode is "player". You MUST set Mode explicitly if recording — either Mode="recorder" or Mode="full-duplex". Mode is not inferred from other properties like Recorder or RecorderChannels.

as = audiostreamer                                          % default: player mode, 44100 Hz
as = audiostreamer(Mode="player", SampleRate=fs)            % player at fs Hz
as = audiostreamer(Mode="recorder", SampleRate=fs)          % recorder at fs Hz
as = audiostreamer(Mode="full-duplex", SampleRate=fs)       % simultaneous play + record
as = audiostreamer(Mode="full-duplex", SampleRate=48000, Driver="ASIO", ...
    Player="Focusrite USB ASIO", Recorder="Focusrite USB ASIO", ...
    PlayerChannels=[1 2], RecorderChannels=[1 2])

Properties

Device Configuration (set BEFORE streaming starts)

PropertyTypeDefaultNotes
Mode"player" / "recorder" / "full-duplex""player"Set at construction or via property
Driver"DirectSound" / "ASIO" / "WASAPI" (Win); "CoreAudio" (Mac); "ALSA" (Linux)OS defaultOnly set on Windows (Mac/Linux have one driver each). Setting at construction selects the default device for that driver.
PlayerstringSystem default for driverOutput device name. Omit to use the default device for the selected driver.
RecorderstringSystem default for driverInput device name. Omit to use the default device for the selected driver.
SampleRatepositive scalar44100Hz
DeviceBufferSizepositive int or "auto""auto"Fixed for ASIO (use asiosettings).
DeviceBitFormat"single" / "int24" / "int16""int24"int16 on ASIO silently uses int24
PlayerChannelsrow vector or "auto""auto"1-based mapping. "auto" upmixes mono→stereo; for N≥2 channels, opens N channels on the device
RecorderChannelsrow vector11-based mapping. Records 1 channel by default — set e.g. 1:2 for stereo
ExclusiveModeon/off"on"WASAPI only — disables OS mixing/resampling
ConstantLatency"off" / "dropPlayer" / "dropRecorder""off"Full-duplex dropout handling

IMPORTANT: Mode, SampleRate, Driver, DeviceBufferSize, DeviceBitFormat, ExclusiveMode, ConstantLatency, PlayerChannels, and RecorderChannels lock once streaming starts. Call release(as) before changing any of these properties to avoid an automatic release with a warning.

Callback Properties

PropertySignatureTrigger
PlayerFcn@(obj, event)Player buffer drops below PlayerMinSamples
PlayerMinSamplespositive int (default 16384)Threshold for PlayerFcn trigger
RecorderFcn@(obj, event)Recorder buffer exceeds RecorderMinSamples
RecorderMinSamplespositive int (default 1024)Threshold for RecorderFcn trigger
PlayerCompletedFcn@(obj, event)Output queue empties
RecorderCompletedFcn@(obj, event)Fixed-length recording finishes
PlayerUnderrunFcn@(obj, event)Player underrun occurs

ALL callbacks MUST accept exactly 2 arguments. First arg = the audiostreamer object. Second arg = event struct with .Type field. Use @(obj, ~) if you don't need the event.

Event struct fields by type:

  • PlayerFcn: event.Type = "Player", event.NumPlayerSamples
  • RecorderFcn: event.Type = "Recorder", event.NumRecorderSamples
  • PlayerCompletedFcn: event.Type = "PlayerCompleted", event.StreamTime
  • RecorderCompletedFcn: event.Type = "RecorderCompleted", event.StreamTime
  • PlayerUnderrunFcn: event.Type = "PlayerUnderrun", event.SamplesUnderrun

Read-Only Status

PropertyDescription
NumPlayerSamplesSamples currently queued in output buffer
NumRecorderSamplesSamples available to read() without blocking
MaxPlayerChannelsMax output channels on selected device
MaxRecorderChannelsMax input channels on selected device

Methods

Playback

MethodDescription
play(obj, x)Queue x and play. Blocks until output buffer <= PlayerMinSamples (up to PlayerMinSamples samples remain unplayed when it returns). Call waitfor(as) after the last play to ensure complete playback before release.
play(obj, x, "non-blocking")Queue x and return immediately regardless of buffer level.
play(obj)Start PlayerFcn callback loop (no data argument).
write(obj, x)[R2026a+] Queue x to output buffer WITHOUT starting playback. Use with start().
write(obj, x, "non-blocking")[R2026a+] Queue x and return immediately regardless of buffer level.

Recording

MethodDescription
record(obj)Start recording indefinitely. Warns if unread samples remain in the buffer. To avoid: stop(as) (or stop(as, "recorder") in full-duplex), then read(as) to flush. Not needed if samples were already consumed by a callback or read.
record(obj, numSamples)Record exactly numSamples then stop. Same unread-samples warning applies.
read(obj)Return all available recorded samples immediately (non-blocking). Returns empty if none available.
read(obj, numSamples)Blocks until numSamples available, then returns them.

Full-Duplex

MethodDescription
playrec(obj, x)Play x and record simultaneously. Non-blocking — recording continues in the background; retrieve data with read.
playrec(obj, x, numSamples)Play x and record numSamples. Blocking — returns recorded matrix.
playrec(obj)Start callback-driven full-duplex (requires RecorderFcn and/or PlayerFcn).

playrec pauses both player and recorder, queues audio, then resumes both simultaneously for repeatable latency. This is critical for measurements with impzest.

Transport Control

MethodDescription
start(obj)[R2026a+] Start streaming in current mode.
start(obj, Mode="player")[R2026a+] Start only player (full-duplex).
start(obj, Mode="recorder", SamplesToRecord=N)[R2026a+] Start recorder with fixed count.
stop(obj)Stop all streaming. Preserves unread input samples. Resets underrun count (as does getUnderrunCount).
stop(obj, "player"/"recorder"/"both")Stop specific side.
pause(obj) / pause(obj, "player"/"recorder"/"both")Pause with state preservation.
resume(obj) / resume(obj, "player"/"recorder"/"both")Resume from pause.
waitfor(obj) / waitfor(obj, "player"/"recorder"/"both")Block until complete.
release(obj)Stop, flush, close device, tear down. Deletes unread samples.

Query / Diagnostics

MethodDescription
isPlaying(obj)Returns OnOffSwitchState
isRecording(obj)Returns OnOffSwitchState
isPlayerPaused(obj)Returns OnOffSwitchState
isRecorderPaused(obj)Returns OnOffSwitchState
getUnderrunCount(obj)Underrun sample count since last call. Resets counter (as does stop).
getStreamTime(obj)Elapsed stream time in seconds.
getStreamTime(obj, "reset")Reset stream timer.
measureLoopbackLatency(obj)Full-duplex only, single channel. Returns delay in samples.

Static Device Enumeration

audiostreamer.getDrivers()              % Available drivers for this OS
audiostreamer.getPlayerNames()          % All output devices
audiostreamer.getPlayerNames("ASIO")    % Output devices for specific driver
audiostreamer.getRecorderNames()        % All input devices
audiostreamer.getRecorderNames("ASIO")  % Input devices for specific driver
audiostreamer.getAudioDevices()         % Struct array: Name, Driver, MaxRecorderChannels, MaxPlayerChannels, SampleRate (channel counts are int32)

Note: getAudioDevices() returns int32 for MaxRecorderChannels and MaxPlayerChannels. Cast to double() before using these values in UI components (e.g., uispinner Limits) or arithmetic that expects double.

CRITICAL: There is NO setup() Method

The audiostreamer does NOT have a public setup() method. Device initialization happens implicitly on the first play(), record(), playrec(), or start() call. Do NOT call setup() — it will error.

If PlayerFcn is set, the first streaming call invokes it repeatedly to pre-buffer at least 8192 samples (or PlayerMinSamples, whichever is greater) before the device opens.

Common Patterns

Pattern 1: Simple Blocking Measurement (Sweep + IR)

as = audiostreamer(Mode="full-duplex", SampleRate=48000, ...
    PlayerChannels=1, RecorderChannels=1);
x = sweeptone(2, 1, 48000);
y = playrec(as, x, size(x, 1));  % blocking: returns recorded audio
underruns = getUnderrunCount(as);
ir = impzest(x, y);
release(as);

Pattern 2: Non-Blocking Play + Record with waitfor

as = audiostreamer(Mode="full-duplex", SampleRate=48000);
x = sweeptone(3, 2, 48000);
playrec(as, x);          % non-blocking (no output arg)
waitfor(as);             % block until done
y = read(as);            % retrieve recorded data
release(as);

Pattern 3: Pre-Buffered Playback (write + start) — R2026a+

Use write+start when you need to control exactly when playback begins (e.g., synchronized full-duplex start). For simple playback, play(as, signal) achieves the same result — it queues and starts automatically.

as = audiostreamer(Mode="player", SampleRate=48000);
write(as, signal);       % queue without starting
start(as);               % begin playback
waitfor(as);             % wait for completion
release(as);

Pattern 4: Callback-Driven Streaming Player

as = audiostreamer(Mode="player", SampleRate=48000, DeviceBufferSize=1024);
gen = dsp.ColoredNoise("pink", NumChannels=2, SamplesPerFrame=1024);
as.PlayerFcn = @(obj, ~) play(obj, gen());
as.PlayerMinSamples = 4096;
play(as);    % or start(as) [R2026a+] — begins callback loop
% ... later ...
stop(as);
release(as);

Pattern 5: Callback-Driven Level Metering (Recorder)

as = audiostreamer(Mode="recorder", SampleRate=48000);
as.RecorderFcn = @(obj, ~) updateMeter(read(obj));
as.RecorderMinSamples = 1024;
start(as);       % or record(as) before R2026a
% ... meter updates in background ...
stop(as);
release(as);

Pattern 6: Frame-at-a-Time Processing Loop (Full-Duplex)

The most direct replacement for legacy audioDeviceReader/audioDeviceWriter loops. Call start(as) before the loop so that read has samples available.

as = audiostreamer(Mode="full-duplex", SampleRate=48000, RecorderChannels=1:2);
start(as);
for iter = 1:numIterations
    in = read(as, frameLength);      % blocks until frameLength samples available
    out = process(myPlugin, in);
    write(as, out);                  % blocks until buffer has room
end
nUnderruns = getUnderrunCount(as);   % total underruns since last call (resets counter)
release(as);

Before R2026a, use record(as) + play(as, out) instead of start/write.

For player-only (e.g., file input → device output), use play(as, out) with no start needed — play queues and starts automatically.

Pattern 7: Repeated Measurements with Callbacks (Full-Duplex)

as = audiostreamer(Mode="full-duplex", SampleRate=48000, PlayerChannels=1, RecorderChannels=1);
x = sweeptone(2, 1, 48000);
as.RecorderMinSamples = size(x, 1);
as.RecorderFcn = @(obj, ~) processMeasurement(obj, x);
as.PlayerFcn = @(obj, ~) write(obj, x);  % or play(obj, x) before R2026a
as.PlayerMinSamples = size(x, 1);
as.ConstantLatency = "dropPlayer";  % keep in sync for impzest
playrec(as);   % starts callback-driven measurement loop
% ... runs continuously ...
stop(as);
release(as);

Pattern 8: App with Timer-Based GUI Updates

as = audiostreamer(Mode="player", SampleRate=fs, DeviceBufferSize=1024);
as.PlayerFcn = @(obj, ~) play(obj, getNextFrame());
as.PlayerMinSamples = 20 * 1024;
as.PlayerUnderrunFcn = @(~, ev) fprintf("Dropped %d samples\n", ev.SamplesUnderrun);

figTimer = timer(ExecutionMode="fixedRate", Period=0.05, ...
    TimerFcn=@(~,~) updatePlot(as));

play(as);           % starts callback loop
start(figTimer);    % starts GUI updates
% ...
stop(as);
release(as);
stop(figTimer);
delete(figTimer);

In the timer callback, check buffer health before expensive GUI operations:

function updatePlot(as)
    if as.NumPlayerSamples < 0.5 * as.PlayerMinSamples
        return  % skip GUI update to prevent dropout
    end
    % ... update plots ...
    if as.NumPlayerSamples > 0.9 * as.PlayerMinSamples
        drawnow("limitrate");
    end
end

Pattern 9: Full-Duplex with write/start for Control — R2026a+

as = audiostreamer(Mode="full-duplex", SampleRate=48000);
write(as, excitation);                         % queue output
start(as, SamplesToRecord=size(excitation,1)); % start both
waitfor(as, "both");
y = read(as);
release(as);

Teardown Best Practice

release(as) is sufficient — it implicitly stops streaming, flushes buffers, and closes the device. No need to call stop first. However, release discards any unplayed samples — call waitfor(as) first if playback must complete.

waitfor(as);   % ensure all queued audio finishes playing
release(as);

In apps, wrap in try-catch and nil the reference:

try
    release(as);
catch
end
as = [];

The destructor calls release() automatically, but explicit cleanup is preferred in apps to avoid device lock-up. Calling release from within PlayerCompletedFcn is safe and does not deadlock.

Note: isvalid(as) returns true even after release — it cannot be used to detect a released audiostreamer. To track released state, nil the object reference and check with isempty.

ConstantLatency Modes (Full-Duplex)

ValueBehaviorUse For
"off"After dropout, inserts silence frame (latency increases)General use
"dropPlayer"Late output frames dropped; latency stays constantMeasurements with impzest (sweep-based)
"dropRecorder"Input frames dropped; latency constantAdaptive filters (NOT compatible with impzest)

Error Conditions

Error IDCause
audio:device:methodRequiresModesCalling method invalid for current Mode (e.g., record() in player mode). Set Mode to "full-duplex" if you need both playback and recording methods.
audio:device:invalidChannelMapChannel indices exceed device max. Check MaxPlayerChannels or MaxRecorderChannels and adjust mapping.
audio:device:callbackNarginCallback doesn't accept exactly 2 arguments. Use @(obj, ~) or @(obj, event) signature.
audio:device:playrecRecorderFcnConflictplayrec called with output argument while RecorderFcn is set — callback consumes samples via read(), leaving nothing for the return value. Clear RecorderFcn before blocking playrec.
audio:device:startModePlayerNotValidstart(Mode="player") in recorder-only mode
audio:device:startModeRecorderNotValidstart(Mode="recorder") in player-only mode
MATLAB:validators:mustBeFiniteAudio data contains NaN or Inf
MATLAB:validators:mustBeRealAudio data is complex

audiostreamer vs. Legacy Audio APIs

audiostreamer is strongly preferred for all audio device I/O when Audio Toolbox is available. Legacy alternatives may be useful as fallbacks when Audio Toolbox is not installed or in edge cases.

Legacy APILimitationaudiostreamer Equivalent
audiodevinfoDoes not support ASIO; incomplete device listaudiostreamer.getAudioDevices(), audiostreamer.getPlayerNames(), etc.
audioplayer / audiorecorderNo ASIO/WASAPI exclusive; limited driver model; no callbacksaudiostreamer in player/recorder/full-duplex mode
sound / soundscCreates an audioplayer under the hood; concurrent calls overlap (do NOT queue)audiostreamer with play() for sequential playback
audioDeviceWriter / audioDeviceReaderSeparate objects; no callbacks; no pre-buffering; frame-at-a-time loops onlySingle audiostreamer object with blocking/non-blocking modes
audioPlayerRecorderLimited full-duplex; no transport control; no latency measurementplayrec, measureLoopbackLatency, start/stop/pause/resume

audiodevreset is fine to call — it resets the audio subsystem and can help recover from device errors regardless of which API you use.

When sound/soundsc is acceptable: Only for a single isolated playback with no sequencing. If you need to play two clips back-to-back (e.g., before/after comparison), use audiostreamer — its play() calls queue automatically.

Migration Pitfalls (audioDeviceReader/Writer → audiostreamer)

LegacyaudiostreamerGotcha
audioDeviceReader with NumChannels=2RecorderChannels=1:2audiostreamer records 1 channel by default. You must set RecorderChannels explicitly for stereo/multichannel.
audioDeviceWriter returns underrun count per framegetUnderrunCount(as) after loopplay() has no return value. Call getUnderrunCount when you need the total — it resets the counter each call.
audioDeviceReader returns overrun count per frameNo equivalent neededaudiostreamer buffers all recorded samples internally — recorder cannot overrun.
Device='Default'Omit Player/RecorderNo "Default" string — omitting the property selects the system default for the current driver.
[data, nOverrun] = deviceReader()record(as) then data = read(as, N)Must call record(as) (or start(as) [R2026a+]) before the loop — otherwise read blocks forever waiting for samples.
Two separate objects for reader+writerSingle audiostreamer(Mode="full-duplex")One object handles both directions. Use two separate objects if devices require different drivers or conflict when opened together.

Diagnostics

For debugging streaming issues, enable the diagnostic trace:

as = audiostreamer(Mode="full-duplex", SampleRate=44100);
as.TraceEnabled = true;   % logs internal timing and buffer state

Copyright 2026 The MathWorks, Inc.


Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.