miniDSP
A small C library for audio DSP
Loading...
Searching...
No Matches
minidsp.h File Reference

A mini library of DSP (Digital Signal Processing) routines. More...

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>
#include <float.h>
#include <complex.h>
#include <fftw3.h>

Go to the source code of this file.

Data Structures

struct  MD_DTMFTone
 A single detected DTMF tone with timing information. More...
struct  MD_vad_params
 Parameters for the VAD detector. More...
struct  MD_vad_state
 Internal state for the VAD detector. More...

Macros

#define MINIDSP_VERSION_MAJOR   0
#define MINIDSP_VERSION_MINOR   0
#define MINIDSP_VERSION_PATCH   0
#define MINIDSP_VERSION   "0.0.0"
#define M_PI   3.14159265358979323846
#define MD_STEG_LSB   0
 Steganography method: least-significant-bit encoding.
#define MD_STEG_FREQ_BAND   1
 Steganography method: near-ultrasonic frequency-band modulation (BFSK).
#define MD_STEG_SPECTEXT   2
 Steganography method: hybrid LSB + spectrogram text art.
#define MD_STEG_TYPE_TEXT   0
 Payload type flag: text (null-terminated string).
#define MD_STEG_TYPE_BINARY   1
 Payload type flag: binary (raw byte buffer).
VAD feature indices
#define MD_VAD_FEAT_ENERGY   0
 Frame energy.
#define MD_VAD_FEAT_ZCR   1
 Zero-crossing rate.
#define MD_VAD_FEAT_SPECTRAL_ENTROPY   2
 Spectral entropy.
#define MD_VAD_FEAT_SPECTRAL_FLATNESS   3
 Spectral flatness.
#define MD_VAD_FEAT_BAND_ENERGY_RATIO   4
 Band energy ratio.
#define MD_VAD_NUM_FEATURES   5
 Total number of features.

Typedefs

typedef void(* MD_ErrorHandler) (MD_ErrorCode code, const char *func_name, const char *message)
 Signature for a user-installed error handler.

Enumerations

enum  MD_ErrorCode { MD_ERR_NULL_POINTER = 1 , MD_ERR_INVALID_SIZE = 2 , MD_ERR_INVALID_RANGE = 3 , MD_ERR_ALLOC_FAILED = 4 }
 Error codes reported by miniDSP when a precondition is violated. More...
enum  MD_GCC_WEIGHTING_TYPE { SIMP , PHAT }
 Weighting types for Generalized Cross-Correlation. More...

Functions

void MD_set_error_handler (MD_ErrorHandler handler)
 Install a custom error handler.
double MD_dot (const double *a, const double *b, unsigned N)
 Compute the dot product of two vectors.
double MD_entropy (const double *a, unsigned N, bool clip)
 Compute the normalized entropy of a distribution.
double MD_energy (const double *a, unsigned N)
 Compute signal energy: sum of squared samples.
double MD_power (const double *a, unsigned N)
 Compute signal power: energy divided by the number of samples.
double MD_power_db (const double *a, unsigned N)
 Compute signal power in decibels: 10 * log10(power).
double MD_rms (const double *a, unsigned N)
 Compute the root mean square (RMS) of a signal.
double MD_zero_crossing_rate (const double *a, unsigned N)
 Compute the zero-crossing rate of a signal.
void MD_autocorrelation (const double *a, unsigned N, double *out, unsigned max_lag)
 Compute the normalised autocorrelation of a signal.
void MD_peak_detect (const double *a, unsigned N, double threshold, unsigned min_distance, unsigned *peaks_out, unsigned *num_peaks_out)
 Detect peaks (local maxima) in a signal.
double MD_f0_autocorrelation (const double *signal, unsigned N, double sample_rate, double min_freq_hz, double max_freq_hz)
 Estimate the fundamental frequency (F0) using autocorrelation.
double MD_f0_fft (const double *signal, unsigned N, double sample_rate, double min_freq_hz, double max_freq_hz)
 Estimate the fundamental frequency (F0) using FFT peak picking.
void MD_mix (const double *a, const double *b, double *out, unsigned N, double w_a, double w_b)
 Mix (weighted sum) two signals.
void MD_delay_echo (const double *in, double *out, unsigned N, unsigned delay_samples, double feedback, double dry, double wet)
 Delay line / echo effect using a circular buffer with feedback.
void MD_tremolo (const double *in, double *out, unsigned N, double rate_hz, double depth, double sample_rate)
 Tremolo effect (amplitude modulation by a sinusoidal LFO).
void MD_comb_reverb (const double *in, double *out, unsigned N, unsigned delay_samples, double feedback, double dry, double wet)
 Comb-filter reverb (feedback comb filter with dry/wet mix).
unsigned MD_convolution_num_samples (unsigned signal_len, unsigned kernel_len)
 Compute the output length of a full linear convolution.
void MD_convolution_time (const double *signal, unsigned signal_len, const double *kernel, unsigned kernel_len, double *out)
 Time-domain full linear convolution (direct sum-of-products).
void MD_moving_average (const double *signal, unsigned signal_len, unsigned window_len, double *out)
 Causal moving-average FIR filter with zero-padded startup.
void MD_fir_filter (const double *signal, unsigned signal_len, const double *coeffs, unsigned num_taps, double *out)
 Apply a causal FIR filter with arbitrary coefficients.
void MD_convolution_fft_ola (const double *signal, unsigned signal_len, const double *kernel, unsigned kernel_len, double *out)
 Full linear convolution using FFT overlap-add (offline).
void MD_design_lowpass_fir (double *coeffs, unsigned num_taps, double cutoff_freq, double sample_rate, double kaiser_beta)
 Design a Kaiser-windowed sinc lowpass FIR filter.
double MD_scale (double in, double oldmin, double oldmax, double newmin, double newmax)
 Map a single value from one range to another.
void MD_scale_vec (double *in, double *out, unsigned N, double oldmin, double oldmax, double newmin, double newmax)
 Map every element of a vector from one range to another.
void MD_fit_within_range (double *in, double *out, unsigned N, double newmin, double newmax)
 Fit values within [newmin, newmax].
void MD_adjust_dblevel (const double *in, double *out, unsigned N, double dblevel)
 Automatic Gain Control: scale a signal so its power matches the requested dB level, then clip to [-1, 1].
void MD_magnitude_spectrum (const double *signal, unsigned N, double *mag_out)
 Compute the magnitude spectrum of a real-valued signal.
void MD_power_spectral_density (const double *signal, unsigned N, double *psd_out)
 Compute the power spectral density (PSD) of a real-valued signal.
void MD_phase_spectrum (const double *signal, unsigned N, double *phase_out)
 Compute the one-sided phase spectrum of a real 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.
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.
void MD_mel_filterbank (unsigned N, double sample_rate, unsigned num_mels, double min_freq_hz, double max_freq_hz, double *filterbank_out)
 Build a mel-spaced triangular filterbank matrix.
void MD_mel_energies (const double *signal, unsigned N, double sample_rate, unsigned num_mels, double min_freq_hz, double max_freq_hz, double *mel_out)
 Compute mel-band energies from a single frame.
void MD_mfcc (const double *signal, unsigned N, double sample_rate, unsigned num_mels, unsigned num_coeffs, double min_freq_hz, double max_freq_hz, double *mfcc_out)
 Compute mel-frequency cepstral coefficients (MFCCs) from a single frame.
void MD_lowpass_brickwall (double *signal, unsigned len, double cutoff_hz, double sample_rate)
 Apply a brickwall lowpass filter to a signal in-place.
double MD_bessel_i0 (double x)
 Zeroth-order modified Bessel function of the first kind, \(I_0(x)\).
double MD_sinc (double x)
 Normalized sinc function: \(\mathrm{sinc}(x) = \sin(\pi x)/(\pi x)\).
void MD_Gen_Hann_Win (double *out, unsigned n)
 Generate a Hanning (Hann) window of length n.
void MD_Gen_Hamming_Win (double *out, unsigned n)
 Generate a Hamming window of length n.
void MD_Gen_Blackman_Win (double *out, unsigned n)
 Generate a Blackman window of length n.
void MD_Gen_Rect_Win (double *out, unsigned n)
 Generate a rectangular window of length n (all ones).
void MD_Gen_Kaiser_Win (double *out, unsigned n, double beta)
 Generate a Kaiser window of length n with shape parameter beta.
void MD_sine_wave (double *output, unsigned N, double amplitude, double freq, double sample_rate)
 Generate a sine wave.
void MD_white_noise (double *output, unsigned N, double amplitude, unsigned seed)
 Generate Gaussian white noise.
void MD_impulse (double *output, unsigned N, double amplitude, unsigned position)
 Generate a discrete impulse (Kronecker delta).
void MD_chirp_linear (double *output, unsigned N, double amplitude, double f_start, double f_end, double sample_rate)
 Generate a linear chirp (swept sine with linearly increasing frequency).
void MD_chirp_log (double *output, unsigned N, double amplitude, double f_start, double f_end, double sample_rate)
 Generate a logarithmic chirp (swept sine with exponentially increasing frequency).
void MD_square_wave (double *output, unsigned N, double amplitude, double freq, double sample_rate)
 Generate a square wave.
void MD_sawtooth_wave (double *output, unsigned N, double amplitude, double freq, double sample_rate)
 Generate a sawtooth wave.
void MD_shepard_tone (double *output, unsigned N, double amplitude, double base_freq, double sample_rate, double rate_octaves_per_sec, unsigned num_octaves)
 Generate a Shepard tone — the auditory illusion of endlessly rising or falling pitch.
unsigned MD_dtmf_detect (const double *signal, unsigned signal_len, double sample_rate, MD_DTMFTone *tones_out, unsigned max_tones)
 Detect DTMF tones in an audio signal.
void MD_dtmf_generate (double *output, const char *digits, double sample_rate, unsigned tone_ms, unsigned pause_ms)
 Generate a DTMF tone sequence.
unsigned MD_dtmf_signal_length (unsigned num_digits, double sample_rate, unsigned tone_ms, unsigned pause_ms)
 Calculate the number of samples needed for MD_dtmf_generate().
void MD_shutdown (void)
 Free all internally cached FFT plans and buffers.
void MD_get_multiple_delays (const double **sigs, unsigned M, unsigned N, unsigned margin, int weightfunc, int *outdelays)
 Estimate delays between a reference signal and M-1 other signals.
int MD_get_delay (const double *siga, const double *sigb, unsigned N, double *ent, unsigned margin, int weightfunc)
 Estimate the delay between two signals.
void MD_gcc (const double *siga, const double *sigb, unsigned N, double *lagvals, int weightfunc)
 Compute the full generalized cross-correlation between two signals.
unsigned MD_spectrogram_text (double *output, unsigned max_len, const char *text, double freq_lo, double freq_hi, double duration_sec, double sample_rate)
 Synthesise audio that displays readable text in a spectrogram.
unsigned MD_steg_capacity (unsigned signal_len, double sample_rate, int method)
 Compute the maximum message length (in bytes) that can be hidden.
unsigned MD_steg_encode (const double *host, double *output, unsigned signal_len, double sample_rate, const char *message, int method)
 Encode a secret message into a host audio signal.
unsigned MD_steg_decode (const double *stego, unsigned signal_len, double sample_rate, char *message_out, unsigned max_msg_len, int method)
 Decode a secret message from a stego audio signal.
unsigned MD_steg_encode_bytes (const double *host, double *output, unsigned signal_len, double sample_rate, const unsigned char *data, unsigned data_len, int method)
 Encode arbitrary binary data into a host audio signal.
unsigned MD_steg_decode_bytes (const double *stego, unsigned signal_len, double sample_rate, unsigned char *data_out, unsigned max_len, int method)
 Decode binary data from a stego audio signal.
int MD_steg_detect (const double *signal, unsigned signal_len, double sample_rate, int *payload_type_out)
 Detect which steganography method (if any) was used to encode a signal.
unsigned MD_resample_output_len (unsigned input_len, double in_rate, double out_rate)
 Compute the output buffer size needed for resampling.
unsigned MD_resample (const double *input, unsigned input_len, double *output, unsigned max_output_len, double in_rate, double out_rate, unsigned num_zero_crossings, double kaiser_beta)
 Resample a signal from one sample rate to another using polyphase sinc interpolation.
