38static unsigned _N = 0;
39static double *siga_loc =
nullptr;
40static double *sigb_loc =
nullptr;
41static double *lags_loc =
nullptr;
42static fftw_complex *ffta =
nullptr;
43static fftw_complex *fftb =
nullptr;
44static fftw_complex *xspec =
nullptr;
45static double *xcorr =
nullptr;
47static fftw_plan pa =
nullptr;
48static fftw_plan pb =
nullptr;
49static fftw_plan px =
nullptr;
58 if (xspec) fftw_free(xspec);
59 if (fftb) fftw_free(fftb);
60 if (ffta) fftw_free(ffta);
62 if (lags_loc) free(lags_loc);
63 if (xcorr) free(xcorr);
64 if (sigb_loc) free(sigb_loc);
65 if (siga_loc) free(siga_loc);
67 xspec =
nullptr; fftb =
nullptr; ffta =
nullptr;
68 lags_loc =
nullptr; xcorr =
nullptr; sigb_loc =
nullptr; siga_loc =
nullptr;
74 siga_loc = calloc(_N,
sizeof(
double));
75 sigb_loc = calloc(_N,
sizeof(
double));
76 xcorr = calloc(_N + 1,
sizeof(
double));
77 lags_loc = calloc(_N,
sizeof(
double));
82 ffta = fftw_alloc_complex(_N);
83 fftb = fftw_alloc_complex(_N);
84 xspec = fftw_alloc_complex(_N);
90 if (pa) fftw_destroy_plan(pa);
91 if (pb) fftw_destroy_plan(pb);
92 if (px) fftw_destroy_plan(px);
93 pa =
nullptr; pb =
nullptr; px =
nullptr;
117 pa = fftw_plan_dft_r2c_1d(_N, siga_loc, ffta, FFTW_ESTIMATE | FFTW_DESTROY_INPUT);
118 pb = fftw_plan_dft_r2c_1d(_N, sigb_loc, fftb, FFTW_ESTIMATE | FFTW_DESTROY_INPUT);
119 px = fftw_plan_dft_c2r_1d(_N, xspec, xcorr, FFTW_ESTIMATE | FFTW_DESTROY_INPUT);
142static unsigned _spec_N = 0;
143static double *_spec_in =
nullptr;
144static fftw_complex *_spec_out =
nullptr;
145static fftw_plan _spec_plan =
nullptr;
154static double *_stft_win =
nullptr;
155static unsigned _stft_win_N = 0;
160 if (_spec_out) fftw_free(_spec_out);
161 if (_spec_in) free(_spec_in);
169 if (_spec_plan) fftw_destroy_plan(_spec_plan);
170 _spec_plan =
nullptr;
180 if (_spec_N == N)
return;
185 _spec_in = calloc(N,
sizeof(
double));
186 _spec_out = fftw_alloc_complex(N / 2 + 1);
188 _spec_plan = fftw_plan_dft_r2c_1d(
189 (
int)N, _spec_in, _spec_out,
190 FFTW_ESTIMATE | FFTW_DESTROY_INPUT);
208 if (_stft_win_N == N)
return;
211 _stft_win = malloc(N *
sizeof(
double));
212 assert(_stft_win !=
nullptr);
232static void _fftshift(
const double *in,
double *out,
unsigned N)
235 unsigned half = (unsigned)floor((
double)N / 2.0);
238 memcpy(out, &in[half],
sizeof(
double) * (N - half));
241 memcpy(&out[N - half], in,
sizeof(
double) * half);
253 double *max,
unsigned *maxi)
255 assert(a !=
nullptr);
259 double best_v = a[0];
261 for (
unsigned i = 1; i < N; i++) {
298double MD_dot(
const double *a,
const double *b,
unsigned N)
301 for (
unsigned i = 0; i < N; i++) {
320 assert(a !=
nullptr);
321 if (N == 1)
return a[0] * a[0];
335 assert(a !=
nullptr);
351 assert(a !=
nullptr);
353 double p = fmax(1.0e-10,
MD_power(a, N));
354 return 10.0 * log10(p);
370 double oldmin,
double oldmax,
371 double newmin,
double newmax)
373 return (in - oldmin) * (newmax - newmin) / (oldmax - oldmin) + newmin;
380 double oldmin,
double oldmax,
381 double newmin,
double newmax)
383 assert(in !=
nullptr);
384 assert(out !=
nullptr);
385 assert(oldmin < oldmax);
386 assert(newmin < newmax);
389 double scale = (newmax - newmin) / (oldmax - oldmin);
390 for (
unsigned i = 0; i < N; i++) {
391 out[i] = (in[i] - oldmin) * scale + newmin;
403 double newmin,
double newmax)
405 assert(in !=
nullptr);
406 assert(out !=
nullptr);
407 assert(newmin < newmax);
411 double in_min = in[0];
412 double in_max = in[0];
413 for (
unsigned i = 1; i < N; i++) {
414 if (in[i] < in_min) in_min = in[i];
415 if (in[i] > in_max) in_max = in[i];
418 if (in_min >= newmin && in_max <= newmax) {
420 for (
unsigned i = 0; i < N; i++) {
424 MD_scale_vec(in, out, N, in_min, in_max, newmin, newmax);
439 unsigned N,
double dblevel)
442 double desired_power = pow(10.0, dblevel / 10.0);
450 double gain = sqrt((desired_power * (
double)N) / input_energy);
453 bool out_of_range =
false;
454 for (
unsigned i = 0; i < N; i++) {
455 out[i] = in[i] * gain;
456 if (out[i] > 1.0 || out[i] < -1.0) {
485 assert(a !=
nullptr);
487 if (N <= 1)
return 0.0;
490 double max_entropy = log2((
double)N);
495 for (
unsigned i = 0; i < N; i++) {
496 total += (a[i] < 0.0) ? 0.0 : a[i];
499 for (
unsigned i = 0; i < N; i++) {
500 total += a[i] * a[i];
506 if (total == 0.0)
return 0.0;
509 double entropy = 0.0;
510 for (
unsigned i = 0; i < N; i++) {
511 if (a[i] == 0.0)
continue;
512 if (clip && a[i] < 0.0)
continue;
518 p = (a[i] * a[i]) / total;
521 entropy += p * log2(p);
525 return -entropy / max_entropy;
545 double n_minus_1 = (double)(n - 1);
546 for (
unsigned i = 0; i < n; i++) {
547 out[i] = 0.5 * (1.0 - cos(2.0 * M_PI * (
double)i / n_minus_1));
556 double freq,
double sample_rate)
558 assert(output !=
nullptr);
560 assert(sample_rate > 0.0);
561 double phase_step = 2.0 * M_PI * freq / sample_rate;
562 for (
unsigned i = 0; i < N; i++)
563 output[i] = amplitude * sin(phase_step * (
double)i);
569 assert(output !=
nullptr);
574 unsigned long long state = (
unsigned long long)seed;
585 state = state * 6364136223846793005ULL + 1442695040888963407ULL;
586 double u1 = (double)(state >> 11) * 0x1.0p-53;
587 if (u1 < DBL_MIN) u1 = DBL_MIN;
588 state = state * 6364136223846793005ULL + 1442695040888963407ULL;
589 double u2 = (double)(state >> 11) * 0x1.0p-53;
591 double r = sqrt(-2.0 * log(u1));
592 double theta = 2.0 * M_PI * u2;
593 output[i] = amplitude * r * cos(theta);
594 output[i + 1] = amplitude * r * sin(theta);
599 state = state * 6364136223846793005ULL + 1442695040888963407ULL;
600 double u1 = (double)(state >> 11) * 0x1.0p-53;
601 if (u1 < DBL_MIN) u1 = DBL_MIN;
602 state = state * 6364136223846793005ULL + 1442695040888963407ULL;
603 double u2 = (double)(state >> 11) * 0x1.0p-53;
604 output[i] = amplitude * sqrt(-2.0 * log(u1)) * cos(2.0 * M_PI * u2);
608void MD_impulse(
double *output,
unsigned N,
double amplitude,
unsigned position)
610 assert(output !=
nullptr);
612 assert(position < N);
613 memset(output, 0, N *
sizeof(
double));
614 output[position] = amplitude;
618 double f_start,
double f_end,
double sample_rate)
620 assert(output !=
nullptr);
622 assert(sample_rate > 0.0);
629 double T = (double)(N - 1) / sample_rate;
630 double chirp_rate = (f_end - f_start) / T;
632 for (
unsigned i = 0; i < N; i++) {
633 double t = (double)i / sample_rate;
634 double phase = 2.0 * M_PI * (f_start * t + 0.5 * chirp_rate * t * t);
635 output[i] = amplitude * sin(phase);
640 double f_start,
double f_end,
double sample_rate)
642 assert(output !=
nullptr);
644 assert(sample_rate > 0.0);
645 assert(f_start > 0.0);
647 assert(f_start != f_end);
654 double T = (double)(N - 1) / sample_rate;
655 double ratio = f_end / f_start;
656 double log_ratio = log(ratio);
658 for (
unsigned i = 0; i < N; i++) {
659 double t = (double)i / sample_rate;
660 double phase = 2.0 * M_PI * f_start * T
661 * (pow(ratio, t / T) - 1.0) / log_ratio;
662 output[i] = amplitude * sin(phase);
667 double freq,
double sample_rate)
669 assert(output !=
nullptr);
671 assert(sample_rate > 0.0);
672 double phase_step = 2.0 * M_PI * freq / sample_rate;
673 for (
unsigned i = 0; i < N; i++) {
674 double phase = fmod(phase_step * (
double)i, 2.0 * M_PI);
675 if (phase < 0.0) phase += 2.0 * M_PI;
676 if (phase == 0.0 || phase == M_PI)
678 else if (phase < M_PI)
679 output[i] = amplitude;
681 output[i] = -amplitude;
686 double freq,
double sample_rate)
688 assert(output !=
nullptr);
690 assert(sample_rate > 0.0);
691 double phase_step = 2.0 * M_PI * freq / sample_rate;
692 for (
unsigned i = 0; i < N; i++) {
693 double phase = fmod(phase_step * (
double)i, 2.0 * M_PI);
694 if (phase < 0.0) phase += 2.0 * M_PI;
695 output[i] = amplitude * (phase / M_PI - 1.0);
729 assert(signal !=
nullptr);
730 assert(mag_out !=
nullptr);
736 memcpy(_spec_in, signal, N *
sizeof(
double));
739 fftw_execute(_spec_plan);
742 unsigned num_bins = N / 2 + 1;
743 for (
unsigned k = 0; k < num_bins; k++) {
744 mag_out[k] = cabs(_spec_out[k]);
767 assert(signal !=
nullptr);
768 assert(psd_out !=
nullptr);
774 memcpy(_spec_in, signal, N *
sizeof(
double));
777 fftw_execute(_spec_plan);
782 unsigned num_bins = N / 2 + 1;
783 for (
unsigned k = 0; k < num_bins; k++) {
784 double re = creal(_spec_out[k]);
785 double im = cimag(_spec_out[k]);
786 psd_out[k] = (re * re + im * im) / (
double)N;
809 assert(signal !=
nullptr);
810 assert(phase_out !=
nullptr);
816 memcpy(_spec_in, signal, N *
sizeof(
double));
819 fftw_execute(_spec_plan);
823 unsigned num_bins = N / 2 + 1;
824 for (
unsigned k = 0; k < num_bins; k++) {
825 phase_out[k] = carg(_spec_out[k]);
837 if (signal_len < N)
return 0;
838 return (signal_len - N) / hop + 1;
860void MD_stft(
const double *signal,
unsigned signal_len,
861 unsigned N,
unsigned hop,
double *mag_out)
863 assert(signal !=
nullptr);
864 assert(mag_out !=
nullptr);
869 if (num_frames == 0)
return;
872 unsigned num_bins = N / 2 + 1;
874 for (
unsigned f = 0; f < num_frames; f++) {
875 const double *src = signal + (size_t)f * hop;
879 for (
unsigned n = 0; n < N; n++) {
880 _spec_in[n] = src[n] * _stft_win[n];
883 fftw_execute(_spec_plan);
888 double *row = mag_out + (size_t)f * num_bins;
889 for (
unsigned k = 0; k < num_bins; k++) {
890 row[k] = cabs(_spec_out[k]);
914 unsigned margin,
int weightfunc,
919 static unsigned last_N = 0;
920 static double *hann_win =
nullptr;
921 static double *t_ref =
nullptr;
922 static double *t_sig =
nullptr;
932 hann_win = malloc(N *
sizeof(
double));
933 assert(hann_win !=
nullptr);
936 t_ref = malloc(N *
sizeof(
double));
937 assert(t_ref !=
nullptr);
939 t_sig = malloc(N *
sizeof(
double));
940 assert(t_sig !=
nullptr);
946 for (
unsigned i = 0; i < N; i++) {
947 t_ref[i] = sigs[0][i] * hann_win[i];
951 for (
unsigned i = 0; i < M - 1; i++) {
953 for (
unsigned j = 0; j < N; j++) {
954 t_sig[j] = sigs[i + 1][j] * hann_win[j];
956 outdelays[i] =
MD_get_delay(t_ref, t_sig, N,
nullptr, margin, weightfunc);
979 double *ent,
unsigned margin,
int weightfunc)
984 MD_gcc(siga, sigb, N, lags_loc, weightfunc);
987 unsigned center = (unsigned)ceil((
double)N / 2.0);
994 if (center + m >= N) {
995 m = (N - 1) - center;
999 unsigned start = center - m;
1000 unsigned len = 2 * m + 1;
1004 _max_index(lags_loc + start, len, &peak_val, &peak_i);
1007 if (ent !=
nullptr) {
1008 *ent =
MD_entropy(lags_loc + start, len,
true);
1012 return (
int)(peak_i) - (
int)(m);
1028void MD_gcc(
const double *siga,
const double *sigb,
unsigned N,
1029 double *lagvals,
int weightfunc)
1034 memcpy(siga_loc, siga, _N *
sizeof(
double));
1035 memcpy(sigb_loc, sigb, _N *
sizeof(
double));
1054 unsigned num_bins = _N / 2 + 1;
1056 switch (weightfunc) {
1058 for (
unsigned i = 0; i < num_bins; i++) {
1059 double complex cs = fftb[i] * conj(ffta[i]);
1061 xspec[i] = cs / (cabs(cs) + DBL_MIN);
1066 for (
unsigned i = 0; i < num_bins; i++) {
1067 double complex cs = fftb[i] * conj(ffta[i]);
1068 xspec[i] = cs / (double)_N;
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).
static void _xcorr_malloc(void)
Allocate all buffers needed for cross-correlation of length _N.
double MD_power(const double *a, unsigned N)
Signal power: energy divided by the number of samples.
static void _stft_setup(unsigned N)
Ensure the shared r2c plan is ready for length N, and that the STFT Hanning window buffer matches N.
static void _xcorr_free(void)
Free all dynamically allocated FFT buffers.
void MD_power_spectral_density(const double *signal, unsigned N, double *psd_out)
Compute the power spectral density (PSD) of a real-valued signal.
static void _fftshift(const double *in, double *out, unsigned N)
Shift an FFT output so that the zero-lag is in the middle.
void MD_white_noise(double *output, unsigned N, double amplitude, unsigned seed)
Generate Gaussian white noise.
void MD_sine_wave(double *output, unsigned N, double amplitude, double freq, double sample_rate)
Generate a sine wave.
void MD_impulse(double *output, unsigned N, double amplitude, unsigned position)
Generate a discrete impulse (Kronecker delta).
void MD_scale_vec(double *in, double *out, unsigned N, double oldmin, double oldmax, double newmin, double newmax)
Apply MD_scale() to every element of a vector.
void MD_phase_spectrum(const double *signal, unsigned N, double *phase_out)
Compute the one-sided phase spectrum of a real-valued signal.
static void _xcorr_setup(void)
Allocate buffers and create FFTW plans for signals of length _N.
double MD_scale(double in, double oldmin, double oldmax, double newmin, double newmax)
Linearly map a value from one range to another.
void MD_Gen_Hann_Win(double *out, unsigned n)
Generate a Hanning (raised cosine) window.
double MD_energy(const double *a, unsigned N)
Signal energy: the sum of squared samples.
static void _spec_free(void)
Free spectrum analysis buffers.
void MD_stft(const double *signal, unsigned signal_len, unsigned N, unsigned hop, double *mag_out)
Compute the Short-Time Fourier Transform (STFT) magnitude matrix.
static void _xcorr_teardown(void)
Destroy existing FFTW plans and free all buffers.
static void _stft_teardown(void)
Free the cached STFT Hanning window.
static void _gcc_setup(unsigned N)
Ensure the cached FFT setup matches the requested signal length.
static void _spec_teardown(void)
Tear down spectrum analysis plan and buffers.
double MD_entropy(const double *a, unsigned N, bool clip)
Compute the normalised entropy of a distribution.
static void _spec_setup(unsigned N)
Ensure the spectrum FFT cache matches the requested length.
void MD_shutdown(void)
Free all internally cached FFT plans and buffers.
double MD_power_db(const double *a, unsigned N)
Signal power expressed in decibels (dB).
void MD_gcc(const double *siga, const double *sigb, unsigned N, double *lagvals, int weightfunc)
Compute the Generalized Cross-Correlation between two signals.
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 several other signals.
double MD_dot(const double *a, const double *b, unsigned N)
Dot product of two vectors a and b, each of length N.
void MD_sawtooth_wave(double *output, unsigned N, double amplitude, double freq, double sample_rate)
Generate a sawtooth wave.
void MD_magnitude_spectrum(const double *signal, unsigned N, double *mag_out)
Compute the magnitude spectrum of a real-valued signal.
static void _max_index(const double *a, unsigned N, double *max, unsigned *maxi)
Find the index and value of the maximum element in an array.
unsigned MD_stft_num_frames(unsigned signal_len, unsigned N, unsigned hop)
Compute the number of complete STFT frames for the given parameters.
void MD_fit_within_range(double *in, double *out, unsigned N, double newmin, double newmax)
Squeeze values into [newmin, newmax] only if they don't already fit.
void MD_square_wave(double *output, unsigned N, double amplitude, double freq, double sample_rate)
Generate a square wave.
int MD_get_delay(const double *siga, const double *sigb, unsigned N, double *ent, unsigned margin, int weightfunc)
Estimate the delay (in samples) between two signals.
void MD_adjust_dblevel(const double *in, double *out, unsigned N, double dblevel)
Automatic Gain Control (AGC): adjust a signal to a target dB level.
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).
A mini library of DSP (Digital Signal Processing) routines.
@ PHAT
Phase Transform weighting (sharper peaks, more robust to noise)