25double MD_dot(
const double *a,
const double *b,
unsigned N)
28 for (
unsigned i = 0; i < N; i++) {
48 if (N == 1)
return a[0] * a[0];
80 double p = fmax(1.0e-10,
MD_power(a, N));
81 return 10.0 * log10(p);
97 double oldmin,
double oldmax,
98 double newmin,
double newmax)
100 return (in - oldmin) * (newmax - newmin) / (oldmax - oldmin) + newmin;
107 double oldmin,
double oldmax,
108 double newmin,
double newmax)
110 assert(in !=
nullptr);
111 assert(out !=
nullptr);
112 assert(oldmin < oldmax);
113 assert(newmin < newmax);
116 double scale = (newmax - newmin) / (oldmax - oldmin);
117 for (
unsigned i = 0; i < N; i++) {
118 out[i] = (in[i] - oldmin) * scale + newmin;
130 double newmin,
double newmax)
132 assert(in !=
nullptr);
133 assert(out !=
nullptr);
134 assert(newmin < newmax);
138 double in_min = in[0];
139 double in_max = in[0];
140 for (
unsigned i = 1; i < N; i++) {
141 if (in[i] < in_min) in_min = in[i];
142 if (in[i] > in_max) in_max = in[i];
145 if (in_min >= newmin && in_max <= newmax) {
147 for (
unsigned i = 0; i < N; i++) {
151 MD_scale_vec(in, out, N, in_min, in_max, newmin, newmax);
166 unsigned N,
double dblevel)
169 double desired_power = pow(10.0, dblevel / 10.0);
177 double gain = sqrt((desired_power * (
double)N) / input_energy);
180 bool out_of_range =
false;
181 for (
unsigned i = 0; i < N; i++) {
182 out[i] = in[i] * gain;
183 if (out[i] > 1.0 || out[i] < -1.0) {
212 assert(a !=
nullptr);
214 if (N <= 1)
return 0.0;
217 double max_entropy = log2((
double)N);
222 for (
unsigned i = 0; i < N; i++) {
223 total += (a[i] < 0.0) ? 0.0 : a[i];
226 for (
unsigned i = 0; i < N; i++) {
227 total += a[i] * a[i];
233 if (total == 0.0)
return 0.0;
236 double entropy = 0.0;
237 for (
unsigned i = 0; i < N; i++) {
238 if (a[i] == 0.0)
continue;
239 if (clip && a[i] < 0.0)
continue;
245 p = (a[i] * a[i]) / total;
248 entropy += p * log2(p);
252 return -entropy / max_entropy;
260#define MD_F0_ACF_PEAK_THRESHOLD 0.15
266 double denom = y_left - 2.0 * y_mid + y_right;
267 if (fabs(denom) < 1e-12)
return 0.0;
269 double delta = 0.5 * (y_left - y_right) / denom;
270 if (delta < -0.5) delta = -0.5;
271 if (delta > 0.5) delta = 0.5;
280double MD_rms(
const double *a,
unsigned N)
282 assert(a !=
nullptr);
295 assert(a !=
nullptr);
297 unsigned crossings = 0;
298 for (
unsigned i = 1; i < N; i++) {
299 if ((a[i] < 0.0) != (a[i - 1] < 0.0))
302 return (
double)crossings / (double)(N - 1);
314 double *out,
unsigned max_lag)
316 assert(a !=
nullptr);
317 assert(out !=
nullptr);
319 assert(max_lag > 0 && max_lag < N);
323 memset(out, 0, max_lag *
sizeof(
double));
326 for (
unsigned tau = 0; tau < max_lag; tau++) {
327 out[tau] =
MD_dot(a, a + tau, N - tau) / r0;
342 unsigned min_distance,
unsigned *peaks_out,
343 unsigned *num_peaks_out)
345 assert(a !=
nullptr);
346 assert(peaks_out !=
nullptr);
347 assert(num_peaks_out !=
nullptr);
348 assert(min_distance >= 1);
351 unsigned last_peak = 0;
353 for (
unsigned i = 1; i + 1 < N; i++) {
354 if (a[i] > a[i - 1] && a[i] > a[i + 1] && a[i] >= threshold) {
355 if (count == 0 || i - last_peak >= min_distance) {
356 peaks_out[count++] = i;
361 *num_peaks_out = count;
366 double min_freq_hz,
double max_freq_hz)
368 assert(signal !=
nullptr);
370 assert(sample_rate > 0.0);
371 assert(min_freq_hz > 0.0);
372 assert(max_freq_hz > min_freq_hz);
374 unsigned lag_min = (unsigned)floor(sample_rate / max_freq_hz);
375 unsigned lag_max = (unsigned)ceil(sample_rate / min_freq_hz);
377 if (lag_min < 1) lag_min = 1;
378 if (lag_max > N - 2) lag_max = N - 2;
379 if (lag_min > lag_max)
return 0.0;
380 if (lag_max < 2)
return 0.0;
382 double *acf = malloc((lag_max + 1) *
sizeof(
double));
383 if (!acf)
return 0.0;
387 unsigned start = (lag_min < 1) ? 1 : lag_min;
388 unsigned stop = (lag_max > N - 2) ? (N - 2) : lag_max;
390 double best_peak = -DBL_MAX;
391 unsigned best_lag = 0;
393 for (
unsigned lag = start; lag <= stop; lag++) {
396 if (y <= acf[lag - 1] || y <= acf[lag + 1])
continue;
409 double lag_est = (double)best_lag;
410 if (best_lag > 0 && best_lag + 1 <= lag_max) {
417 if (lag_est <= 0.0)
return 0.0;
418 return sample_rate / lag_est;
428void MD_mix(
const double *a,
const double *b,
double *out,
429 unsigned N,
double w_a,
double w_b)
431 assert(a !=
nullptr);
432 assert(b !=
nullptr);
433 assert(out !=
nullptr);
434 for (
unsigned i = 0; i < N; i++) {
435 out[i] = w_a * a[i] + w_b * b[i];
444 unsigned delay_samples,
double feedback,
445 double dry,
double wet)
447 assert(in !=
nullptr);
448 assert(out !=
nullptr);
450 assert(delay_samples > 0);
451 assert(fabs(feedback) < 1.0);
453 double *delay = calloc(delay_samples,
sizeof(
double));
454 assert(delay !=
nullptr);
457 for (
unsigned n = 0; n < N; n++) {
459 double d = delay[idx];
460 out[n] = dry * x + wet * d;
461 delay[idx] = x + feedback * d;
463 if (idx == delay_samples) idx = 0;
470 double rate_hz,
double depth,
double sample_rate)
472 assert(in !=
nullptr);
473 assert(out !=
nullptr);
475 assert(sample_rate > 0.0);
476 assert(rate_hz >= 0.0);
477 assert(depth >= 0.0 && depth <= 1.0);
479 double phase_step = 2.0 * M_PI * rate_hz / sample_rate;
480 for (
unsigned n = 0; n < N; n++) {
481 double lfo = 0.5 * (1.0 + sin(phase_step * (
double)n));
482 double gain = (1.0 - depth) + depth * lfo;
483 out[n] = in[n] * gain;
488 unsigned delay_samples,
double feedback,
489 double dry,
double wet)
491 assert(in !=
nullptr);
492 assert(out !=
nullptr);
494 assert(delay_samples > 0);
495 assert(fabs(feedback) < 1.0);
497 double *comb = calloc(delay_samples,
sizeof(
double));
498 assert(comb !=
nullptr);
501 for (
unsigned n = 0; n < N; n++) {
503 double delayed = comb[idx];
504 double y_comb = x + feedback * delayed;
506 out[n] = dry * x + wet * y_comb;
508 if (idx == delay_samples) idx = 0;
531 assert(out !=
nullptr);
539 double n_minus_1 = (double)(n - 1);
540 for (
unsigned i = 0; i < n; i++) {
541 out[i] = 0.5 * (1.0 - cos(2.0 * M_PI * (
double)i / n_minus_1));
552 assert(out !=
nullptr);
560 double n_minus_1 = (double)(n - 1);
561 for (
unsigned i = 0; i < n; i++) {
562 out[i] = 0.54 - 0.46 * cos(2.0 * M_PI * (
double)i / n_minus_1);
576 assert(out !=
nullptr);
584 double n_minus_1 = (double)(n - 1);
585 for (
unsigned i = 0; i < n; i++) {
586 double p = 2.0 * M_PI * (double)i / n_minus_1;
587 out[i] = 0.42 - 0.5 * cos(p) + 0.08 * cos(2.0 * p);
596 assert(out !=
nullptr);
598 for (
unsigned i = 0; i < n; i++) {
A mini library of DSP (Digital Signal Processing) routines.
double MD_power(const double *a, unsigned N)
Signal power: energy divided by the number of samples.
#define MD_F0_ACF_PEAK_THRESHOLD
Minimum normalised autocorrelation peak height accepted as voiced F0.
void MD_Gen_Blackman_Win(double *out, unsigned n)
Generate a Blackman window.
double MD_zero_crossing_rate(const double *a, unsigned N)
Zero-crossing rate: fraction of adjacent sample pairs that differ in sign.
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.
static double md_parabolic_offset(double y_left, double y_mid, double y_right)
Three-point parabolic refinement around a discrete peak index.
void MD_Gen_Hamming_Win(double *out, unsigned n)
Generate a Hamming window.
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).
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.
void MD_peak_detect(const double *a, unsigned N, double threshold, unsigned min_distance, unsigned *peaks_out, unsigned *num_peaks_out)
Peak detection: find local maxima above a threshold.
void MD_mix(const double *a, const double *b, double *out, unsigned N, double w_a, double w_b)
Signal mixing: weighted sum of two signals.
double MD_entropy(const double *a, unsigned N, bool clip)
Compute the normalised entropy of a distribution.
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_power_db(const double *a, unsigned N)
Signal power expressed in decibels (dB).
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.
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_Gen_Rect_Win(double *out, unsigned n)
Generate a rectangular window (all ones).
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).
void MD_autocorrelation(const double *a, unsigned N, double *out, unsigned max_lag)
Normalised autocorrelation for lags 0..max_lag-1.
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.
double MD_rms(const double *a, unsigned N)
Root mean square: the standard measure of signal "loudness".
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.