Skill v1.0.1
currentLLM-judged scan100/100+6 new
version: "1.0.1" name: matlab-write-audio-plugin description: > Guide authoring of Audio Toolbox plugins (audioPlugin, audioPluginSource) that pass validateAudioPlugin and generate deployable VST/AU code. Use when creating audio effect or generator plugins, writing classdef files inheriting from audioPlugin, or troubleshooting validateAudioPlugin failures. license: https://www.mathworks.com/content/dam/mathworks/license/pmrl/license.md metadata: author: MathWorks version: "1.0"
Writing Audio Plugins in MATLAB
When To Use
- Creating audio effect or generator plugins (classdef inheriting from
audioPluginoraudioPluginSource) - Troubleshooting
validateAudioPluginorgenerateAudioPluginfailures - Converting a MATLAB audio algorithm into a deployable VST/AU plugin
- Integrating deep learning inference into a real-time audio plugin
When NOT To Use
- General MATLAB class authoring unrelated to audio plugins
- Audio file I/O, feature extraction, or analysis (no plugin involved)
- Simulink audio processing blocks
- Writing Audio Toolbox functions that are not plugins (e.g.,
audioDatastore,audioFeatureExtractor)
Structure
Every audio plugin is a classdef with %#codegen, public tunable properties, a Constant PluginInterface, and methods process + reset.
classdef MyPlugin < audioPlugin%#codegenpropertiesGain = 0.5Cutoff = 1000endproperties (Access = private)pSR = 44100pB = [1 0 0]pA = [1 0 0]pState = zeros(2, 2) % (filterOrder, numChannels)endproperties (Constant)PluginInterface = audioPluginInterface( ...audioPluginParameter('Gain', ...DisplayName='Gain', Label='dB', Mapping={'lin', 0, 1}), ...audioPluginParameter('Cutoff', ...DisplayName='Cutoff', Label='Hz', Mapping={'log', 20, 20000}), ...InputChannels=2, OutputChannels=2)endmethodsfunction y = process(plugin, x)[y, plugin.pState] = filter(plugin.pB, plugin.pA, x, plugin.pState);y = y * plugin.Gain;endfunction reset(plugin)plugin.pSR = getSampleRate(plugin);plugin.pState = zeros(2, 2);designFilter(plugin);endfunction set.Cutoff(plugin, val)plugin.Cutoff = val;designFilter(plugin); %#ok<MCSUP>endendmethods (Access = private)function designFilter(plugin)wn = plugin.Cutoff / (plugin.pSR / 2);wn = max(eps, min(wn, 1 - eps));[plugin.pB, plugin.pA] = butter(2, wn);endendend
Source plugins inherit audioPluginSource, omit InputChannels, and process takes no audio input — use getSamplesPerFrame(plugin) for output frame size.
System Object hybrids (matlab.System & audioPlugin) require (StrictDefaults), isInputSizeMutableImpl returning true, and stepImpl/resetImpl instead of process/reset. Use only when user requests Simulink compatibility.
Plugin Lifecycle
- Constructor — Construct all sub-objects with literal arguments.
getSampleRatereturns 44100 here; use for initial buffer sizing only. - `reset` — Called when sample rate or frame size changes. Cache
getSampleRate(plugin)inpSR. Recompute all SR-dependent values. Callreset()on every sub-object (after setting their sample rate). - `process` — Called per audio frame. Return
doubleoutput sized[N, numOutputChannels]. Never assign to properties registered inaudioPluginParameter— for output meters, keep properties public but unregistered. - Set methods — Recompute derived values (coefficients, buffer sizes) when parameters change. Add
%#ok<MCSUP>only when the set method actually accesses another property throughobj.PropertyNameor calls a method that does (e.g.,designFilter(plugin)fromset.Cutoff). Do not add it preemptively — only suppress warnings that checkcode actually raises on that line. - Save/load (optional, MATLAB-only) — Only needed when the plugin has private state that
resetcannot reconstruct from parameters and sample rate (e.g., loaded data, handle sub-objects with internal buffers). Not compiled into generated VSTs/standalones — DAW hosts persist parameters via the plugin interface and callreseton restore. Seereferences/advanced-patterns.mdfor the pattern.
Codegen Requirements
All code must be codegen-compatible. validateAudioPlugin sweeps 5 sample rates (8000–192000), frame sizes 2.^(1:13)+1 (max 8193), and all parameter extremes.
Always use built-in functions over hand-implementations. Prefer toolbox functions in this order: Audio Toolbox → DSP System Toolbox → Signal Processing Toolbox → base MATLAB. If unsure whether a codegen-compatible built-in exists for an operation, consult references/available-functions.md before implementing manually.
Buffers and State
Pre-allocate all state to maximum needed size. Codegen locks property size from the constructor's last assignment — allocate at the maximum the parameter can reach, then index into the active region at runtime.
Shift with indexed assignment:
buf(1:end-N) = buf(N+1:end); % shift left by Nbuf(end-N+1:end) = newData; % fill tail
Never concatenate to shift — [buf(N+1:end); zeros(N,ch)] produces a variable-size result that codegen rejects on assignment to a fixed-size property.
Never use : on the column dimension when assigning to a fixed-size property — codegen treats x(i,:) as variable-size. Index columns explicitly: [x(i,1), x(i,2)].
Initialize arrays that will hold complex values with complex(zeros(...)) — not bare zeros(...). Codegen locks the real/complex attribute from the first assignment. If the array starts real, assigning FFT output into it later fails with "left-hand side constrained to be non-complex."
dsp.AsyncBuffer capacity must exceed the largest single write the plugin will receive. validateAudioPlugin delivers frames up to 8193 samples; account for that plus any overlap when sizing the buffer.
When filter() input comes from a sub-object (e.g., crossoverFilter), codegen cannot propagate the column count — the returned state becomes variable-size. Process channels explicitly:
[low(:,1), plugin.pState(:,1)] = filter(b, a, low(:,1), plugin.pState(:,1));[low(:,2), plugin.pState(:,2)] = filter(b, a, low(:,2), plugin.pState(:,2));
Enum Parameters (Different-Length Values)
Use Style='dropdown' for 3+ values, 'vrocker'/'vtoggle' for exactly 2.
When enum values have different character lengths ('On'/'Off', 'Short'/'VeryLong'), prefer a separate int32 enum class file. The framework can handle char padding internally, but an explicit enum class produces cleaner generated code with typed dispatch instead of string comparisons:
% MyMode.mclassdef MyMode < int32enumerationNormal (0)Aggressive (1)Subtle (2)endend
Plugin property: Mode = MyMode.Normal with Mapping={'enum','Normal','Aggressive','Subtle'}.
Derived Values from Parameters
When computing normalized frequency or delay indices from parameters, clamp the result:
wn = plugin.Cutoff / (plugin.pSR / 2);wn = max(eps, min(wn, 1 - eps)); % keep in valid (0,1) range for butter/cheby
Clamp delay-line read indices to [1, bufferLength]. This prevents out-of-bounds at extreme sample rates or parameter settings that validateAudioPlugin will exercise.
Switch Completeness
Every switch that assigns a variable must include otherwise with a safe default — codegen requires all branches to define the same outputs.
Sub-Objects
Construct with literal arguments in the constructor. In reset, propagate sample rate then reset:
function reset(plugin)fs = getSampleRate(plugin);setSampleRate(plugin.pEcho, fs);reset(plugin.pEcho);plugin.pCompressor.SampleRate = fs;reset(plugin.pCompressor);end
Call sub-plugins as process(plugin.pSub, x). Call System Objects as plugin.pObj(x). Forward parameter changes in set methods.
External Data and Runtime-Only Calls
- Load data files:
coder.load('data.mat')in the constructor — baked into the binary - Guard non-codegen calls: wrap
fprintf/disp/plotinif isempty(coder.target)
Validation
validateAudioPlugin -nomex ClassName % structural + testbenchvalidateAudioPlugin ClassName % full MEX codegengenerateAudioPlugin ClassName % produce VST/AU binary
After validation passes:
- Run
checkcodeon all produced.mfiles — resolve every warning by renaming or restructuring, not by adding%#oksuppressions (except%#ok<MCSUP>in set methods). Re-run checkcode to confirm zero warnings remain. - Verify functional behavior: instantiate,
setSampleRate,reset, process a test signal, confirm output matches intent.
Generation
Default output is VST 2. Use flags to select other formats:
| Flag | Format | Platform | |
|---|---|---|---|
-vst | VST 2 (default) | Windows, macOS | |
-vst3 | VST 3 | Windows, macOS | |
-au | Audio Unit v2 | macOS only | |
-auv3 | Audio Unit v3 | macOS only | |
-exe | Standalone executable | Windows, macOS | |
-juceproject | JUCE project (source code) | All (including Linux) |
When the user requests an output format unavailable on the current platform (e.g., AU on Windows, or any compiled binary on Linux), explain the constraint and suggest the closest alternative (-juceproject on Linux, -vst/-vst3 on Windows instead of AU).
References
references/available-functions.md— Built-in streaming DSP objects (prefer over manual implementations)references/advanced-patterns.md— AsyncBuffer, modulated delay, save/load, codegen edge casesreferences/parameters.md— Mapping laws, multi-bus I/O, grid layout constraintsreferences/grid-layout.md— Grid layout syntax, row allocation withDisplayNameLocationreferences/deep-learning.md— Neural network inference withcoder.loadDeepLearningNetwork
Copyright 2026 The MathWorks, Inc.