void MD_vad_default_params (MD_vad_params *params)
 Populate a VAD params struct with optimized defaults.
void MD_vad_init (MD_vad_state *state, const MD_vad_params *params)
 Initialize VAD state from params.
void MD_vad_calibrate (MD_vad_state *state, const double *signal, unsigned N, double sample_rate)
 Feed a known-silence frame to seed the adaptive normalization.
int MD_vad_process_frame (MD_vad_state *state, const double *signal, unsigned N, double sample_rate, double *score_out, double *features_out)
 Process one audio frame and return a binary speech decision.

Detailed Description

A mini library of DSP (Digital Signal Processing) routines.

This header declares functions for:

  • Basic signal measurements (energy, power, entropy)
  • Signal analysis (RMS, zero-crossing rate, autocorrelation, peak detection, F0 estimation, mixing)
  • Simple effects (delay/echo, tremolo, and comb-filter reverb)
  • Signal scaling and gain adjustment
  • Math utilities (Bessel I₀, normalized sinc)
  • Window generation (Hanning, Hamming, Blackman, rectangular, Kaiser)
  • Signal generators (sine, white noise, impulse, chirp, square, sawtooth, Shepard tone)
  • FIR filtering, convolution, and lowpass FIR design (time-domain and FFT overlap-add)
  • Sample rate conversion (polyphase sinc resampler)
  • FFT-based magnitude spectrum, power spectral density, STFT, mel filterbanks, MFCCs, and brickwall lowpass filtering
  • DTMF tone detection (ITU-T Q.24) and generation
  • Generalized Cross-Correlation (GCC-PHAT) for delay estimation
  • Spectrogram text art (synthesise audio that displays text in a spectrogram)
  • Audio steganography (hide, detect, and recover secret messages or binary data via LSB, frequency-band, or spectrogram-text encoding)
  • Voice activity detection (VAD) with adaptive feature normalization and onset/hangover smoothing
  • Configurable error handling (custom error handler callback, safe defaults on precondition failure)

These are the kinds of building blocks you'd use in an audio processing pipeline – for example, estimating which direction a sound came from using a pair of microphones.

Definition in file minidsp.h.

Macro Definition Documentation

◆ M_PI

#define M_PI   3.14159265358979323846

Definition at line 110 of file minidsp.h.

◆ MD_STEG_FREQ_BAND

#define MD_STEG_FREQ_BAND   1

Steganography method: near-ultrasonic frequency-band modulation (BFSK).

Definition at line 1540 of file minidsp.h.

◆ MD_STEG_LSB

#define MD_STEG_LSB   0

Steganography method: least-significant-bit encoding.

Definition at line 1538 of file minidsp.h.

◆ MD_STEG_SPECTEXT

#define MD_STEG_SPECTEXT   2

Steganography method: hybrid LSB + spectrogram text art.

Encodes the message via LSB (machine-readable round-trip) and simultaneously renders it as text in a spectrogram using sine tones in the 18–23.5 kHz ultrasonic band (human-readable visual watermark).

The host signal is automatically upsampled to 48 kHz if its sample rate is below 48 kHz, so the output buffer must be sized for MD_resample_output_len(signal_len, sample_rate, 48000.0) samples when the input rate is less than 48 kHz.

Visual capacity is limited by host duration: each character occupies 240 ms (8 bitmap columns at 30 ms each). Messages longer than the visual capacity are truncated for the spectrogram art, but the full message is always recoverable via the LSB data channel.

Definition at line 1556 of file minidsp.h.

◆ MD_STEG_TYPE_BINARY

#define MD_STEG_TYPE_BINARY   1

Payload type flag: binary (raw byte buffer).

Definition at line 1561 of file minidsp.h.

◆ MD_STEG_TYPE_TEXT

#define MD_STEG_TYPE_TEXT   0

Payload type flag: text (null-terminated string).

Definition at line 1559 of file minidsp.h.

◆ MD_VAD_FEAT_BAND_ENERGY_RATIO

#define MD_VAD_FEAT_BAND_ENERGY_RATIO   4

Band energy ratio.

Definition at line 1793 of file minidsp.h.

◆ MD_VAD_FEAT_ENERGY

#define MD_VAD_FEAT_ENERGY   0

Frame energy.

Definition at line 1789 of file minidsp.h.

◆ MD_VAD_FEAT_SPECTRAL_ENTROPY

#define MD_VAD_FEAT_SPECTRAL_ENTROPY   2

Spectral entropy.

Definition at line 1791 of file minidsp.h.

◆ MD_VAD_FEAT_SPECTRAL_FLATNESS

#define MD_VAD_FEAT_SPECTRAL_FLATNESS   3

Spectral flatness.

Definition at line 1792 of file minidsp.h.

◆ MD_VAD_FEAT_ZCR

#define MD_VAD_FEAT_ZCR   1

Zero-crossing rate.

Definition at line 1790 of file minidsp.h.

◆ MD_VAD_NUM_FEATURES

#define MD_VAD_NUM_FEATURES   5

Total number of features.

Definition at line 1794 of file minidsp.h.

◆ MINIDSP_VERSION

#define MINIDSP_VERSION   "0.0.0"

Definition at line 42 of file minidsp.h.

◆ MINIDSP_VERSION_MAJOR

#define MINIDSP_VERSION_MAJOR   0

Definition at line 33 of file minidsp.h.

◆ MINIDSP_VERSION_MINOR

#define MINIDSP_VERSION_MINOR   0

Definition at line 36 of file minidsp.h.

◆ MINIDSP_VERSION_PATCH

#define MINIDSP_VERSION_PATCH   0

Definition at line 39 of file minidsp.h.

Typedef Documentation

◆ MD_ErrorHandler

typedef void(* MD_ErrorHandler) (MD_ErrorCode code, const char *func_name, const char *message)

Signature for a user-installed error handler.

Parameters
codeOne of the MD_ERR_* error codes.
func_nameName of the library function that detected the error.
messageHuman-readable description of the violation.

The handler may log, count, or even call abort() — the library itself never terminates the process.

Definition at line 78 of file minidsp.h.

Enumeration Type Documentation

◆ MD_ErrorCode

Error codes reported by miniDSP when a precondition is violated.

These codes are passed to the active error handler. Zero is reserved for "no error"; all defined codes are positive.

Enumerator
MD_ERR_NULL_POINTER 

A required pointer argument is NULL.

MD_ERR_INVALID_SIZE 

A size or count argument is invalid (e.g.

N == 0).

MD_ERR_INVALID_RANGE 

A range or bound is invalid (e.g.

min >= max).

MD_ERR_ALLOC_FAILED 

A memory allocation failed.

Definition at line 61 of file minidsp.h.

◆ MD_GCC_WEIGHTING_TYPE

Weighting types for Generalized Cross-Correlation.

Enumerator
SIMP 

Simple 1/N weighting (basic cross-correlation).

PHAT 

Phase Transform weighting (sharper peaks, more robust to noise).

Definition at line 1451 of file minidsp.h.

Function Documentation

◆ MD_adjust_dblevel()

void MD_adjust_dblevel ( const double * in,
double * out,
unsigned N,
double dblevel )

Automatic Gain Control: scale a signal so its power matches the requested dB level, then clip to [-1, 1].

Automatic Gain Control: scale a signal so its power matches the requested dB level, then clip to [-1, 1].

The input signal is assumed to be in the range [-1.0, 1.0]. The function computes a gain factor so that the output signal has the desired power level (in dB), then clips to [-1.0, 1.0] if any sample exceeds that range.

Based on Jaydeep Dhole's AGC implementation for MATLAB.

Definition at line 166 of file minidsp_core.c.

◆ MD_autocorrelation()

void MD_autocorrelation ( const double * a,
unsigned N,
double * out,
unsigned max_lag )

Compute the normalised autocorrelation of a signal.

The autocorrelation measures the similarity between a signal and a delayed copy of itself. This function computes the normalised (biased) autocorrelation for lags 0 through max_lag-1:

\[R[\tau] = \frac{1}{R[0]} \sum_{n=0}^{N-1-\tau} x[n]\,x[n+\tau] \]

where \(R[0] = \sum x[n]^2\) is the signal energy. The output satisfies out[0] = 1.0 and |out[tau]| <= 1.0. A silent signal (all zeros) produces all-zero output.

Parameters
aInput signal of length N.
NNumber of samples. Must be > 0.
outOutput array of length max_lag (caller-allocated).
max_lagNumber of lag values to compute. Must be > 0 and < N.
double sig[1024];
MD_sine_wave(sig, 1024, 1.0, 100.0, 1000.0);
double acf[50];
MD_autocorrelation(sig, 1024, acf, 50);
// acf[0] = 1.0, acf[10] ~ 1.0 (lag = one period of 100 Hz at 1 kHz)
void MD_sine_wave(double *output, unsigned N, double amplitude, double freq, double sample_rate)
Generate a sine wave.
void MD_autocorrelation(const double *a, unsigned N, double *out, unsigned max_lag)
Compute the normalised autocorrelation of a signal.

Compute the normalised autocorrelation of a signal.

out[tau] = (1/R[0]) * sum_{n=0}^{N-1-tau} x[n] * x[n+tau]

Reuses MD_dot() for the inner product. Silent signals (R[0]=0) produce all-zero output.

Definition at line 321 of file minidsp_core.c.

◆ MD_bessel_i0()

double MD_bessel_i0 ( double x)

Zeroth-order modified Bessel function of the first kind, \(I_0(x)\).

Computed via the power series:

\[ I_0(x) = \sum_{k=0}^{\infty} \left[\frac{(x/2)^k}{k!}\right]^2 \]

Converges until the term is below \(10^{-15}\) relative tolerance.

Parameters
xInput value (any real number).
Returns
\(I_0(x)\). Always \(\geq 1\) since \(I_0(0)=1\).
double val = MD_bessel_i0(5.0); // ≈ 27.2399
double MD_bessel_i0(double x)
Zeroth-order modified Bessel function of the first kind, .

Zeroth-order modified Bessel function of the first kind, \(I_0(x)\).

Uses the power series: I₀(x) = Σ [(x/2)^k / k!]² Converges until the term is below 1e-15 * sum (relative tolerance).

Definition at line 532 of file minidsp_core.c.

◆ MD_chirp_linear()

void MD_chirp_linear ( double * output,
unsigned N,
double amplitude,
double f_start,
double f_end,
double sample_rate )

Generate a linear chirp (swept sine with linearly increasing frequency).

The instantaneous frequency sweeps linearly from f_start to f_end over N samples:

f(t) = f_start + (f_end - f_start) * t / T

where T = (N-1) / sample_rate is the sweep duration. The output is:

output[i] = amplitude * sin(2*pi * (f_start*t + 0.5*chirp_rate*t^2))

A linear chirp is the standard test signal for spectrograms – its instantaneous frequency traces a straight diagonal line in the time-frequency plane.

Parameters
outputOutput buffer of length N (caller-allocated).
NNumber of samples to generate. Must be > 0.
amplitudePeak amplitude of the chirp (e.g. 1.0).
f_startStarting frequency in Hz.
f_endEnding frequency in Hz.
sample_rateSampling rate in Hz. Must be > 0.
double sig[16000];
// 1-second linear chirp from 200 Hz to 4000 Hz at 16 kHz sample rate
MD_chirp_linear(sig, 16000, 1.0, 200.0, 4000.0, 16000.0);
void MD_chirp_linear(double *output, unsigned N, double amplitude, double f_start, double f_end, double sample_rate)
Generate a linear chirp (swept sine with linearly increasing frequency).

Definition at line 78 of file minidsp_generators.c.

◆ MD_chirp_log()

void MD_chirp_log ( double * output,
unsigned N,
double amplitude,
double f_start,
double f_end,
double sample_rate )

Generate a logarithmic chirp (swept sine with exponentially increasing frequency).

The instantaneous frequency sweeps exponentially from f_start to f_end over N samples:

f(t) = f_start * (f_end / f_start)^(t / T)

where T = (N-1) / sample_rate is the sweep duration. The output is:

output[i] = amplitude * sin(2*pi * f_start * T * (r^(t/T) - 1) / ln(r))

where r = f_end / f_start.

A logarithmic chirp spends equal time per octave, making it ideal for measuring systems whose behaviour is best described on a log-frequency axis (e.g. audio equaliser response).

