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
//! Low-level DSP kernels for onset detection.
//!
//! This module provides optimized, low-level building blocks for onset detection algorithms.
//! These functions operate directly on spectrograms and detection functions to compute onset
//! features and apply adaptive thresholding.
//!
//! The kernels include:
//! - Energy-based onset detection function computation
//! - Adaptive thresholding using median-based local thresholds
//!
//! These functions are typically used internally by higher-level onset detection implementations
//! and are optimized for performance.
use Array2;
use ;
/// Computes an energy-based onset detection function from a magnitude spectrogram.
///
/// For each frame, sums the positive differences in energy (squared magnitude) across all
/// frequency bins. This produces a time series where peaks correspond to sudden increases
/// in spectral energy, indicating potential onsets.
///
/// Formula: `odf[t] = Σ max(0, mag[b,t]² - mag[b,t-1]²)` for all bins b.
///
/// # Arguments
///
/// * `mag` — 2D magnitude spectrogram with shape `(frequency_bins, frames)`
///
/// # Returns
///
/// Onset detection function values for each frame. The first frame is always 0.0.
///
/// # Example
///
/// ```rust,ignore
/// use ndarray::Array2;
/// use audio_samples::operations::onset::kernels::energy_odf;
///
/// let mag = Array2::from_shape_vec((128, 100), vec![0.0; 12800]).unwrap();
/// let odf = energy_odf(&mag);
/// assert_eq!(odf.len().get(), 100);
/// assert_eq!(odf[0], 0.0);
/// ```
/// Applies adaptive thresholding to a signal in-place using a median-based local threshold.
///
/// For each sample, if its value is below `median[i] * multiplier`, it is set to zero.
/// Otherwise, it remains unchanged. This technique removes low-amplitude fluctuations while
/// preserving strong peaks, improving onset detection robustness against varying background
/// energy levels.
///
/// # Arguments
///
/// * `signal` — Signal to threshold (modified in-place)
/// * `median` — Median-filtered version of the signal (same length as `signal`)
/// * `multiplier` — Threshold multiplier (typically 1.0-2.0, higher = more aggressive)
///
/// # Panics
///
/// Panics in debug builds if `signal` and `median` have different lengths.
///
/// # Example
///
/// ```rust,ignore
/// use non_empty_slice::non_empty_slice;
/// use audio_samples::operations::onset::kernels::apply_adaptive_threshold;
///
/// let mut signal = non_empty_slice![1.0, 5.0, 2.0, 8.0, 1.5].to_non_empty_vec();
/// let median = non_empty_slice![1.5, 2.0, 2.5, 3.0, 1.8];
/// apply_adaptive_threshold(&mut signal, &median, 2.0);
/// // Values below median * 2.0 are set to zero
/// ```