miniDSP
A small C library for audio DSP
Loading...
Searching...
No Matches
minidsp_generators.c
Go to the documentation of this file.
1
9#include "minidsp.h"
10
11/* -----------------------------------------------------------------------
12 * Public API: Signal generators
13 * -----------------------------------------------------------------------*/
14
15void MD_sine_wave(double *output, unsigned N, double amplitude,
16 double freq, double sample_rate)
17{
18 assert(output != nullptr);
19 assert(N > 0);
20 assert(sample_rate > 0.0);
21 double phase_step = 2.0 * M_PI * freq / sample_rate;
22 for (unsigned i = 0; i < N; i++)
23 output[i] = amplitude * sin(phase_step * (double)i);
24}
25
26void MD_white_noise(double *output, unsigned N, double amplitude,
27 unsigned seed)
28{
29 assert(output != nullptr);
30 assert(N > 0);
31
32 /* 64-bit LCG (Knuth MMIX constants) for uniform doubles in (0, 1).
33 * Self-contained so we don't need POSIX drand48. */
34 unsigned long long state = (unsigned long long)seed;
35
36 /* Box-Muller transform: convert pairs of uniform random numbers
37 * into pairs of Gaussian random numbers (mean 0, std dev 1),
38 * then scale by the requested amplitude.
39 *
40 * For each pair (u1, u2) drawn from (0, 1]:
41 * z0 = sqrt(-2 ln u1) * cos(2 pi u2)
42 * z1 = sqrt(-2 ln u1) * sin(2 pi u2) */
43 unsigned i = 0;
44 while (i + 1 < N) {
45 state = state * 6364136223846793005ULL + 1442695040888963407ULL;
46 double u1 = (double)(state >> 11) * 0x1.0p-53;
47 if (u1 < DBL_MIN) u1 = DBL_MIN;
48 state = state * 6364136223846793005ULL + 1442695040888963407ULL;
49 double u2 = (double)(state >> 11) * 0x1.0p-53;
50
51 double r = sqrt(-2.0 * log(u1));
52 double theta = 2.0 * M_PI * u2;
53 output[i] = amplitude * r * cos(theta);
54 output[i + 1] = amplitude * r * sin(theta);
55 i += 2;
56 }
57 /* If N is odd, generate one extra pair and use only the first value */
58 if (i < N) {
59 state = state * 6364136223846793005ULL + 1442695040888963407ULL;
60 double u1 = (double)(state >> 11) * 0x1.0p-53;
61 if (u1 < DBL_MIN) u1 = DBL_MIN;
62 state = state * 6364136223846793005ULL + 1442695040888963407ULL;
63 double u2 = (double)(state >> 11) * 0x1.0p-53;
64 output[i] = amplitude * sqrt(-2.0 * log(u1)) * cos(2.0 * M_PI * u2);
65 }
66}
67
68void MD_impulse(double *output, unsigned N, double amplitude, unsigned position)
69{
70 assert(output != nullptr);
71 assert(N > 0);
72 assert(position < N);
73 memset(output, 0, N * sizeof(double));
74 output[position] = amplitude;
75}
76
77void MD_chirp_linear(double *output, unsigned N, double amplitude,
78 double f_start, double f_end, double sample_rate)
79{
80 assert(output != nullptr);
81 assert(N > 0);
82 assert(sample_rate > 0.0);
83
84 if (N == 1) {
85 output[0] = 0.0;
86 return;
87 }
88
89 double T = (double)(N - 1) / sample_rate;
90 double chirp_rate = (f_end - f_start) / T;
91
92 for (unsigned i = 0; i < N; i++) {
93 double t = (double)i / sample_rate;
94 double phase = 2.0 * M_PI * (f_start * t + 0.5 * chirp_rate * t * t);
95 output[i] = amplitude * sin(phase);
96 }
97}
98
99void MD_chirp_log(double *output, unsigned N, double amplitude,
100 double f_start, double f_end, double sample_rate)
101{
102 assert(output != nullptr);
103 assert(N > 0);
104 assert(sample_rate > 0.0);
105 assert(f_start > 0.0);
106 assert(f_end > 0.0);
107 assert(f_start != f_end);
108
109 if (N == 1) {
110 output[0] = 0.0;
111 return;
112 }
113
114 double T = (double)(N - 1) / sample_rate;
115 double ratio = f_end / f_start;
116 double log_ratio = log(ratio);
117
118 for (unsigned i = 0; i < N; i++) {
119 double t = (double)i / sample_rate;
120 double phase = 2.0 * M_PI * f_start * T
121 * (pow(ratio, t / T) - 1.0) / log_ratio;
122 output[i] = amplitude * sin(phase);
123 }
124}
125
126void MD_square_wave(double *output, unsigned N, double amplitude,
127 double freq, double sample_rate)
128{
129 assert(output != nullptr);
130 assert(N > 0);
131 assert(sample_rate > 0.0);
132 double phase_step = 2.0 * M_PI * freq / sample_rate;
133 for (unsigned i = 0; i < N; i++) {
134 double phase = fmod(phase_step * (double)i, 2.0 * M_PI);
135 if (phase < 0.0) phase += 2.0 * M_PI;
136 if (phase == 0.0 || phase == M_PI)
137 output[i] = 0.0;
138 else if (phase < M_PI)
139 output[i] = amplitude;
140 else
141 output[i] = -amplitude;
142 }
143}
144
145void MD_sawtooth_wave(double *output, unsigned N, double amplitude,
146 double freq, double sample_rate)
147{
148 assert(output != nullptr);
149 assert(N > 0);
150 assert(sample_rate > 0.0);
151 double phase_step = 2.0 * M_PI * freq / sample_rate;
152 for (unsigned i = 0; i < N; i++) {
153 double phase = fmod(phase_step * (double)i, 2.0 * M_PI);
154 if (phase < 0.0) phase += 2.0 * M_PI;
155 output[i] = amplitude * (phase / M_PI - 1.0);
156 }
157}
158
159void MD_shepard_tone(double *output, unsigned N, double amplitude,
160 double base_freq, double sample_rate,
161 double rate_octaves_per_sec, unsigned num_octaves)
162{
163 assert(output != nullptr);
164 assert(N > 0);
165 assert(sample_rate > 0.0);
166 assert(base_freq > 0.0);
167 assert(num_octaves > 0);
168
169 double rate = rate_octaves_per_sec;
170 double center = (double)(num_octaves - 1) / 2.0;
171 double sigma = (double)num_octaves / 4.0;
172 double nyquist = sample_rate / 2.0;
173 double margin = 5.0 * sigma;
174
175 /* Determine the range of layer indices needed.
176 *
177 * Layer k has octave offset from the Gaussian centre at time t:
178 * d_k(t) = k − center + rate · t
179 *
180 * A layer is relevant if |d_k(t)| ≤ 5σ for at least one t in
181 * [0, duration]. For rate > 0 (rising), d_k increases with time,
182 * so early layers start below centre and later ones rise above it.
183 * Extra layers below the initial configuration are needed to replace
184 * those that drift above the Gaussian on the high side. For rate < 0
185 * (falling), the mirror logic applies. */
186 double duration = (N > 1) ? (double)(N - 1) / sample_rate : 0.0;
187 double drift = rate * duration;
188
189 int k_min = (int)floor(center - margin - fmax(0.0, drift));
190 int k_max = (int)ceil(center + margin - fmin(0.0, drift));
191 unsigned total_layers = (unsigned)(k_max - k_min + 1);
192
193 /* Per-layer phase accumulators (zero-initialised). */
194 double *phases = calloc(total_layers, sizeof(double));
195 assert(phases != nullptr);
196 memset(output, 0, N * sizeof(double));
197
198 for (unsigned i = 0; i < N; i++) {
199 double t = (double)i / sample_rate;
200 for (int k = k_min; k <= k_max; k++) {
201 /* d = octave distance from Gaussian centre (continuous) */
202 double d = (double)k - center + rate * t;
203
204 /* Skip layers outside the significant Gaussian tail */
205 if (fabs(d) > margin) continue;
206
207 double freq = base_freq * pow(2.0, d);
208 unsigned idx = (unsigned)(k - k_min);
209 phases[idx] += 2.0 * M_PI * freq / sample_rate;
210
211 /* Skip frequencies outside the audible / Nyquist range */
212 if (freq >= nyquist || freq < 20.0) continue;
213
214 double gauss = exp(-0.5 * d * d / (sigma * sigma));
215 /* Keep phase bounded to preserve floating-point precision */
216 if (phases[idx] > 4.0 * M_PI)
217 phases[idx] = fmod(phases[idx], 2.0 * M_PI);
218 output[i] += gauss * sin(phases[idx]);
219 }
220 }
221
222 free(phases);
223
224 /* Normalise so the peak absolute value equals the requested amplitude. */
225 double peak = 0.0;
226 for (unsigned i = 0; i < N; i++) {
227 double a = fabs(output[i]);
228 if (a > peak) peak = a;
229 }
230 if (peak > 0.0) {
231 double scale = amplitude / peak;
232 for (unsigned i = 0; i < N; i++)
233 output[i] *= scale;
234 }
235}
A mini library of DSP (Digital Signal Processing) routines.
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_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_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.
void MD_sawtooth_wave(double *output, unsigned N, double amplitude, double freq, double sample_rate)
Generate a sawtooth wave.
void MD_square_wave(double *output, unsigned N, double amplitude, double freq, double sample_rate)
Generate a square wave.
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).