Parameters
outputOutput buffer of length N (caller-allocated).
NNumber of samples to generate. Must be > 0.
amplitudePeak amplitude of the chirp (e.g. 1.0).
f_startStarting frequency in Hz. Must be > 0.
f_endEnding frequency in Hz. Must be > 0 and != f_start.
sample_rateSampling rate in Hz. Must be > 0.
double sig[44100];
// 1-second log chirp from 20 Hz to 20 kHz at 44.1 kHz sample rate
MD_chirp_log(sig, 44100, 1.0, 20.0, 20000.0, 44100.0);
void MD_chirp_log(double *output, unsigned N, double amplitude, double f_start, double f_end, double sample_rate)
Generate a logarithmic chirp (swept sine with exponentially increasing frequency).

Definition at line 100 of file minidsp_generators.c.

◆ MD_comb_reverb()

void MD_comb_reverb ( const double * in,
double * out,
unsigned N,
unsigned delay_samples,
double feedback,
double dry,
double wet )

Comb-filter reverb (feedback comb filter with dry/wet mix).

Internal comb section:

\[c[n] = x[n] + feedback \cdot c[n-D] \]

Final output:

\[y[n] = dry \cdot x[n] + wet \cdot c[n] \]

where \(D\) is delay_samples. In-place safe: out may alias in.

Parameters
inInput signal of length N.
outOutput signal of length N (caller-allocated).
NNumber of samples.
delay_samplesComb delay in samples (must be > 0).
feedbackFeedback gain (must satisfy |feedback| < 1).
dryDry (original) mix weight.
wetWet (comb output) mix weight.

Definition at line 495 of file minidsp_core.c.

◆ MD_convolution_fft_ola()

void MD_convolution_fft_ola ( const double * signal,
unsigned signal_len,
const double * kernel,
unsigned kernel_len,
double * out )

Full linear convolution using FFT overlap-add (offline).

Produces the same output as MD_convolution_time() but is faster for longer kernels by processing blocks in the frequency domain.

Parameters
signalInput signal of length signal_len.
signal_lenNumber of input samples (must be > 0).
kernelFIR kernel of length kernel_len.
kernel_lenNumber of FIR taps (must be > 0).
outOutput buffer of length signal_len + kernel_len - 1.

Definition at line 124 of file minidsp_fir.c.

◆ MD_convolution_num_samples()

unsigned MD_convolution_num_samples ( unsigned signal_len,
unsigned kernel_len )

Compute the output length of a full linear convolution.

For input length N and kernel length M, full convolution length is N+M-1.

Definition at line 18 of file minidsp_fir.c.

◆ MD_convolution_time()

void MD_convolution_time ( const double * signal,
unsigned signal_len,
const double * kernel,
unsigned kernel_len,
double * out )

Time-domain full linear convolution (direct sum-of-products).

Computes: out[n] = sum_{k=0}^{kernel_len-1} signal[n-k] * kernel[k] with out-of-range signal samples treated as zero.

Parameters
signalInput signal of length signal_len.
signal_lenNumber of input samples (must be > 0).
kernelFIR kernel of length kernel_len.
kernel_lenNumber of FIR taps (must be > 0).
outOutput buffer of length signal_len + kernel_len - 1.

Definition at line 25 of file minidsp_fir.c.

◆ MD_delay_echo()

void MD_delay_echo ( const double * in,
double * out,
unsigned N,
unsigned delay_samples,
double feedback,
double dry,
double wet )

Delay line / echo effect using a circular buffer with feedback.

Let D = delay_samples. The internal delay state follows:

\[s[n] = x[n] + feedback \cdot s[n-D] \]

and output is:

\[y[n] = dry \cdot x[n] + wet \cdot s[n-D] \]

This creates repeating echoes decaying geometrically when \(|feedback| < 1\). In-place safe: out may alias in.

Parameters
inInput signal of length N.
outOutput signal of length N (caller-allocated).
NNumber of samples.
delay_samplesDelay length in samples (must be > 0).
feedbackEcho feedback gain (must satisfy |feedback| < 1).
dryDry (original) mix weight.
wetWet (delayed) mix weight.

Definition at line 451 of file minidsp_core.c.

◆ MD_design_lowpass_fir()

void MD_design_lowpass_fir ( double * coeffs,
unsigned num_taps,
double cutoff_freq,
double sample_rate,
double kaiser_beta )

Design a Kaiser-windowed sinc lowpass FIR filter.

Generates a linear-phase lowpass filter with the specified cutoff frequency and Kaiser window shape. The coefficients are normalized to unity DC gain (they sum to 1.0).

\[ h[i] = 2\,f_c\;\mathrm{sinc}\!\bigl(2\,f_c\,(i - (N-1)/2)\bigr) \;\cdot\; w_{\mathrm{Kaiser}}[i] \]

where \(f_c = \mathrm{cutoff\_freq} / \mathrm{sample\_rate}\).

Parameters
coeffsOutput buffer of length num_taps (caller-allocated).
num_tapsFilter length (must be > 0).
cutoff_freq-6 dB cutoff frequency in Hz (must be > 0 and < sample_rate / 2).
sample_rateSampling rate in Hz (must be > 0).
kaiser_betaKaiser window \(\beta\) parameter (e.g. 10.0).
double h[65];
MD_design_lowpass_fir(h, 65, 4000.0, 48000.0, 10.0); // 4 kHz LPF
void MD_design_lowpass_fir(double *coeffs, unsigned num_taps, double cutoff_freq, double sample_rate, double kaiser_beta)
Design a Kaiser-windowed sinc lowpass FIR filter.
Definition minidsp_fir.c:88

Definition at line 88 of file minidsp_fir.c.

◆ MD_dot()

double MD_dot ( const double * a,
const double * b,
unsigned N )

Compute the dot product of two vectors.

The dot product is the sum of element-wise products: a[0]*b[0] + a[1]*b[1] + ...

Compute the dot product of two vectors.

dot = a[0]*b[0] + a[1]*b[1] + ... + a[N-1]*b[N-1]

This is one of the most fundamental operations in DSP. The dot product measures how "similar" two signals are – if they are identical the result is large; if they are unrelated it is near zero.

Definition at line 26 of file minidsp_core.c.

◆ MD_dtmf_detect()

unsigned MD_dtmf_detect ( const double * signal,
unsigned signal_len,
double sample_rate,
MD_DTMFTone * tones_out,
unsigned max_tones )

Detect DTMF tones in an audio signal.

Slides a Hanning-windowed FFT frame across the signal and checks each frame for a valid row + column frequency pair. A tone is reported only after it persists for at least 40 ms (ITU-T Q.24), and a new tone is not accepted until at least 40 ms of silence separates it from the previous one.

The FFT size is the largest power of two whose window fits within 35 ms, keeping it shorter than the 40 ms Q.24 minimum pause so the state machine can resolve inter-digit gaps. The hop size is N/4 (75 % overlap).

Parameters
signalAudio samples (mono).
signal_lenNumber of samples. Must be > 0.
sample_rateSampling rate in Hz. Must be >= 4000 (Nyquist for the highest DTMF frequency, 1633 Hz).
tones_outOutput array for detected tones (caller-allocated).
max_tonesSize of tones_out. Must be > 0.
Returns
Number of tones detected (<= max_tones).
// Generate a short DTMF sequence and detect it
const char *digits = "5551234";
unsigned len = MD_dtmf_signal_length(7, 8000.0, 70, 70);
double *sig = malloc(len * sizeof(double));
MD_dtmf_generate(sig, digits, 8000.0, 70, 70);
MD_DTMFTone tones[16];
unsigned n = MD_dtmf_detect(sig, len, 8000.0, tones, 16);
for (unsigned i = 0; i < n; i++)
printf("%c %.3f--%.3f s\n", tones[i].digit,
tones[i].start_s, tones[i].end_s);
free(sig);
unsigned MD_dtmf_detect(const double *signal, unsigned signal_len, double sample_rate, MD_DTMFTone *tones_out, unsigned max_tones)
Detect DTMF tones in an audio signal.
void MD_dtmf_generate(double *output, const char *digits, double sample_rate, unsigned tone_ms, unsigned pause_ms)
Generate a DTMF tone sequence.
unsigned MD_dtmf_signal_length(unsigned num_digits, double sample_rate, unsigned tone_ms, unsigned pause_ms)
Calculate the number of samples needed for MD_dtmf_generate().
A single detected DTMF tone with timing information.
Definition minidsp.h:1328

Definition at line 139 of file minidsp_dtmf.c.

◆ MD_dtmf_generate()

void MD_dtmf_generate ( double * output,
const char * digits,
double sample_rate,
unsigned tone_ms,
unsigned pause_ms )

Generate a DTMF tone sequence.

Each digit is rendered as the sum of its row and column sinusoids, each at amplitude 0.5 (peak sum = 1.0). Digits are separated by silent gaps. Use MD_dtmf_signal_length() to pre-compute the required output buffer size.

Timing constraints follow ITU-T Q.24:

  • tone_ms >= 40 (minimum recognisable tone)
  • pause_ms >= 40 (minimum inter-digit pause)
Parameters
outputOutput buffer (caller-allocated, length from MD_dtmf_signal_length()).
digitsNull-terminated string of valid DTMF characters: '0'–'9', 'A'–'D' (case-insensitive), '*', '#'. An invalid character triggers an assertion failure.
sample_rateSampling rate in Hz. Must be > 0.
tone_msDuration of each tone in milliseconds (>= 40).
pause_msDuration of silence between tones in ms (>= 40).
unsigned len = MD_dtmf_signal_length(3, 8000.0, 70, 70);
double *sig = malloc(len * sizeof(double));
MD_dtmf_generate(sig, "911", 8000.0, 70, 70);
// sig now contains 3 tones of 70 ms each with 70 ms gaps
free(sig);

Definition at line 325 of file minidsp_dtmf.c.

◆ MD_dtmf_signal_length()

unsigned MD_dtmf_signal_length ( unsigned num_digits,
double sample_rate,
unsigned tone_ms,
unsigned pause_ms )

Calculate the number of samples needed for MD_dtmf_generate().

\[N = D \cdot \left\lfloor \frac{t_{\text{tone}} \cdot f_s}{1000} \right\rfloor + (D - 1) \cdot \left\lfloor \frac{t_{\text{pause}} \cdot f_s}{1000} \right\rfloor \]

where \(D\) is the number of digits.

Parameters
num_digitsNumber of digits in the sequence.
sample_rateSampling rate in Hz. Must be > 0.
tone_msTone duration in milliseconds.
pause_msPause duration in milliseconds.
Returns
Total number of samples (0 if num_digits == 0).

Definition at line 367 of file minidsp_dtmf.c.

◆ MD_energy()

double MD_energy ( const double * a,
unsigned N )

Compute signal energy: sum of squared samples.

Compute signal energy: sum of squared samples.

     N-1

E = SUM a[n]^2 n=0

Energy tells you "how loud" a signal is overall. A silent signal has zero energy; a loud one has high energy. Notice that squaring makes all values positive, so negative samples contribute too.

Definition at line 46 of file minidsp_core.c.

◆ MD_entropy()

double MD_entropy ( const double * a,
unsigned N,
bool clip )

Compute the normalized entropy of a distribution.

Returns a value between 0.0 (all energy concentrated in one bin) and 1.0 (energy spread equally across all bins).

Parameters
clipIf true, ignore negative values. If false, square all values first.

Compute the normalized entropy of a distribution.

Entropy measures how "spread out" a distribution is:

  • 0.0 means all the energy is in a single bin (very peaky).
  • 1.0 means the energy is spread equally (completely flat).

The Shannon entropy formula is: H = -SUM( p_i * log2(p_i) ) We normalise by dividing by log2(N) so the result is always in [0, 1].

Parameters
aArray of values representing the distribution.
NLength of the array.
clipIf true, ignore negative values (treat them as 0). If false, use a[i]^2 so all values become non-negative.
Returns
Normalised entropy in [0.0, 1.0].

Definition at line 218 of file minidsp_core.c.

◆ MD_f0_autocorrelation()

double MD_f0_autocorrelation ( const double * signal,
unsigned N,
double sample_rate,
double min_freq_hz,
double max_freq_hz )

Estimate the fundamental frequency (F0) using autocorrelation.

This method searches for the strongest local peak in the normalised autocorrelation sequence over lags corresponding to the requested frequency range:

