This repository contains a single-channel adaptive feedback canceller implemented as a MATLAB audio plugin using Audio Toolbox. The plugin suppresses acoustic feedback between a loudspeaker and microphone by running a Normalized Least Mean Squares (NLMS) adaptive filter. The two test benches let you validate the algorithm either in a fully reproducible simulation with a simple virtual feedback path or in a real microphone-speaker setup.
- NLMS adaptive filter with configurable order, step size, and input gain
- MATLAB Audio Test Bench integration for quick auditioning and plugin export
- Offline simulation test bench with virtual feedback path and controlled excitation signals
- Real-time test bench for hardware-in-the-loop evaluation with live audio
- Visualization of signals, metrics (ERLE/attenuation), and filter coefficient evolution
- MATLAB R2023a or later
- Audio Toolbox
- An audio interface, microphone, and loudspeaker for the real-time test bench
AFCPlugin.m— MATLAB audio plugin implementationTestbench_Simulation.m— offline experiment with a configurable virtual feedback pathTestbench_Realtime.m— hardware-in-the-loop evaluation scriptdata/— helper assets and captured logs (e.g.,speech.mp3)figures/— diagrams used in this README
A microphone signal in a feedback loop can be modeled as
x[n] = s[n] + f[n]
where s[n] is the desired near-end signal and f[n] is the acoustic feedback contribution. The adaptive filter estimates the feedback term f_hat[n] from a block-delayed version of the microphone signal and subtracts it from the microphone input to yield the error signal:
e[n] = x[n] - f_hat[n]
The error signal is the output of the plugin and ideally contains only the near-end signal s[n]. The adaptive filter coefficients are updated in real time to minimize the power of e[n],
effectively learning the impulse response of the acoustic path between loudspeaker and microphone.
The plugin implements the NLMS update rule:
w[n+1] = w[n] + (μ * e[n] * r[n]) / (‖r[n]‖² + ε)
where w[n] are the filter coefficients, r[n] is the reference signal (previous microphone block), μ is the step size and ε = 1e-5 is a small constant to prevent division by zero. The filter order is adjustable between 64 and 8192 taps so you can match the expected length of the acoustic path impulse response.
AFCPlugin derives from audioPlugin and exposes three user parameters:
InputGain(−96 to +12 dB) — gain applied to the microphone input before processing (defaults to 0 dB)FilterOrder(64…8192 taps) — length of the NLMS filter (defaults to 64 taps)StepSize(0.001…1.0) — convergence/sharpness of the filter adaptation (defaults to 0.001)
Internally the plugin maintains the current filter coefficients, a circular buffer of past samples, and the previous block that acts as the reference signal. The process method iterates each block sample-by-sample, generates the estimated feedback, applies the NLMS weight update, and emits the error e[n]. As a safety measure, the output block is normalized if clipping is detected.
The quickest way to inspect the plugin GUI and tweak parameters is MATLAB’s Audio Test Bench:
audioTestBench(AFCPlugin)From there you can route audio between available devices, monitor the signal in real time, inspect levels and spectra, and export the plugin as a VST3/AU binary if you want to evaluate it in a DAW.
Testbench_Simulation.m lets you run controlled experiments without a physical setup:
- Open the script and adjust the parameters at the top. Key options include sample rate, block size, virtual feedback gain/delay, excitation type (
white_noise,chirp, orspeechfromdata/input/speech.mp3), filter order, and NLMS step size. - Run the script. It instantiates the plugin, simulates a feedback loop by delaying and scaling the previous output, and feeds the combined microphone signal into the AFC algorithm.
- Inspect the generated plots: source/output/residual signals, ERLE per block, and the final filter coefficients plus their evolution (
imagescheatmap). - The results are saved to a
.matfile in thedata/directory, which contain the source, processed output, residual, ERLE, and filter coefficient history for later inspection.
This script is ideal for verifying convergence, tuning FilterOrder/StepSize, and reproducing bugs as every run is deterministic.
Testbench_Realtime.m can be used to test the plugin in a physical microphone-loudspeaker setup. Before running it:
- Connect a loudspeaker and microphone that form the feedback loop. Use conservative monitor levels.
- Set
audioInterfaceto the exact name of your audio interface reported byaudioDeviceInfo. - Adjust parameters at the top of the script (
blockSize,filterOrder,stepSizeetc.).- Optional: set
externalExcitationto false if you want to use an internally generated source signal to test the setup (as in the simulation) instead of using an external sound source.
- Optional: set
- Run the script. It streams audio using
audioDeviceReader/audioDeviceWriter, logs overruns/underruns, and computes a block-wise attenuation metric (proxy for ERLE when no separate reference to the isolated feedback component is available). - The same plots as in the simulation will be generated (except for the residual and ERLE which are replaced by the attenuation metric) and the results are similarly saved to a
.matfile in thedata/directory.
- Start with low speaker volume and gradually increase it to avoid instability and loud howling feedback.
- The real-time attenuation metric only approximates ERLE because the true feedback component is unknown.
- Performance depends heavily on filter order, step size, and block size relative to the acoustic path; long rooms may require thousands of taps.
- Noise injection, double-talk detection, and multi-channel support are natural next steps if you want to extend the project.
- This implementation is very much a proof-of-concept; production-grade AFC systems require more robust techniques and optimizations.
This project is licensed under the MIT License — see the LICENSE file for details.