1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
//! DSP feature overlays for plots
//!
//! This module provides functions to compute DSP features over sliding windows
//! for visualization as plot overlays.
use NonZeroUsize;
use crate::;
/// Computes RMS (Root Mean Square) amplitude over sliding windows.
///
/// Divides the input signal into overlapping frames and computes the RMS value for each frame.
/// RMS is a measure of signal power and correlates with perceived loudness. Useful for
/// visualizing amplitude envelopes on waveform plots.
///
/// # Arguments
/// * `audio` — Input audio signal (mono or multi-channel)
/// * `window_size` — Window size in samples. Typical values: 2048-8192 for music, 512-2048
/// for speech.
/// * `hop_size` — Hop size (stride) in samples between successive windows. Smaller hop sizes
/// produce smoother curves at the cost of more computation.
///
/// # Returns
/// A tuple `(time_points, rms_values)` where:
/// - `time_points` are the center times of each window in seconds
/// - `rms_values` are the RMS amplitudes (same scale as input samples, typically 0.0-1.0 for
/// normalized audio)
///
/// # Example
/// ```rust,no_run
/// use audio_samples::{AudioSamples, sample_rate, nzu};
/// use audio_samples::operations::plotting::dsp_overlays;
///
/// let audio = AudioSamples::new_mono(ndarray::Array1::from_elem(44100, 0.0f32), sample_rate!(44100))?;
/// let (times, rms) = dsp_overlays::compute_windowed_rms(&audio, nzu!(2048), nzu!(512));
/// # Ok::<(), audio_samples::AudioSampleError>(())
/// ```
/// Computes peak (maximum absolute amplitude) over sliding windows.
///
/// Divides the input signal into overlapping frames and finds the maximum absolute sample
/// value in each frame. Peak values indicate the loudest instantaneous amplitude and are
/// useful for visualizing dynamic range and clipping risk.
///
/// # Arguments
/// * `audio` — Input audio signal (mono or multi-channel)
/// * `window_size` — Window size in samples. Typical values: 2048-8192 for music, 512-2048
/// for speech.
/// * `hop_size` — Hop size (stride) in samples between successive windows. Smaller hop sizes
/// produce smoother curves at the cost of more computation.
///
/// # Returns
/// A tuple `(time_points, peak_values)` where:
/// - `time_points` are the center times of each window in seconds
/// - `peak_values` are the maximum absolute amplitudes (same scale as input samples, typically
/// 0.0-1.0 for normalized audio)
///
/// # Example
/// ```rust,no_run
/// use audio_samples::{AudioSamples, sample_rate, nzu};
/// use audio_samples::operations::plotting::dsp_overlays;
///
/// let audio = AudioSamples::new_mono(ndarray::Array1::from_elem(44100, 0.0f32), sample_rate!(44100))?;
/// let (times, peaks) = dsp_overlays::compute_windowed_peak(&audio, nzu!(2048), nzu!(512));
/// # Ok::<(), audio_samples::AudioSampleError>(())
/// ```
/// Computes zero-crossing rate (ZCR) over sliding windows.
///
/// Divides the input signal into overlapping frames and counts how many times the signal
/// crosses the zero amplitude line in each frame. ZCR is a simple measure of signal noisiness
/// and spectral content: higher ZCR correlates with noisier, more broadband signals (e.g.,
/// fricatives in speech), while lower ZCR indicates tonal, pitched content.
///
/// # Arguments
/// * `audio` — Input audio signal (mono or multi-channel)
/// * `window_size` — Window size in samples. Typical values: 2048-8192 for music, 512-2048
/// for speech.
/// * `hop_size` — Hop size (stride) in samples between successive windows. Smaller hop sizes
/// produce smoother curves at the cost of more computation.
///
/// # Returns
/// A tuple `(time_points, zcr_values)` where:
/// - `time_points` are the center times of each window in seconds
/// - `zcr_values` are the zero-crossing rates (counts per sample, typically 0.0-0.5)
///
/// # Example
/// ```rust,no_run
/// use audio_samples::{AudioSamples, sample_rate, nzu};
/// use audio_samples::operations::plotting::dsp_overlays;
///
/// let audio = AudioSamples::new_mono(ndarray::Array1::from_elem(44100, 0.0f32), sample_rate!(44100))?;
/// let (times, zcr) = dsp_overlays::compute_windowed_zcr(&audio, nzu!(2048), nzu!(512));
/// # Ok::<(), audio_samples::AudioSampleError>(())
/// ```
/// Computes signal energy over sliding windows.
///
/// Divides the input signal into overlapping frames and computes the energy (RMS squared,
/// proportional to power) for each frame. Energy is a measure of signal intensity and is
/// useful for detecting voiced vs. unvoiced segments, onset detection, and dynamic analysis.
///
/// # Arguments
/// * `audio` — Input audio signal (mono or multi-channel)
/// * `window_size` — Window size in samples. Typical values: 2048-8192 for music, 512-2048
/// for speech.
/// * `hop_size` — Hop size (stride) in samples between successive windows. Smaller hop sizes
/// produce smoother curves at the cost of more computation.
///
/// # Returns
/// A tuple `(time_points, energy_values)` where:
/// - `time_points` are the center times of each window in seconds
/// - `energy_values` are the squared RMS values (power, typically 0.0-1.0 for normalized audio)
///
/// # Example
/// ```rust,no_run
/// use audio_samples::{AudioSamples, sample_rate, nzu};
/// use audio_samples::operations::plotting::dsp_overlays;
///
/// let audio = AudioSamples::new_mono(ndarray::Array1::from_elem(44100, 0.0f32), sample_rate!(44100))?;
/// let (times, energy) = dsp_overlays::compute_windowed_energy(&audio, nzu!(2048), nzu!(512));
/// # Ok::<(), audio_samples::AudioSampleError>(())
/// ```
/// Computes spectral centroid over sliding windows.
///
/// Divides the input signal into overlapping frames, computes the FFT for each frame, and
/// calculates the spectral centroid (the "center of mass" of the spectrum). The centroid
/// correlates with perceived brightness: higher centroid values indicate more high-frequency
/// content, while lower values indicate more bass-heavy signals.
///
/// # Arguments
/// * `audio` — Input audio signal (mono or multi-channel)
/// * `window_size` — Window size in samples. Must be a power of 2 for FFT efficiency.
/// Typical values: 2048-8192.
/// * `hop_size` — Hop size (stride) in samples between successive windows. Smaller hop sizes
/// produce smoother curves at the cost of more computation.
///
/// # Returns
/// A tuple `(time_points, centroid_values)` where:
/// - `time_points` are the center times of each window in seconds
/// - `centroid_values` are the spectral centroid frequencies in Hz
///
/// Windows where the spectral centroid cannot be computed (e.g., silent frames) are skipped.
///
/// # Example
/// ```rust,no_run
/// use audio_samples::{AudioSamples, sample_rate, nzu};
/// use audio_samples::operations::plotting::dsp_overlays;
///
/// let audio = AudioSamples::new_mono(ndarray::Array1::from_elem(44100, 0.0f32), sample_rate!(44100))?;
/// let (times, centroids) = dsp_overlays::compute_windowed_spectral_centroid(
/// &audio, nzu!(2048), nzu!(512)
/// );
/// # Ok::<(), audio_samples::AudioSampleError>(())
/// ```
/// Computes spectral rolloff frequency over sliding windows.
///
/// Divides the input signal into overlapping frames, computes the FFT for each frame, and
/// calculates the rolloff frequency: the frequency below which a specified percentage (e.g., 85%)
/// of the spectral energy is contained. Rolloff is useful for distinguishing tonal vs. noisy
/// content and for detecting the high-frequency "cutoff" of the signal.
///
/// # Arguments
/// * `audio` — Input audio signal (mono or multi-channel)
/// * `window_size` — Window size in samples. Must be a power of 2 for FFT efficiency.
/// Typical values: 2048-8192.
/// * `hop_size` — Hop size (stride) in samples between successive windows. Smaller hop sizes
/// produce smoother curves at the cost of more computation.
/// * `rolloff_percent` — Rolloff threshold as a fraction (e.g., 0.85 for 85%). Typical values:
/// 0.85-0.95.
///
/// # Returns
/// A tuple `(time_points, rolloff_values)` where:
/// - `time_points` are the center times of each window in seconds
/// - `rolloff_values` are the rolloff frequencies in Hz
///
/// Windows where the spectral rolloff cannot be computed (e.g., silent frames) are skipped.
///
/// # Example
/// ```rust,no_run
/// use audio_samples::{AudioSamples, sample_rate, nzu};
/// use audio_samples::operations::plotting::dsp_overlays;
///
/// let audio = AudioSamples::new_mono(ndarray::Array1::from_elem(44100, 0.0f32), sample_rate!(44100))?;
/// let (times, rolloff) = dsp_overlays::compute_windowed_spectral_rolloff(
/// &audio, nzu!(2048), nzu!(512), 0.85
/// );
/// # Ok::<(), audio_samples::AudioSampleError>(())
/// ```