\[f_0 = \frac{f_s}{\tau_\text{peak}} \]

where \(\tau_\text{peak}\) is the selected lag and \(f_s\) is the sample rate.

Parameters
signalInput signal of length N.
NNumber of samples (must be >= 2).
sample_rateSampling rate in Hz (must be > 0).
min_freq_hzMinimum search frequency in Hz (must be > 0).
max_freq_hzMaximum search frequency in Hz (must be > min_freq_hz).
Returns
Estimated F0 in Hz, or 0.0 if no reliable F0 is found.
Note
Invalid API usage is guarded by assertions. A return value of 0.0 means the call was valid but no usable pitch peak was found (for example, silence or an unvoiced/noisy frame).
double f0 = MD_f0_autocorrelation(frame, frame_len, 16000.0, 80.0, 400.0);
double MD_f0_autocorrelation(const double *signal, unsigned N, double sample_rate, double min_freq_hz, double max_freq_hz)
Estimate the fundamental frequency (F0) using autocorrelation.

Definition at line 372 of file minidsp_core.c.

◆ MD_f0_fft()

double MD_f0_fft ( const double * signal,
unsigned N,
double sample_rate,
double min_freq_hz,
double max_freq_hz )

Estimate the fundamental frequency (F0) using FFT peak picking.

The signal is internally Hann-windowed, transformed with a one-sided FFT, then the dominant magnitude peak in the requested frequency range is mapped back to Hz:

\[f_0 = \frac{k_\text{peak} f_s}{N} \]

where \(k_\text{peak}\) is the selected FFT bin.

This method is simple and fast but generally less robust than MD_f0_autocorrelation() for noisy or strongly harmonic signals.

Parameters
signalInput signal of length N.
NNumber of samples (must be >= 2).
sample_rateSampling rate in Hz (must be > 0).
min_freq_hzMinimum search frequency in Hz (must be > 0).
max_freq_hzMaximum search frequency in Hz (must be > min_freq_hz).
Returns
Estimated F0 in Hz, or 0.0 if no reliable F0 is found.
Note
This function uses the internal FFT cache. Call MD_shutdown() when done with FFT-based APIs.
Invalid API usage is guarded by assertions. A return value of 0.0 means the call was valid but no usable pitch peak was found.
double f0 = MD_f0_fft(frame, frame_len, 16000.0, 80.0, 400.0);
double MD_f0_fft(const double *signal, unsigned N, double sample_rate, double min_freq_hz, double max_freq_hz)
Estimate the fundamental frequency (F0) using FFT peak picking.

Definition at line 379 of file minidsp_spectrum.c.

◆ MD_fir_filter()

void MD_fir_filter ( const double * signal,
unsigned signal_len,
const double * coeffs,
unsigned num_taps,
double * out )

Apply a causal FIR filter with arbitrary coefficients.

Computes: out[n] = sum_{k=0}^{num_taps-1} coeffs[k] * signal[n-k] with out-of-range signal samples treated as zero.

Parameters
signalInput signal of length signal_len.
signal_lenNumber of input samples (must be > 0).
coeffsFIR coefficients of length num_taps.
num_tapsNumber of FIR taps (must be > 0).
outOutput buffer of length signal_len.

Definition at line 68 of file minidsp_fir.c.

◆ MD_fit_within_range()

void MD_fit_within_range ( double * in,
double * out,
unsigned N,
double newmin,
double newmax )

Fit values within [newmin, newmax].

If all values already fit, they are copied unchanged. Otherwise the entire vector is rescaled.

Fit values within [newmin, newmax].

If the input range already lies inside [newmin, newmax], the values are copied as-is (no stretching). Otherwise, the full input range is mapped onto the new range.

Definition at line 130 of file minidsp_core.c.

◆ MD_gcc()

void MD_gcc ( const double * siga,
const double * sigb,
unsigned N,
double * lagvals,
int weightfunc )

Compute the full generalized cross-correlation between two signals.

Parameters
sigaFirst signal.
sigbSecond signal.
NLength of both signals.
lagvalsOutput array of N doubles (pre-allocated). The zero-lag value is at index ceil(N/2).
weightfuncSIMP or PHAT.

Compute the full generalized cross-correlation between two signals.

This is the core GCC-PHAT routine. It fills lagvals[] with the cross-correlation values, shifted so that the zero-lag value is at index ceil(N/2).

Parameters
sigaFirst signal.
sigbSecond signal.
NLength of both signals.
lagvalsOutput array of N doubles (pre-allocated by caller).
weightfuncSIMP or PHAT.

Definition at line 340 of file minidsp_gcc.c.

◆ MD_Gen_Blackman_Win()

void MD_Gen_Blackman_Win ( double * out,
unsigned n )

Generate a Blackman window of length n.

Much lower sidelobes than Hanning/Hamming, with a wider main lobe.

Generate a Blackman window of length n.

The formula is: w[i] = 0.42

  • 0.5 * cos(2*pi*i / (n-1))
  • 0.08 * cos(4*pi*i / (n-1))

Definition at line 619 of file minidsp_core.c.

◆ MD_Gen_Hamming_Win()

void MD_Gen_Hamming_Win ( double * out,
unsigned n )

Generate a Hamming window of length n.

Similar to Hanning, but with a slightly lower first sidelobe.

Generate a Hamming window of length n.

The formula is: w[i] = 0.54 - 0.46 * cos(2*pi*i / (n-1))

Definition at line 595 of file minidsp_core.c.

◆ MD_Gen_Hann_Win()

void MD_Gen_Hann_Win ( double * out,
unsigned n )

Generate a Hanning (Hann) window of length n.

Tapers to zero at both ends and is a common default for FFT analysis.

Generate a Hanning (Hann) window of length n.

The formula is: w[i] = 0.5 * (1 - cos(2*pi*i / (n-1)))

Windowing is essential before taking an FFT because real-world signals don't start and end at exactly zero. Without a window, the abrupt edges create false high-frequency content ("spectral leakage"). The Hanning window smoothly tapers the signal to zero at both ends, reducing this artefact.

Definition at line 574 of file minidsp_core.c.

◆ MD_Gen_Kaiser_Win()

void MD_Gen_Kaiser_Win ( double * out,
unsigned n,
double beta )

Generate a Kaiser window of length n with shape parameter beta.

\[ w[i] = \frac{I_0\!\left(\beta\,\sqrt{1 - \left(\frac{2i}{n-1}-1\right)^2}\right)} {I_0(\beta)} \]

The \(\beta\) parameter controls the sidelobe/mainlobe tradeoff:

  • \(\beta \approx 5\) : ~45 dB stopband attenuation (fast/draft)
  • \(\beta \approx 10\) : ~100 dB stopband attenuation (high quality)
  • \(\beta \approx 14\) : ~120 dB stopband attenuation (mastering)
Parameters
outOutput buffer of length n (caller-allocated).
nWindow length. Must be > 0. For n == 1, outputs 1.0.
betaShape parameter (> 0 for useful windows).
double win[256];
MD_Gen_Kaiser_Win(win, 256, 10.0); // high-quality Kaiser window
void MD_Gen_Kaiser_Win(double *out, unsigned n, double beta)
Generate a Kaiser window of length n with shape parameter beta.

Generate a Kaiser window of length n with shape parameter beta.

The formula is: w[i] = I₀(β * sqrt(1 - ((2i/(n-1)) - 1)²)) / I₀(β)

The β parameter controls the sidelobe/mainlobe tradeoff:

  • β ≈ 5 → ~45 dB stopband attenuation
  • β ≈ 10 → ~100 dB stopband attenuation
  • β ≈ 14 → ~120 dB stopband attenuation

Definition at line 658 of file minidsp_core.c.

◆ MD_Gen_Rect_Win()

void MD_Gen_Rect_Win ( double * out,
unsigned n )

Generate a rectangular window of length n (all ones).

Useful as a baseline reference (equivalent to no tapering).

Generate a rectangular window of length n (all ones).

Definition at line 639 of file minidsp_core.c.

◆ MD_get_delay()

int MD_get_delay ( const double * siga,
const double * sigb,
unsigned N,
double * ent,
unsigned margin,
int weightfunc )

Estimate the delay between two signals.

Parameters
sigaFirst signal.
sigbSecond signal.
NLength of both signals.
entIf non-null, receives the normalised entropy of the correlation peak region (closer to 1.0 = less trustworthy).
marginSearch +/- this many samples around zero-lag.
weightfuncSIMP or PHAT.
Returns
Delay in samples (positive = sigb lags siga).

Estimate the delay between two signals.

The function computes the GCC between the two signals, then searches within a +/- margin window around zero-lag for the peak. The offset of that peak from zero is the estimated delay.

Parameters
sigaFirst signal (reference).
sigbSecond signal.
NLength of both signals.
entIf non-null, receives the normalised entropy of the lag values in the search window. High entropy (~1.0) means a flat, unreliable correlation; low entropy (~0.0) means a sharp, trustworthy peak.
marginHow far (in samples) to search around zero-lag.
weightfuncSIMP or PHAT.
Returns
Delay in samples.

Definition at line 290 of file minidsp_gcc.c.

◆ MD_get_multiple_delays()

void MD_get_multiple_delays ( const double ** sigs,
unsigned M,
unsigned N,
unsigned margin,
int weightfunc,
int * outdelays )

Estimate delays between a reference signal and M-1 other signals.

Parameters
sigsArray of M pointers to signals (sigs[0] is the reference).
MNumber of signals.
NLength of each signal (all must be the same length).
marginSearch +/- this many samples around zero-lag.
weightfuncSIMP or PHAT (see MD_GCC_WEIGHTING_TYPE).
outdelaysOutput array of M-1 delay values (must be pre-allocated).

Estimate delays between a reference signal and M-1 other signals.

This is a convenience wrapper that calls MD_get_delay() for each non-reference signal. A Hanning window is applied to all signals before computing the cross-correlation.

Parameters
sigsArray of M pointers to signals. sigs[0] is the reference.
MNumber of signals (must be >= 2).
NLength of every signal.
marginSearch +/- margin samples around zero-lag.
weightfuncSIMP or PHAT.
outdelaysOutput: M-1 delay values (pre-allocated by caller).

Definition at line 225 of file minidsp_gcc.c.

◆ MD_impulse()

void MD_impulse ( double * output,
unsigned N,
double amplitude,
unsigned position )

Generate a discrete impulse (Kronecker delta).

Fills the output buffer with zeros except at position, where the value is set to amplitude. A unit impulse (amplitude 1.0 at position 0) is the identity element of convolution and has a perfectly flat magnitude spectrum.

Common uses:

  • Measure a system's impulse response by feeding it through a filter.
  • Verify that MD_magnitude_spectrum() returns a flat spectrum.
  • Create delayed spikes for testing convolution and delay estimation.
Parameters
outputOutput buffer of length N (caller-allocated).
NNumber of samples to generate. Must be > 0.
amplitudeValue of the impulse spike (e.g. 1.0 for unit impulse).
positionSample index of the spike (0-based). Must be < N.
double sig[1024];
MD_impulse(sig, 1024, 1.0, 0); // unit impulse at sample 0
void MD_impulse(double *output, unsigned N, double amplitude, unsigned position)
Generate a discrete impulse (Kronecker delta).

Definition at line 69 of file minidsp_generators.c.

◆ MD_lowpass_brickwall()

void MD_lowpass_brickwall ( double * signal,
unsigned len,
double cutoff_hz,
double sample_rate )

Apply a brickwall lowpass filter to a signal in-place.

Performs an FFT, zeroes all frequency bins above the cutoff frequency, and inverse-FFTs the result. This is a "brickwall" filter: it has zero transition bandwidth, meaning content at or below the cutoff is preserved exactly and content above the cutoff is eliminated completely.

The filter operation in the frequency domain:

