stft_rs/
utils.rs

1/// Utility functions for signal processing and multi-channel audio
2use num_traits::Float;
3
4#[cfg(not(feature = "std"))]
5use alloc::{vec, vec::Vec};
6
7#[cfg(feature = "std")]
8use std::vec;
9
10use crate::PadMode;
11
12/// Apply padding to a signal.
13/// Streaming applications should pad manually to match batch processing quality.
14pub fn apply_padding<T: Float>(signal: &[T], pad_amount: usize, mode: PadMode) -> Vec<T> {
15    let total_len = signal.len() + 2 * pad_amount;
16    let mut padded = vec![T::zero(); total_len];
17
18    padded[pad_amount..pad_amount + signal.len()].copy_from_slice(signal);
19
20    match mode {
21        PadMode::Reflect => {
22            for i in 0..pad_amount {
23                if i + 1 < signal.len() {
24                    padded[pad_amount - 1 - i] = signal[i + 1];
25                }
26            }
27
28            let n = signal.len();
29            for i in 0..pad_amount {
30                if n >= 2 && n - 2 >= i {
31                    padded[pad_amount + n + i] = signal[n - 2 - i];
32                }
33            }
34        }
35        PadMode::Zero => {}
36        PadMode::Edge => {
37            if !signal.is_empty() {
38                for i in 0..pad_amount {
39                    padded[i] = signal[0];
40                }
41                for i in 0..pad_amount {
42                    padded[pad_amount + signal.len() + i] = signal[signal.len() - 1];
43                }
44            }
45        }
46    }
47
48    padded
49}
50
51// ============================================================================
52// Multi-Channel Utilities
53// ============================================================================
54
55/// Deinterleave multi-channel audio data.
56///
57/// Converts interleaved format (e.g., `[L,R,L,R,L,R,...]` for stereo)
58/// into separate channels (`vec![vec![L,L,L,...], vec![R,R,R,...]]`).
59///
60/// # Arguments
61///
62/// * `data` - Interleaved audio data
63/// * `num_channels` - Number of channels
64///
65/// # Panics
66///
67/// Panics if `num_channels` is 0 or if `data.len()` is not divisible by `num_channels`.
68///
69/// # Example
70///
71/// ```
72/// use stft_rs::deinterleave;
73///
74/// let interleaved = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]; // L,R,L,R,L,R
75/// let channels = deinterleave(&interleaved, 2);
76///
77/// assert_eq!(channels[0], vec![1.0, 3.0, 5.0]); // Left
78/// assert_eq!(channels[1], vec![2.0, 4.0, 6.0]); // Right
79/// ```
80pub fn deinterleave<T: Float>(data: &[T], num_channels: usize) -> Vec<Vec<T>> {
81    assert!(num_channels > 0, "num_channels must be greater than 0");
82    assert_eq!(
83        data.len() % num_channels,
84        0,
85        "data length ({}) must be divisible by num_channels ({})",
86        data.len(),
87        num_channels
88    );
89
90    if data.is_empty() {
91        return vec![Vec::new(); num_channels];
92    }
93
94    let samples_per_channel = data.len() / num_channels;
95    let mut channels = vec![Vec::with_capacity(samples_per_channel); num_channels];
96
97    for (i, &sample) in data.iter().enumerate() {
98        channels[i % num_channels].push(sample);
99    }
100
101    channels
102}
103
104/// Deinterleave multi-channel audio into a pre-allocated buffer (zero-allocation).
105///
106/// Converts interleaved format into separate channels without allocating new Vecs.
107/// The output buffer must contain exactly `num_channels` `Vec<T>` elements.
108/// Each Vec will be cleared and filled with samples.
109///
110/// # Arguments
111///
112/// * `data` - Interleaved audio data
113/// * `num_channels` - Number of channels
114/// * `output` - Pre-allocated output buffer with `num_channels` Vecs
115///
116/// # Panics
117///
118/// Panics if `num_channels` is 0, if `data.len()` is not divisible by `num_channels`,
119/// or if `output.len() != num_channels`.
120///
121/// # Example
122///
123/// ```
124/// use stft_rs::deinterleave_into;
125///
126/// let interleaved = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]; // L,R,L,R,L,R
127/// let mut output = vec![Vec::new(), Vec::new()];
128///
129/// deinterleave_into(&interleaved, 2, &mut output);
130///
131/// assert_eq!(output[0], vec![1.0, 3.0, 5.0]); // Left
132/// assert_eq!(output[1], vec![2.0, 4.0, 6.0]); // Right
133/// ```
134pub fn deinterleave_into<T: Float>(data: &[T], num_channels: usize, output: &mut [Vec<T>]) {
135    assert!(num_channels > 0, "num_channels must be greater than 0");
136    assert_eq!(
137        output.len(),
138        num_channels,
139        "output must have exactly {} channels, got {}",
140        num_channels,
141        output.len()
142    );
143    assert_eq!(
144        data.len() % num_channels,
145        0,
146        "data length ({}) must be divisible by num_channels ({})",
147        data.len(),
148        num_channels
149    );
150
151    if data.is_empty() {
152        for channel in output.iter_mut() {
153            channel.clear();
154        }
155        return;
156    }
157
158    let samples_per_channel = data.len() / num_channels;
159
160    // Clear and reserve capacity
161    for channel in output.iter_mut() {
162        channel.clear();
163        channel.reserve(samples_per_channel);
164    }
165
166    // Deinterleave
167    for (i, &sample) in data.iter().enumerate() {
168        output[i % num_channels].push(sample);
169    }
170}
171
172/// Interleave multiple channels into a single buffer.
173///
174/// Converts separate channels (`vec![vec![L,L,L,...], vec![R,R,R,...]]`)
175/// into interleaved format (e.g., `[L,R,L,R,L,R,...]` for stereo).
176///
177/// # Arguments
178///
179/// * `channels` - Vector of audio channels
180///
181/// # Panics
182///
183/// Panics if channels is empty or if channels have different lengths.
184///
185/// # Example
186///
187/// ```
188/// use stft_rs::interleave;
189///
190/// let left = vec![1.0, 3.0, 5.0];
191/// let right = vec![2.0, 4.0, 6.0];
192/// let interleaved = interleave(&[left, right]);
193///
194/// assert_eq!(interleaved, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
195/// ```
196pub fn interleave<T: Float>(channels: &[Vec<T>]) -> Vec<T> {
197    assert!(!channels.is_empty(), "channels must not be empty");
198
199    if channels[0].is_empty() {
200        return Vec::new();
201    }
202
203    let num_channels = channels.len();
204    let samples_per_channel = channels[0].len();
205
206    // Validate all channels have same length
207    for (i, channel) in channels.iter().enumerate() {
208        assert_eq!(
209            channel.len(),
210            samples_per_channel,
211            "Channel {} has length {}, expected {}",
212            i,
213            channel.len(),
214            samples_per_channel
215        );
216    }
217
218    let mut interleaved = Vec::with_capacity(samples_per_channel * num_channels);
219
220    for sample_idx in 0..samples_per_channel {
221        for channel in channels {
222            interleaved.push(channel[sample_idx]);
223        }
224    }
225
226    interleaved
227}
228
229/// Interleave multiple channels into a pre-allocated buffer (zero-allocation).
230///
231/// Converts separate channels into interleaved format without allocating.
232/// The output buffer must have capacity for `samples_per_channel × num_channels`.
233///
234/// # Arguments
235///
236/// * `channels` - Slice of audio channels
237/// * `output` - Pre-allocated output buffer (will be cleared and filled)
238///
239/// # Panics
240///
241/// Panics if channels is empty or if channels have different lengths.
242///
243/// # Example
244///
245/// ```
246/// use stft_rs::interleave_into;
247///
248/// let left = vec![1.0, 3.0, 5.0];
249/// let right = vec![2.0, 4.0, 6.0];
250///
251/// let mut output = Vec::with_capacity(6);
252/// interleave_into(&[left, right], &mut output);
253///
254/// assert_eq!(output, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
255/// ```
256pub fn interleave_into<T: Float>(channels: &[Vec<T>], output: &mut Vec<T>) {
257    assert!(!channels.is_empty(), "channels must not be empty");
258
259    if channels[0].is_empty() {
260        output.clear();
261        return;
262    }
263
264    let num_channels = channels.len();
265    let samples_per_channel = channels[0].len();
266
267    // Validate all channels have same length
268    for (i, channel) in channels.iter().enumerate() {
269        assert_eq!(
270            channel.len(),
271            samples_per_channel,
272            "Channel {} has length {}, expected {}",
273            i,
274            channel.len(),
275            samples_per_channel
276        );
277    }
278
279    output.clear();
280    output.reserve(samples_per_channel * num_channels);
281
282    for sample_idx in 0..samples_per_channel {
283        for channel in channels {
284            output.push(channel[sample_idx]);
285        }
286    }
287}