
A small C library of DSP (Digital Signal Processing) routines for audio applications.
Read the full documentation – API reference, tutorials, and interactive examples.
What's in the box?
Signal Processing (minidsp.h)
- GCC-PHAT – estimate the time delay between two microphone signals using Generalized Cross-Correlation with Phase Transform. This is the core of acoustic source localisation.
- Magnitude spectrum – compute |X(k)| from a real signal using the FFT; the foundation of frequency-domain analysis.
- Power spectral density – compute |X(k)|^2 / N (periodogram); shows how signal power distributes across frequencies.
- Phase spectrum – compute arg(X(k)) in radians; reveals the timing of each frequency component and is a prerequisite for phase-vocoder effects.
- Spectrogram (STFT) – sliding-window FFT producing a time-frequency magnitude matrix; the standard tool for visualising time-varying audio.
- Signal measurements – energy, power, power in dB, normalised entropy.
- Scaling & AGC – linear range mapping, automatic gain control.
- Hanning window – smooth windowing function for FFT analysis.
- Sine wave generator – pure tone at a given frequency and amplitude; the "hello world" of DSP.
Biquad Filters (biquad.h)
Seven classic audio filter types, all based on Robert Bristow-Johnson's Audio EQ Cookbook:
- Low-pass, High-pass, Band-pass, Notch
- Peaking EQ, Low shelf, High shelf
File I/O (fileio.h)
- Read audio files in any format supported by libsndfile (WAV, FLAC, AIFF, OGG, etc.)
- Write audio to WAV (IEEE float for lossless DSP round-trips)
- Write feature vectors in NumPy
.npy format (for Python interop)
- Write feature vectors in safetensors format (for ML pipelines)
- Write feature vectors in HTK binary format (deprecated)
Live Audio I/O (liveio.h)
- Record from the microphone and play back to speakers via PortAudio
- Non-blocking API with callback support
Building
Dependencies
Install the following libraries before building:
| Library | Purpose | Debian/Ubuntu | macOS (Homebrew) |
| FFTW3 | Fast Fourier Transform | apt install libfftw3-dev | brew install fftw |
| PortAudio | Live audio I/O | apt install portaudio19-dev | brew install portaudio |
| libsndfile | Audio file reading | apt install libsndfile1-dev | brew install libsndfile |
| Doxygen | API docs generation (optional) | apt install doxygen | brew install doxygen |
| Apple container | Linux container testing (optional) | — | macOS 26+ built-in |
The Makefiles auto-detect Homebrew paths on macOS (both Apple Silicon and Intel).
On Ubuntu, GCC 14 or later is required for -std=c23 support. Ubuntu 24.04 ships GCC 13 by default, so install gcc-14 explicitly (apt install gcc-14).
Compile the library
make # builds libminidsp.a
Run the test suite
make test # builds and runs all tests
Test inside an Ubuntu container
To verify the library builds and passes all tests on Linux (Ubuntu 24.04 with GCC 14):
make container-test # builds image, then runs make test inside the container
This requires the Apple container CLI on macOS 26+.
Generate API documentation
make docs # generates HTML docs in docs/html
Install git hooks
A pre-push hook is included that runs make test and make container-test before allowing pushes to main:
Quick examples
Detect the delay between two signals
double mic_a[4096], mic_b[4096];
printf("Signal B is %d samples behind signal A\n", delay);
A mini library of DSP (Digital Signal Processing) routines.
@ PHAT
Phase Transform weighting (sharper peaks, more robust to noise)
void MD_shutdown(void)
Free all internally cached FFT plans and buffers.
int MD_get_delay(const double *siga, const double *sigb, unsigned N, double *ent, unsigned margin, int weightfunc)
Estimate the delay between two signals.
Compute the magnitude spectrum
double signal[1024];
unsigned num_bins = 1024 / 2 + 1;
double *mag = malloc(num_bins * sizeof(double));
free(mag);
void MD_magnitude_spectrum(const double *signal, unsigned N, double *mag_out)
Compute the magnitude spectrum of a real-valued signal.
A full example with Hanning windowing is in examples/magnitude_spectrum.c. Run it to generate an interactive HTML plot (Plotly.js + D3.js):
make -C examples plot
open examples/magnitude_spectrum.html # interactive: zoom, pan, hover for values
For a step-by-step walkthrough of the DSP concepts, see the Magnitude Spectrum tutorial.
Compute the power spectral density
double signal[1024];
unsigned num_bins = 1024 / 2 + 1;
double *psd = malloc(num_bins * sizeof(double));
free(psd);
void MD_power_spectral_density(const double *signal, unsigned N, double *psd_out)
Compute the power spectral density (PSD) of a real-valued signal.
A full example with Hanning windowing and one-sided PSD conversion is in examples/power_spectral_density.c. See the PSD tutorial for a detailed explanation.
Compute a spectrogram (STFT)
double signal[32000];
unsigned N = 512;
unsigned hop = 128;
unsigned num_bins = N / 2 + 1;
double *mag = malloc(num_frames * num_bins * sizeof(double));
MD_stft(signal, 32000, N, hop, mag);
free(mag);
void MD_stft(const double *signal, unsigned signal_len, unsigned N, unsigned hop, double *mag_out)
Compute the Short-Time Fourier Transform (STFT) of a real-valued signal.
unsigned MD_stft_num_frames(unsigned signal_len, unsigned N, unsigned hop)
Compute the number of STFT frames for the given signal length and parameters.
A full example generating an interactive HTML heatmap is in examples/spectrogram.c. See the Spectrogram tutorial for a step-by-step explanation.
Filter audio with a low-pass biquad
for (int i = 0; i < num_samples; i++) {
output[i] =
BiQuad(input[i], lpf);
}
free(lpf);
Biquad (second-order IIR) filter interface.
smp_type BiQuad(smp_type sample, biquad *b)
Process a single sample through the filter and return the result.
biquad * BiQuad_new(int type, smp_type dbGain, smp_type freq, smp_type srate, smp_type bandwidth)
Create and initialise a new biquad filter.
State and coefficients for a single biquad filter section.
Test suite
The test suite (tests/test_minidsp.c) covers every public function:
- Dot product – orthogonal vectors, known values, self-dot
- Energy / Power / dB – known signals, sine wave power, dB floor
- Scaling – endpoints, midpoint, vector scaling, fit-within-range
- AGC – target dB level achievement
- Entropy – uniform, spike, zero, clip/no-clip modes
- Hanning window – endpoints, peak, symmetry, range
- Magnitude spectrum – single sine, two sines, DC signal, zeros, impulse (flat spectrum), Parseval's theorem, FFT plan re-caching, non-negativity
- Power spectral density – single sine, two sines, DC signal, zeros, impulse (flat PSD), Parseval's theorem, FFT plan re-caching, non-negativity
- Spectrogram (STFT) – frame count formula, silence, pure tone peak, hop=N non-overlapping frames, non-negativity, Parseval's theorem per frame, plan re-caching across window sizes
- GCC-PHAT – positive/negative/zero delays, SIMP vs PHAT weighting, multi-signal delays, FFT plan caching
- Biquad filters – LPF, HPF, BPF, Notch, PEQ, Low shelf, High shelf, DC rejection
- File I/O writers – .npy round-trip, safetensors round-trip, WAV round-trip
Roadmap
See TODO.md for planned features – FFT spectrum analysis, signal generators, FIR filters, window functions, simple effects, pitch detection, and more.