\[ X'(k) = \begin{cases} X(k) & \text{if } k \leq \lfloor f_c \cdot N / f_s \rfloor \\ 0 & \text{otherwise} \end{cases} \]

where \(X(k)\) is the DFT of the input, \(f_c\) is the cutoff frequency, \(N\) is the signal length, and \(f_s\) is the sample rate.

Note
Uses one-off FFTW plans (not the cached spectrum analysis plans). Suitable for offline/batch processing. Gibbs ringing occurs at the cutoff frequency; this is negligible when the cutoff is far from any frequency band of interest.
Parameters
signalSignal buffer, modified in-place (must not be NULL).
lenNumber of samples (must be > 0).
cutoff_hzCutoff frequency in Hz (must be in (0, sample_rate/2)).
sample_rateSample rate in Hz (must be > 0).
// Remove all content above 8 kHz from a 48 kHz signal
double buf[48000];
MD_sine_wave(buf, 48000, 1.0, 440.0, 48000.0);
MD_lowpass_brickwall(buf, 48000, 8000.0, 48000.0);
void MD_lowpass_brickwall(double *signal, unsigned len, double cutoff_hz, double sample_rate)
Apply a brickwall lowpass filter to a signal in-place.

Definition at line 572 of file minidsp_spectrum.c.

◆ MD_magnitude_spectrum()

void MD_magnitude_spectrum ( const double * signal,
unsigned N,
double * mag_out )

Compute the magnitude spectrum of a real-valued signal.

Given a signal of length N, this function computes the FFT and returns the magnitude |X(k)| for each frequency bin. Because the input is real-valued, the FFT output is conjugate-symmetric, so only the first N/2 + 1 bins are unique (from DC through Nyquist).

To convert bin index k to a frequency in Hz: freq_k = k * sample_rate / N

The output is not normalised by N – divide each value by N to get the "standard" DFT magnitude, or by N/2 (except DC and Nyquist) for single-sided amplitude.

Parameters
signalInput signal of length N.
NNumber of samples in the signal.
mag_outOutput array, must be pre-allocated to at least N/2 + 1 doubles. On return, mag_out[k] = |X(k)|.
Note
The caller must allocate mag_out. The required size is (N / 2 + 1) * sizeof(double).

Example:

double signal[1024];
// ... fill signal with audio samples ...
unsigned num_bins = 1024 / 2 + 1; // = 513
double *mag = malloc(num_bins * sizeof(double));
MD_magnitude_spectrum(signal, 1024, mag);
// mag[0] = DC component magnitude
// mag[k] = magnitude at frequency k * sample_rate / 1024
// mag[512] = Nyquist frequency magnitude
free(mag);
MD_shutdown(); // free cached FFT plans when done
void MD_shutdown(void)
Free all internally cached FFT plans and buffers.
void MD_magnitude_spectrum(const double *signal, unsigned N, double *mag_out)
Compute the magnitude spectrum of a real-valued signal.

This performs a real-to-complex FFT using FFTW, then computes the absolute value (magnitude) of each complex frequency bin.

For a real signal of length N, the FFT is conjugate-symmetric, so only the first N/2 + 1 bins are unique:

  • Bin 0: DC component (zero frequency)
  • Bin k: frequency = k * sample_rate / N
  • Bin N/2: Nyquist frequency (sample_rate / 2)

The magnitude is computed as: |X(k)| = sqrt( Re(X(k))^2 + Im(X(k))^2 )

The FFT plan is cached and reused across calls of the same length, following the same pattern as the GCC functions.

Parameters
signalInput signal of length N.
NNumber of samples (must be >= 2).
mag_outOutput: magnitudes for bins 0..N/2. Must be pre-allocated to N/2 + 1 doubles.

Definition at line 277 of file minidsp_spectrum.c.

◆ MD_mel_energies()

void MD_mel_energies ( const double * signal,
unsigned N,
double sample_rate,
unsigned num_mels,
double min_freq_hz,
double max_freq_hz,
double * mel_out )

Compute mel-band energies from a single frame.

Processing steps: 1) Apply an internal Hann window. 2) Compute one-sided PSD bins via FFT: |X(k)|^2 / N. 3) Apply mel filterbank weights and sum per band.

This function uses the same internal FFT cache as MD_stft() and spectrum APIs.

Parameters
signalInput frame of length N.
NFrame length / FFT size (must be >= 2).
sample_rateSampling rate in Hz (must be > 0).
num_melsNumber of mel bands (must be > 0).
min_freq_hzRequested lower frequency bound in Hz.
max_freq_hzRequested upper frequency bound in Hz (must be > min_freq_hz).
mel_outOutput mel energies, caller-allocated length num_mels.

Definition at line 532 of file minidsp_spectrum.c.

◆ MD_mel_filterbank()

void MD_mel_filterbank ( unsigned N,
double sample_rate,
unsigned num_mels,
double min_freq_hz,
double max_freq_hz,
double * filterbank_out )

Build a mel-spaced triangular filterbank matrix.

This function creates num_mels triangular filters over one-sided FFT bins (0..N/2), using the HTK mel mapping:

mel(f) = 2595 * log10(1 + f / 700)

The requested frequency range [min_freq_hz, max_freq_hz] is clamped at runtime to [0, sample_rate/2]. If the clamped range is empty, all output weights are zero.

Output layout is row-major: filterbank_out[m * (N/2 + 1) + k] where m is the mel band index and k is the FFT bin index.

Parameters
NFFT size (must be >= 2).
sample_rateSampling rate in Hz (must be > 0).
num_melsNumber of mel filters (must be > 0).
min_freq_hzRequested lower frequency bound in Hz.
max_freq_hzRequested upper frequency bound in Hz (must be > min_freq_hz).
filterbank_outOutput matrix, caller-allocated, length num_mels * (N/2 + 1) doubles.

Definition at line 514 of file minidsp_spectrum.c.

◆ MD_mfcc()

void MD_mfcc ( const double * signal,
unsigned N,
double sample_rate,
unsigned num_mels,
unsigned num_coeffs,
double min_freq_hz,
double max_freq_hz,
double * mfcc_out )

Compute mel-frequency cepstral coefficients (MFCCs) from a single frame.

Conventions used by this API:

  • HTK mel mapping for filter placement.
  • Internal Hann windowing and one-sided PSD mel energies.
  • Natural-log compression: log(max(E_mel, 1e-12)).
  • DCT-II with HTK-C0 profile: c0 uses sqrt(1/M) normalization, c_n (n>0) uses sqrt(2/M), where M is num_mels.
  • Coefficient 0 (C0) is written to mfcc_out[0].
Parameters
signalInput frame of length N.
NFrame length / FFT size (must be >= 2).
sample_rateSampling rate in Hz (must be > 0).
num_melsNumber of mel bands (must be > 0).
num_coeffsNumber of cepstral coefficients to output (must be in [1, num_mels]).
min_freq_hzRequested lower frequency bound in Hz.
max_freq_hzRequested upper frequency bound in Hz (must be > min_freq_hz).
mfcc_outOutput array, caller-allocated length num_coeffs.

Definition at line 622 of file minidsp_spectrum.c.

◆ MD_mix()

void MD_mix ( const double * a,
const double * b,
double * out,
unsigned N,
double w_a,
double w_b )

Mix (weighted sum) two signals.

Computes the element-wise weighted sum:

\[\mathrm{out}[n] = w_a \cdot a[n] + w_b \cdot b[n] \]

In-place safe: the output buffer may alias either input.

Parameters
aFirst input signal of length N.
bSecond input signal of length N.
outOutput signal of length N (caller-allocated).
NNumber of samples.
w_aWeight for signal a.
w_bWeight for signal b.
double sine[1024], noise[1024], mix[1024];
MD_sine_wave(sine, 1024, 1.0, 440.0, 44100.0);
MD_white_noise(noise, 1024, 0.1, 42);
MD_mix(sine, noise, mix, 1024, 0.8, 0.2);
void MD_white_noise(double *output, unsigned N, double amplitude, unsigned seed)
Generate Gaussian white noise.
void MD_mix(const double *a, const double *b, double *out, unsigned N, double w_a, double w_b)
Mix (weighted sum) two signals.

Mix (weighted sum) two signals.

out[n] = w_a * a[n] + w_b * b[n]

In-place safe (out may alias a or b).

Definition at line 436 of file minidsp_core.c.

◆ MD_moving_average()

void MD_moving_average ( const double * signal,
unsigned signal_len,
unsigned window_len,
double * out )

Causal moving-average FIR filter with zero-padded startup.

Computes: out[n] = (1/window_len) * sum_{k=0}^{window_len-1} signal[n-k] where out-of-range samples (n-k < 0) are treated as zero.

Parameters
signalInput signal of length signal_len.
signal_lenNumber of input samples (must be > 0).
window_lenMoving-average window length (must be > 0).
outOutput buffer of length signal_len.

Definition at line 48 of file minidsp_fir.c.

◆ MD_peak_detect()

void MD_peak_detect ( const double * a,
unsigned N,
double threshold,
unsigned min_distance,
unsigned * peaks_out,
unsigned * num_peaks_out )

Detect peaks (local maxima) in a signal.

A sample a[i] is a peak if it is strictly greater than both immediate neighbours and above the given threshold. The min_distance parameter suppresses nearby secondary peaks: after accepting a peak at index i, any candidate within min_distance indices is skipped.

Peaks are found left-to-right (deterministic tie-breaking). Endpoint samples (i=0, i=N-1) are never peaks because they lack two neighbours.

Parameters
aInput signal of length N.
NNumber of samples.
thresholdMinimum value for a peak.
min_distanceMinimum index gap between accepted peaks (>= 1).
peaks_outOutput array of peak indices (caller-allocated, worst case N elements).
num_peaks_outReceives the number of peaks found.
double sig[] = {0, 1, 3, 1, 0, 2, 5, 2, 0};
unsigned peaks[9], n;
MD_peak_detect(sig, 9, 0.0, 1, peaks, &n);
// n = 2, peaks = {2, 6} (values 3 and 5)
void MD_peak_detect(const double *a, unsigned N, double threshold, unsigned min_distance, unsigned *peaks_out, unsigned *num_peaks_out)
Detect peaks (local maxima) in a signal.

Detect peaks (local maxima) in a signal.

A sample a[i] is a peak if:

  • a[i] > a[i-1] AND a[i] > a[i+1] (strictly greater than neighbours)
  • a[i] >= threshold
  • distance from the last accepted peak >= min_distance

Endpoints (i=0, i=N-1) are never peaks.

Definition at line 349 of file minidsp_core.c.

◆ MD_phase_spectrum()

void MD_phase_spectrum ( const double * signal,
unsigned N,
double * phase_out )

Compute the one-sided phase spectrum of a real signal.

Returns the instantaneous phase angle \(\phi(k) = \arg X(k)\) for each DFT bin using an unnormalised real-to-complex FFT (FFTW r2c). The phase is expressed in radians in the range \([-\pi,\,\pi]\).

For a real signal of length \(N\), only the first \(N/2+1\) bins carry unique information (bins \(N/2+1\ldots N-1\) are conjugate-symmetric mirrors). Accordingly, phase_out must be pre-allocated to hold at least \(N/2+1\) doubles.

Interpretation:

  • A pure cosine at an integer bin \(k_0\) (exact period in \(N\) samples) produces \(\phi(k_0) = 0\).
  • A pure sine at the same bin produces \(\phi(k_0) = -\pi/2\).
  • A time-delayed signal exhibits linear phase: \(\phi(k) = -2\pi k d/N\), where \(d\) is the delay in samples.
Note
Phase values at bins where the magnitude is near zero are numerically unreliable. Always examine MD_magnitude_spectrum() alongside the phase spectrum to identify significant bins.
Parameters
[in]signalInput signal of length N.
[in]NSignal length (must be >= 2).
[out]phase_outPre-allocated array of at least N/2+1 doubles that receives the phase in radians.

Example

unsigned N = 1024;
double *sig = malloc(N * sizeof(double));
// ... fill sig ...
unsigned num_bins = N / 2 + 1;
double *phase = malloc(num_bins * sizeof(double));
MD_phase_spectrum(sig, N, phase);
// phase[k] in [-M_PI, M_PI]
free(sig);
free(phase);
void MD_phase_spectrum(const double *signal, unsigned N, double *phase_out)
Compute the one-sided phase spectrum of a real signal.
See also
MD_magnitude_spectrum(), MD_power_spectral_density(), MD_shutdown()

Compute the one-sided phase spectrum of a real signal.

The phase is the argument (angle) of each complex DFT coefficient: phi(k) = atan2(Im(X(k)), Re(X(k)))

This reuses the same FFT cache as MD_magnitude_spectrum() and MD_power_spectral_density() – no additional plan allocation.

Phase is scale-invariant (multiplying a signal by a positive constant does not change its phase), so no normalisation by N is needed.

Parameters
signalInput signal of length N.
NNumber of samples (must be >= 2).
phase_outOutput: phase in radians for bins 0..N/2. Must be pre-allocated to N/2 + 1 doubles.

Definition at line 357 of file minidsp_spectrum.c.

◆ MD_power()

double MD_power ( const double * a,
unsigned N )

Compute signal power: energy divided by the number of samples.

Compute signal power: energy divided by the number of samples.

P = E / N

Power is the "average energy per sample". It lets you compare signals of different lengths on an equal footing.

Definition at line 61 of file minidsp_core.c.

◆ MD_power_db()

double MD_power_db ( const double * a,
unsigned N )

Compute signal power in decibels: 10 * log10(power).

Compute signal power in decibels: 10 * log10(power).

P_dB = 10 * log10(P)

Decibels are a logarithmic scale commonly used in audio engineering. Every +10 dB means the power is 10x larger. A floor of 1e-10 is used to avoid log(0), which would be negative infinity.

Definition at line 77 of file minidsp_core.c.

◆ MD_power_spectral_density()

void MD_power_spectral_density ( const double * signal,
unsigned N,
double * psd_out )

Compute the power spectral density (PSD) of a real-valued signal.

The PSD describes how a signal's power is distributed across frequencies. While the magnitude spectrum tells you the amplitude at each frequency, the PSD tells you the power – useful for noise analysis, SNR estimation, and comparing signals of different lengths.

This function computes the "periodogram" estimator:

PSD[k] = |X(k)|^2 / N = (Re(X(k))^2 + Im(X(k))^2) / N

where X(k) is the DFT of the input signal (unnormalised, as computed by FFTW).

Relationship to the magnitude spectrum: PSD[k] = |X(k)|^2 / N = (magnitude[k])^2 / N

Parseval's theorem (energy conservation): The one-sided PSD sums to the total signal energy: PSD[0] + 2 * sum(PSD[1..N/2-1]) + PSD[N/2] = sum(x[n]^2)

Parameters
signalInput signal of length N.
NNumber of samples in the signal (must be >= 2).
psd_outOutput array, must be pre-allocated to at least N/2 + 1 doubles. On return, psd_out[k] = |X(k)|^2 / N.
Note
The caller must allocate psd_out. The required size is (N / 2 + 1) * sizeof(double).

Example:

double signal[1024];
// ... fill signal with audio samples ...
unsigned num_bins = 1024 / 2 + 1; // = 513
double *psd = malloc(num_bins * sizeof(double));
MD_power_spectral_density(signal, 1024, psd);
// psd[0] = DC power
// psd[k] = power at frequency k * sample_rate / 1024
// psd[512] = Nyquist frequency power
free(psd);
MD_shutdown(); // free cached FFT plans when done
void MD_power_spectral_density(const double *signal, unsigned N, double *psd_out)
Compute the power spectral density (PSD) of a real-valued signal.

The PSD is the "periodogram" estimator: PSD[k] = |X(k)|^2 / N. It reuses the same FFT cache as MD_magnitude_spectrum() – both perform the same real-to-complex FFT, only the post-processing differs.

We compute |X(k)|^2 = re^2 + im^2 directly from the real and imaginary parts, rather than calling cabs() (which computes sqrt(re^2 + im^2)) and then squaring. This avoids a redundant sqrt and is both faster and more numerically precise.

Parameters
signalInput signal of length N.
NNumber of samples (must be >= 2).
psd_outOutput: PSD for bins 0..N/2. Must be pre-allocated to N/2 + 1 doubles.

Definition at line 315 of file minidsp_spectrum.c.

◆ MD_resample()

unsigned MD_resample ( const double * input,
unsigned input_len,
double * output,
unsigned max_output_len,
double in_rate,
double out_rate,
unsigned num_zero_crossings,
double kaiser_beta )

Resample a signal from one sample rate to another using polyphase sinc interpolation.

Uses a fixed table of 512 sub-phases with linear interpolation and a Kaiser-windowed sinc anti-aliasing filter. Anti-aliasing cutoff is automatically set to \(\min(\mathrm{in\_rate}, \mathrm{out\_rate})/2\).

Parameters
inputInput signal of length input_len.
input_lenNumber of input samples (must be > 0).
outputOutput buffer (caller-allocated). Use MD_resample_output_len() to size it.
max_output_lenCapacity of output buffer. Must be >= MD_resample_output_len(input_len, in_rate, out_rate).
in_rateInput sample rate in Hz (must be > 0).
out_rateOutput sample rate in Hz (must be > 0).
num_zero_crossingsNumber of sinc zero-crossings per side. Higher = better quality. Typical: 32.
kaiser_betaKaiser window shape parameter. Typical: 10.0 for ~100 dB stopband.
Returns
Number of samples written to output.
double in[44100], out[48000];
MD_sine_wave(in, 44100, 1.0, 440.0, 44100.0);
unsigned n = MD_resample(in, 44100, out, 48000,
44100.0, 48000.0, 32, 10.0);
unsigned MD_resample(const double *input, unsigned input_len, double *output, unsigned max_output_len, double in_rate, double out_rate, unsigned num_zero_crossings, double kaiser_beta)
Resample a signal from one sample rate to another using polyphase sinc interpolation.

Definition at line 21 of file minidsp_resample.c.

◆ MD_resample_output_len()

unsigned MD_resample_output_len ( unsigned input_len,
double in_rate,
double out_rate )

Compute the output buffer size needed for resampling.

Returns \(\lceil \mathrm{input\_len} \times \mathrm{out\_rate} / \mathrm{in\_rate} \rceil\).

Parameters
input_lenNumber of input samples (must be > 0).
in_rateInput sample rate in Hz (must be > 0).
out_rateOutput sample rate in Hz (must be > 0).
Returns
Required output buffer length.
unsigned n = MD_resample_output_len(44100, 44100.0, 48000.0); // 48000
unsigned MD_resample_output_len(unsigned input_len, double in_rate, double out_rate)
Compute the output buffer size needed for resampling.

Definition at line 12 of file minidsp_resample.c.

◆ MD_rms()

double MD_rms ( const double * a,
unsigned N )

Compute the root mean square (RMS) of a signal.

RMS is the standard measure of signal "loudness":

\[\mathrm{RMS} = \sqrt{\frac{1}{N}\sum_{n=0}^{N-1} x[n]^2} \]

Equivalently, sqrt(MD_power(a, N)). A unit-amplitude sine wave has RMS = 1/sqrt(2) ~ 0.707. A DC signal of value c has RMS = |c|.

Parameters
aInput signal of length N.
NNumber of samples. Must be > 0.
Returns
RMS value (always >= 0).
double sig[1024];
MD_sine_wave(sig, 1024, 1.0, 440.0, 44100.0);
double rms = MD_rms(sig, 1024); // ~ 0.707
double MD_rms(const double *a, unsigned N)
Compute the root mean square (RMS) of a signal.

Compute the root mean square (RMS) of a signal.

RMS = sqrt(1/N * sum(x[n]^2)) = sqrt(power)

Definition at line 288 of file minidsp_core.c.

◆ MD_sawtooth_wave()

void MD_sawtooth_wave ( double * output,
unsigned N,
double amplitude,
double freq,
double sample_rate )

Generate a sawtooth wave.

Fills the output buffer with a sawtooth wave that ramps linearly from −amplitude to +amplitude over each period:

\[x[n] = A \left(\frac{\phi}{\pi} - 1\right) \]

where \(\phi = 2\pi f n / f_s \pmod{2\pi}\).

A sawtooth wave contains all integer harmonics (1f, 2f, 3f, …) whose amplitudes decay as 1/k — useful for demonstrating richer harmonic content compared to the square wave's odd-only series.

Parameters
outputOutput buffer of length N (caller-allocated).
NNumber of samples to generate. Must be > 0.
amplitudePeak amplitude of the sawtooth wave (e.g. 1.0).
freqFrequency in Hz.
sample_rateSampling rate in Hz. Must be > 0.
double sig[1024];
MD_sawtooth_wave(sig, 1024, 1.0, 440.0, 44100.0);
void MD_sawtooth_wave(double *output, unsigned N, double amplitude, double freq, double sample_rate)
Generate a sawtooth wave.

Definition at line 146 of file minidsp_generators.c.

◆ MD_scale()

double MD_scale ( double in,
double oldmin,
double oldmax,
double newmin,
double newmax )

Map a single value from one range to another.

Example: MD_scale(5, 0, 10, 0, 100) returns 50.

Map a single value from one range to another.

Formula: out = (in - oldmin) * (newmax - newmin) / (oldmax - oldmin) + newmin

For example, mapping a value of 5 from the range [0, 10] into [0, 100] gives 50. This is sometimes called "lerp" (linear interpolation).

Definition at line 97 of file minidsp_core.c.

◆ MD_scale_vec()

void MD_scale_vec ( double * in,
double * out,
unsigned N,
double oldmin,
double oldmax,
double newmin,
double newmax )

Map every element of a vector from one range to another.

Map every element of a vector from one range to another.

Definition at line 107 of file minidsp_core.c.

◆ MD_set_error_handler()

void MD_set_error_handler ( MD_ErrorHandler handler)

Install a custom error handler.

When a miniDSP function detects a precondition violation (NULL pointer, invalid size, etc.) it calls the active handler instead of aborting. The default handler prints a message to stderr.

Pass NULL to restore the default handler.

Thread safety
This function must be called once, before any other MD_* call. It must not be called concurrently with any other miniDSP function.
// Example: redirect miniDSP errors to an application log
static void my_handler(MD_ErrorCode code, const char *fn, const char *msg) {
app_log(LOG_WARN, "miniDSP error %d in %s: %s", code, fn, msg);
}
int main(void) {
MD_set_error_handler(my_handler);
// ... use miniDSP ...
}
MD_ErrorCode
Error codes reported by miniDSP when a precondition is violated.
Definition minidsp.h:61
void MD_set_error_handler(MD_ErrorHandler handler)
Install a custom error handler.

Definition at line 27 of file minidsp_error.c.

◆ MD_shepard_tone()

void MD_shepard_tone ( double * output,
unsigned N,
double amplitude,
double base_freq,
double sample_rate,
double rate_octaves_per_sec,
unsigned num_octaves )

Generate a Shepard tone — the auditory illusion of endlessly rising or falling pitch.

A Shepard tone superimposes several sine waves spaced one octave apart. Each tone glides continuously upward (or downward) in pitch while a Gaussian spectral envelope — fixed in log-frequency space — fades tones in at one end and out at the other. The result is a sound that seems to rise (or fall) forever without ever actually leaving its frequency range.

Signal model. At time \(t = n / f_s\) the output sample is:

\[ x[n] \;=\; A_\mathrm{norm}\!\sum_k \underbrace{ \exp\!\Bigl(-\frac{d_k(t)^2}{2\sigma^2}\Bigr) }_{\text{Gaussian envelope}} \;\sin\!\bigl(\varphi_k(n)\bigr) \]

where the octave distance from the Gaussian centre is

\[ d_k(t) = k - c + R\,t, \qquad c = \frac{L-1}{2}, \qquad \sigma = \frac{L}{4} \]

and the instantaneous frequency of layer \(k\) is \(f_k(t) = f_\text{base}\cdot 2^{d_k(t)}\). The phase \(\varphi_k\) is accumulated sample-by-sample from \(f_k\) so that each tone glides smoothly. \(R\) is rate_octaves_per_sec and \(L\) is num_octaves. \(A_\mathrm{norm}\) scales the peak to amplitude.

The sum ranges over all integer indices \(k\) for which \(|d_k(t)|\) is within \(5\sigma\) at some point during the signal, ensuring enough layers are present to sustain the illusion for the full duration.

Parameters
outputOutput buffer of length N (caller-allocated).
NNumber of samples to generate. Must be > 0.
amplitudePeak amplitude of the output signal.
base_freqCentre frequency of the Gaussian envelope in Hz. Typical values: 200–600 Hz.
sample_rateSampling rate in Hz. Must be > 0.
rate_octaves_per_secGlissando rate in octaves per second. Positive = rising, negative = falling, 0 = static chord.
num_octavesNumber of audible octave layers (width of the Gaussian bell). Typical values: 6–10. Must be > 0.
// 5 seconds of endlessly rising Shepard tone at 44.1 kHz
unsigned N = 5 * 44100;
double *sig = malloc(N * sizeof(double));
MD_shepard_tone(sig, N, 0.8, 440.0, 44100.0, 0.5, 8);
// sig[] now sounds like it rises forever
free(sig);
void MD_shepard_tone(double *output, unsigned N, double amplitude, double base_freq, double sample_rate, double rate_octaves_per_sec, unsigned num_octaves)
Generate a Shepard tone — the auditory illusion of endlessly rising or falling pitch.

Definition at line 160 of file minidsp_generators.c.

◆ MD_shutdown()

void MD_shutdown ( void )

Free all internally cached FFT plans and buffers.

Call when done.

Definition at line 238 of file minidsp_spectrum.c.

◆ MD_sinc()

double MD_sinc ( double x)

Normalized sinc function: \(\mathrm{sinc}(x) = \sin(\pi x)/(\pi x)\).

\[ \mathrm{sinc}(x) = \begin{cases} 1 & \text{if } |x| < 10^{-12} \\ \dfrac{\sin(\pi x)}{\pi x} & \text{otherwise} \end{cases} \]

Parameters
xInput value.
Returns
sinc(x). Equals 1 at zero, 0 at nonzero integers.
double v = MD_sinc(0.5); // ≈ 0.6366 (2/π)
double MD_sinc(double x)
Normalized sinc function: .

Normalized sinc function: \(\mathrm{sinc}(x) = \sin(\pi x)/(\pi x)\).

Returns 1.0 for |x| < 1e-12 to avoid division by zero.

Definition at line 552 of file minidsp_core.c.

◆ MD_sine_wave()

void MD_sine_wave ( double * output,
unsigned N,
double amplitude,
double freq,
double sample_rate )

Generate a sine wave.

Fills output[i] = amplitude * sin(2π * freq * i / sample_rate) for i in [0, N).

This is the simplest test signal in DSP — a pure tone at a single frequency. Use it to verify filter responses, check FFT bin alignment, or provide a clean input for any processing chain.

Parameters
outputOutput buffer of length N (caller-allocated).
NNumber of samples to generate. Must be > 0.
amplitudePeak amplitude of the sine wave (e.g. 1.0).
freqFrequency in Hz.
sample_rateSampling rate in Hz. Must be > 0.
double sig[1024];
MD_sine_wave(sig, 1024, 1.0, 440.0, 44100.0); // 440 Hz A4 tone

Definition at line 16 of file minidsp_generators.c.

◆ MD_spectrogram_text()

unsigned MD_spectrogram_text ( double * output,
unsigned max_len,
const char * text,
double freq_lo,
double freq_hi,
double duration_sec,
double sample_rate )

Synthesise audio that displays readable text in a spectrogram.

Given a short string, the function rasterises it with a built-in 5x7 bitmap font. Each bitmap column becomes a time slice; each "on" pixel becomes a sine wave at the corresponding frequency between freq_lo and freq_hi. A 3 ms raised-cosine crossfade suppresses clicks at column boundaries. The output is normalised to 0.9 peak amplitude.

Parameters
outputOutput buffer (caller-allocated).
max_lenSize of output in samples (must be >= returned value).
textPrintable ASCII string to render (must be non-empty).
freq_loLowest frequency in Hz (bottom of text).
freq_hiHighest frequency in Hz (top of text, must be < Nyquist).
duration_secTotal duration in seconds.
sample_rateSample rate in Hz.
Returns
Number of samples written to output.
double buf[64000];
unsigned n = MD_spectrogram_text(buf, 64000, "HELLO",
200.0, 7500.0, 2.0, 16000.0);
// buf[0..n-1] now contains synthesised audio; view its spectrogram
// to see "HELLO" spelled out in the frequency domain.
unsigned MD_spectrogram_text(double *output, unsigned max_len, const char *text, double freq_lo, double freq_hi, double duration_sec, double sample_rate)
Synthesise audio that displays readable text in a spectrogram.

Definition at line 144 of file minidsp_spectext.c.

◆ MD_square_wave()

void MD_square_wave ( double * output,
unsigned N,
double amplitude,
double freq,
double sample_rate )

Generate a square wave.

Fills the output buffer with a bipolar square wave that alternates between +amplitude and −amplitude at the given frequency:

\[x[n] = \begin{cases} +A & 0 < \phi < \pi \\ -A & \pi < \phi < 2\pi \\ 0 & \phi = 0 \text{ or } \phi = \pi \end{cases} \]

where \(\phi = 2\pi f n / f_s \pmod{2\pi}\).

A square wave contains only odd harmonics (1f, 3f, 5f, …) whose amplitudes decay as 1/k — a classic demonstration of the Fourier series and the Gibbs phenomenon.

Parameters
outputOutput buffer of length N (caller-allocated).
NNumber of samples to generate. Must be > 0.
amplitudePeak amplitude of the square wave (e.g. 1.0).
freqFrequency in Hz.
sample_rateSampling rate in Hz. Must be > 0.
double sig[1024];
MD_square_wave(sig, 1024, 1.0, 440.0, 44100.0);
void MD_square_wave(double *output, unsigned N, double amplitude, double freq, double sample_rate)
Generate a square wave.

Definition at line 127 of file minidsp_generators.c.

◆ MD_steg_capacity()

unsigned MD_steg_capacity ( unsigned signal_len,
double sample_rate,
int method )

Compute the maximum message length (in bytes) that can be hidden.

Parameters
signal_lenLength of the host signal in samples.
sample_rateSample rate in Hz.
methodMD_STEG_LSB, MD_STEG_FREQ_BAND, or MD_STEG_SPECTEXT.
Returns
Maximum message bytes that fit (excluding null terminator).

Definition at line 571 of file minidsp_steg.c.

◆ MD_steg_decode()

unsigned MD_steg_decode ( const double * stego,
unsigned signal_len,
double sample_rate,
char * message_out,
unsigned max_msg_len,
int method )

Decode a secret message from a stego audio signal.

Reads the 32-bit length header, then extracts message bytes using the same method that was used for encoding.

Parameters
stegoThe stego signal containing the hidden message.
signal_lenLength of the stego signal in samples.
sample_rateSample rate in Hz.
message_outOutput buffer for the decoded message (caller-allocated).
max_msg_lenSize of message_out buffer (including null terminator).
methodMD_STEG_LSB, MD_STEG_FREQ_BAND, or MD_STEG_SPECTEXT.
Returns
Number of message bytes decoded (0 if none found).
char recovered[256];
unsigned n = MD_steg_decode(stego, 44100, 44100.0,
recovered, 256, MD_STEG_LSB);
printf("Hidden message: %s\n", recovered);
unsigned MD_steg_decode(const double *stego, unsigned signal_len, double sample_rate, char *message_out, unsigned max_msg_len, int method)
Decode a secret message from a stego audio signal.
#define MD_STEG_LSB
Steganography method: least-significant-bit encoding.
Definition minidsp.h:1538

Definition at line 656 of file minidsp_steg.c.

◆ MD_steg_decode_bytes()

unsigned MD_steg_decode_bytes ( const double * stego,
unsigned signal_len,
double sample_rate,
unsigned char * data_out,
unsigned max_len,
int method )

Decode binary data from a stego audio signal.

Works like MD_steg_decode() but writes raw bytes without null termination, suitable for recovering binary payloads.

Parameters
stegoThe stego signal containing the hidden data.
signal_lenLength of the stego signal in samples.
sample_rateSample rate in Hz.
data_outOutput buffer for the decoded bytes (caller-allocated).
max_lenMaximum number of bytes to write to data_out.
methodMD_STEG_LSB, MD_STEG_FREQ_BAND, or MD_STEG_SPECTEXT.
Returns
Number of data bytes decoded (0 if none found).
unsigned char recovered[1024];
unsigned n = MD_steg_decode_bytes(stego, 44100, 44100.0,
recovered, 1024, MD_STEG_LSB);
// recovered[0..n-1] contains the original binary data
unsigned MD_steg_decode_bytes(const double *stego, unsigned signal_len, double sample_rate, unsigned char *data_out, unsigned max_len, int method)
Decode binary data from a stego audio signal.

Definition at line 625 of file minidsp_steg.c.

◆ MD_steg_detect()

int MD_steg_detect ( const double * signal,
unsigned signal_len,
double sample_rate,
int * payload_type_out )

Detect which steganography method (if any) was used to encode a signal.

Probes the signal for a valid steganographic header using both LSB and frequency-band (BFSK) methods. If a valid header is found, returns the method identifier and optionally the payload type (text or binary).

BFSK detection is only attempted when sample_rate >= 40000 Hz. If both methods appear valid, BFSK is preferred (lower false-positive rate).

Parameters
signalThe signal to inspect.
signal_lenLength of the signal in samples.
sample_rateSample rate in Hz.
payload_type_outIf non-null, receives MD_STEG_TYPE_TEXT or MD_STEG_TYPE_BINARY when a method is detected.
Returns
MD_STEG_LSB, MD_STEG_FREQ_BAND, MD_STEG_SPECTEXT, or -1 if no steganographic content is detected.
int payload_type;
int method = MD_steg_detect(signal, signal_len, 44100.0, &payload_type);
if (method >= 0) {
printf("Detected %s payload (%s)\n",
payload_type == MD_STEG_TYPE_BINARY ? "binary" : "text",
method == MD_STEG_LSB ? "LSB" : "BFSK");
}
#define MD_STEG_TYPE_BINARY
Payload type flag: binary (raw byte buffer).
Definition minidsp.h:1561
int MD_steg_detect(const double *signal, unsigned signal_len, double sample_rate, int *payload_type_out)
Detect which steganography method (if any) was used to encode a signal.

Definition at line 670 of file minidsp_steg.c.

◆ MD_steg_encode()

unsigned MD_steg_encode ( const double * host,
double * output,
unsigned signal_len,
double sample_rate,
const char * message,
int method )

Encode a secret message into a host audio signal.

The host signal is copied to output, then the message is embedded using the selected method. A 32-bit length header is prepended so that MD_steg_decode() can recover the message without knowing its length in advance.

  • MD_STEG_LSB — flips the least-significant bit of a 16-bit PCM representation of each sample. Distortion is at most ±1/32768 (≈ −90 dB). Works at any sample rate.
  • MD_STEG_FREQ_BAND — adds a low-amplitude BFSK tone in the near-ultrasonic band (18.5 / 19.5 kHz). Requires sample_rate >= 40000 Hz so the carriers remain below Nyquist.
  • MD_STEG_SPECTEXT — hybrid: LSB data + spectrogram text art in the 18–23.5 kHz band. Auto-upsamples to 48 kHz; output buffer must be sized for the 48 kHz signal length when input rate < 48 kHz.
Parameters
hostInput host signal (not modified).
outputOutput stego signal (caller-allocated; for MD_STEG_SPECTEXT with sample_rate < 48 kHz, must hold MD_resample_output_len(signal_len, sample_rate, 48000) samples).
signal_lenLength of host and output in samples.
sample_rateSample rate in Hz.
messageNull-terminated message string to hide.
methodMD_STEG_LSB, MD_STEG_FREQ_BAND, or MD_STEG_SPECTEXT.
Returns
Number of message bytes encoded (0 on failure).
double host[44100], stego[44100];
MD_sine_wave(host, 44100, 0.8, 440.0, 44100.0);
unsigned n = MD_steg_encode(host, stego, 44100, 44100.0,
"secret", MD_STEG_LSB);
unsigned MD_steg_encode(const double *host, double *output, unsigned signal_len, double sample_rate, const char *message, int method)
Encode a secret message into a host audio signal.

Definition at line 646 of file minidsp_steg.c.

◆ MD_steg_encode_bytes()

unsigned MD_steg_encode_bytes ( const double * host,
double * output,
unsigned signal_len,
double sample_rate,
const unsigned char * data,
unsigned data_len,
int method )

Encode arbitrary binary data into a host audio signal.

Works like MD_steg_encode() but accepts a raw byte buffer instead of a null-terminated string, so it can embed data containing 0x00 bytes (e.g. images, compressed archives, cryptographic keys).

Parameters
hostInput host signal (not modified).
outputOutput stego signal (caller-allocated, same length).
signal_lenLength of host and output in samples.
sample_rateSample rate in Hz.
dataPointer to the binary data to hide.
data_lenLength of data in bytes.
methodMD_STEG_LSB, MD_STEG_FREQ_BAND, or MD_STEG_SPECTEXT.
Returns
Number of data bytes encoded (0 on failure).
double host[44100], stego[44100];
MD_sine_wave(host, 44100, 0.8, 440.0, 44100.0);
unsigned char png_data[332];
// ... read PNG file into png_data ...
unsigned n = MD_steg_encode_bytes(host, stego, 44100, 44100.0,
png_data, 332, MD_STEG_LSB);
unsigned MD_steg_encode_bytes(const double *host, double *output, unsigned signal_len, double sample_rate, const unsigned char *data, unsigned data_len, int method)
Encode arbitrary binary data into a host audio signal.

Definition at line 616 of file minidsp_steg.c.

◆ MD_stft()

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.

The STFT slides a Hanning-windowed FFT over the signal in steps of hop samples, producing a time-frequency magnitude matrix.

For each frame f starting at sample f * hop, the function:

  1. Multiplies the frame by a Hanning window.
  2. Computes the real-to-complex FFT using FFTW.
  3. Stores the magnitudes |X(k)| for bins 0..N/2 in the output.

The STFT formula for frame f and bin k is:

X_f(k) = SUM_{n=0}^{N-1} w[n] * x[f*hop + n] * e^{-j2pi*k*n/N}

mag_out[f * (N/2+1) + k] = |X_f(k)|

where w[n] is the Hanning window.

The output is not normalised by N – divide each value by N to get the "standard" DFT magnitude, consistent with MD_magnitude_spectrum().

The STFT reuses the same cached FFT plan as MD_magnitude_spectrum() and MD_power_spectral_density(). Only the Hanning window buffer is separate.

Parameters
signalInput signal.
signal_lenTotal number of samples in the signal.
NFFT window size (must be >= 2).
hopHop size in samples (must be >= 1).
mag_outOutput array (row-major). Must be pre-allocated to at least MD_stft_num_frames(signal_len, N, hop) * (N/2+1) doubles. On return, mag_out[f*(N/2+1) + k] = |X_f(k)|.
Note
If signal_len < N, the function returns immediately without writing any output (zero frames fit). Use MD_stft_num_frames() to check in advance.
The caller must allocate mag_out. A typical pattern:
unsigned N = 512;
unsigned hop = 128;
unsigned num_frames = MD_stft_num_frames(signal_len, N, hop);
unsigned num_bins = N / 2 + 1;
double *mag_out = malloc(num_frames * num_bins * sizeof(double));
MD_stft(signal, signal_len, N, hop, mag_out);
// mag_out[f * num_bins + k] = |X_f(k)|
// Convert bin k to Hz: freq_hz = k * sample_rate / N
// Convert frame f to seconds: time_s = (double)(f * hop) / sample_rate
free(mag_out);
MD_shutdown(); // free cached FFT plans when done
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.

Compute the Short-Time Fourier Transform (STFT) of a real-valued signal.

Slides a Hanning-windowed r2c FFT over the signal in steps of hop samples. For each frame, the window is applied by multiplying directly into the shared _spec_in buffer (no separate memcpy pass), then FFTW executes the plan and magnitudes |X(k)| are written to the output row.

The shared spec* plan is reused so that interleaving calls to MD_stft(), MD_magnitude_spectrum(), and MD_power_spectral_density() with the same N incurs no extra plan-rebuild overhead.

Parameters
signalInput signal.
signal_lenNumber of samples (0 frames if < N, see header).
NFFT window size (>= 2).
hopHop size (>= 1).
mag_outRow-major output: mag_out[f*(N/2+1) + k] = |X_f(k)|. Must be pre-allocated by caller.

Definition at line 479 of file minidsp_spectrum.c.

◆ MD_stft_num_frames()

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.

The formula is: num_frames = (signal_len - N) / hop + 1 when signal_len >= N num_frames = 0 when signal_len < N

Use this function to size the output buffer before calling MD_stft().

Parameters
signal_lenTotal number of samples in the signal.
NFFT window size (samples per frame).
hopHop size (samples between successive frame starts).
Returns
Number of complete frames that fit in the signal.

Example:

// 1 s of audio at 16 kHz, 32 ms window, 8 ms hop
unsigned signal_len = 16000;
unsigned N = 512; // 32 ms at 16 kHz
unsigned hop = 128; // 8 ms (75% overlap)
unsigned num_frames = MD_stft_num_frames(signal_len, N, hop);
// num_frames = (16000 - 512) / 128 + 1 = 121

Compute the number of STFT frames for the given signal length and parameters.

Returns (signal_len - N) / hop + 1 when signal_len >= N, else 0. Integer division truncates, so only complete frames are counted.

Definition at line 454 of file minidsp_spectrum.c.

◆ MD_tremolo()

void MD_tremolo ( const double * in,
double * out,
unsigned N,
double rate_hz,
double depth,
double sample_rate )

Tremolo effect (amplitude modulation by a sinusoidal LFO).

The modulation gain is:

\[g[n] = (1 - depth) + depth \cdot \frac{1 + \sin(2\pi f_{LFO} n / f_s)}{2} \]

so \(g[n]\) ranges from \(1-depth\) to \(1\).

Output:

\[y[n] = g[n] \cdot x[n] \]

In-place safe: out may alias in.

Parameters
inInput signal of length N.
outOutput signal of length N (caller-allocated).
NNumber of samples.
rate_hzLFO rate in Hz (must be >= 0).
depthModulation depth in [0, 1].
sample_rateSampling rate in Hz (must be > 0).

Definition at line 477 of file minidsp_core.c.

◆ MD_vad_calibrate()

void MD_vad_calibrate ( MD_vad_state * state,
const double * signal,
unsigned N,
double sample_rate )

Feed a known-silence frame to seed the adaptive normalization.

Computes all five features and updates the EMA min/max estimates without running the state machine or producing a decision. Call this on several silence frames before processing live audio to improve initial normalization accuracy.

Parameters
stateVAD state (must be initialized).
signalFrame samples of length N.
NFrame length in samples (must be >= 2).
sample_rateSample rate in Hz (must be > 0).
// Calibrate on 10 frames of silence
double silence[256] = {0};
for (int i = 0; i < 10; i++)
MD_vad_calibrate(&st, silence, 256, 16000.0);
void MD_vad_calibrate(MD_vad_state *state, const double *signal, unsigned N, double sample_rate)
Feed a known-silence frame to seed the adaptive normalization.
See also
MD_vad_init(), MD_vad_process_frame()

Definition at line 208 of file minidsp_vad.c.

◆ MD_vad_default_params()

void MD_vad_default_params ( MD_vad_params * params)

Populate a VAD params struct with optimized defaults.

Default values (F2-optimized, recall-biased):

Parameter Value
weight (energy) 0.723068
weight (zcr) 0.063948
weight (entropy) 0.005964
weight (flatness) 0.048865
weight (band ratio) 0.158156
threshold 0.245332
onset_frames 1
hangover_frames 22
adaptation_rate 0.012755
band_low_hz 126.4
band_high_hz 2899.3
Note
These defaults were optimized via a 300-trial Optuna search on LibriVAD train-clean-100 (all noise types, all SNRs), maximizing F2 (beta=2). Baseline F2=0.837 improved to F2=0.933 (P=0.782, R=0.981). See the VAD tutorial guide for full methodology and per-condition results.
Parameters
paramsOutput params struct. Must not be NULL.
p.threshold = 0.4; // raise threshold for more precision
void MD_vad_default_params(MD_vad_params *params)
Populate a VAD params struct with optimized defaults.
Parameters for the VAD detector.
Definition minidsp.h:1803
double threshold
Decision threshold (0.0–1.0).
Definition minidsp.h:1805
See also
MD_vad_init(), MD_vad_process_frame()

Definition at line 166 of file minidsp_vad.c.

◆ MD_vad_init()

void MD_vad_init ( MD_vad_state * state,
const MD_vad_params * params )

Initialize VAD state from params.

If params is NULL, default params are used (equivalent to calling MD_vad_default_params() first). After initialization the detector is in the SILENCE state with all counters at zero.

Parameters
stateOutput state struct. Must not be NULL.
paramsParameters to copy, or NULL for defaults.
MD_vad_init(&st, NULL); // use defaults
void MD_vad_init(MD_vad_state *state, const MD_vad_params *params)
Initialize VAD state from params.
Internal state for the VAD detector.
Definition minidsp.h:1819
See also
MD_vad_default_params(), MD_vad_process_frame()

Definition at line 187 of file minidsp_vad.c.

◆ MD_vad_process_frame()

int MD_vad_process_frame ( MD_vad_state * state,
const double * signal,
unsigned N,
double sample_rate,
double * score_out,
double * features_out )

Process one audio frame and return a binary speech decision.

Processing pipeline:

  1. Extract five raw features (energy, ZCR, spectral entropy, spectral flatness, band energy ratio).
  2. Update adaptive normalization (EMA min/max).
  3. Normalize features to [0.0, 1.0].
  4. Compute weighted score:

    \[ S = \sum_{i=0}^{4} w_i \cdot \hat{f}_i \]

  5. Apply onset/hangover state machine.
Parameters
stateVAD state (must be initialized).
signalFrame samples of length N.
NFrame length in samples (must be >= 2).
sample_rateSample rate in Hz (must be > 0).
score_outIf non-NULL, receives the combined score.
features_outIf non-NULL, receives MD_VAD_NUM_FEATURES normalized feature values in [0.0, 1.0].
Returns
1 if speech detected, 0 if silence.
double frame[256];
double score;
double feats[MD_VAD_NUM_FEATURES];
// ... fill frame ...
int decision = MD_vad_process_frame(&st, frame, 256, 16000.0,
&score, feats);
#define MD_VAD_NUM_FEATURES
Total number of features.
Definition minidsp.h:1794
int MD_vad_process_frame(MD_vad_state *state, const double *signal, unsigned N, double sample_rate, double *score_out, double *features_out)
Process one audio frame and return a binary speech decision.
See also
MD_energy(), MD_zero_crossing_rate(), MD_power_spectral_density()

Definition at line 224 of file minidsp_vad.c.

◆ MD_white_noise()

void MD_white_noise ( double * output,
unsigned N,
double amplitude,
unsigned seed )

Generate Gaussian white noise.

Fills output with normally distributed random samples (mean 0, standard deviation amplitude) using the Box-Muller transform. White noise has equal energy at all frequencies – its power spectral density is approximately flat.

Use white noise to test filters, measure impulse responses, or as an additive noise source for SNR experiments.

Parameters
outputOutput buffer of length N (caller-allocated).
NNumber of samples to generate. Must be > 0.
amplitudeStandard deviation of the noise (e.g. 1.0).
seedSeed for the random number generator. Using the same seed produces the same output sequence, which is useful for reproducible tests.
double noise[4096];
MD_white_noise(noise, 4096, 1.0, 42); // reproducible Gaussian noise

Definition at line 27 of file minidsp_generators.c.

◆ MD_zero_crossing_rate()

double MD_zero_crossing_rate ( const double * a,
unsigned N )

Compute the zero-crossing rate of a signal.

The zero-crossing rate counts how often the signal changes sign, normalised by the number of adjacent pairs:

\[\mathrm{ZCR} = \frac{1}{N-1}\sum_{n=1}^{N-1} \mathbf{1}\!\bigl[\mathrm{sgn}(x[n]) \ne \mathrm{sgn}(x[n-1])\bigr] \]

Returns a value in [0.0, 1.0]. High ZCR indicates noise or high-frequency content; low ZCR indicates tonal or low-frequency content. Zero is treated as non-negative (standard convention).

Parameters
aInput signal of length N.
NNumber of samples. Must be > 1.
Returns
Zero-crossing rate in [0.0, 1.0].
double sig[4096];
MD_sine_wave(sig, 4096, 1.0, 1000.0, 16000.0);
double zcr = MD_zero_crossing_rate(sig, 4096);
// zcr ~ 2 * 1000 / 16000 = 0.125
double MD_zero_crossing_rate(const double *a, unsigned N)
Compute the zero-crossing rate of a signal.

Compute the zero-crossing rate of a signal.

Returns a value in [0.0, 1.0].

Zero is treated as non-negative (standard convention).

Definition at line 301 of file minidsp_core.c.