firewheel_core/dsp/
interleave.rs1use crate::mask::SilenceMask;
2
3pub fn deinterleave<V: AsMut<[f32]>>(
5 channels: &mut [V],
6 start_frame_in_channels: usize,
7 interleaved: &[f32],
8 num_interleaved_channels: usize,
9 calculate_silence_mask: bool,
10) -> SilenceMask {
11 if channels.is_empty() {
12 return SilenceMask::NONE_SILENT;
13 }
14
15 if num_interleaved_channels == 0 {
16 for ch in channels.iter_mut() {
17 ch.as_mut()[start_frame_in_channels..].fill(0.0);
18 }
19
20 return SilenceMask::new_all_silent(channels.len());
21 }
22
23 let mut silence_mask = SilenceMask::NONE_SILENT;
24
25 let (num_filled_channels, samples) = if num_interleaved_channels == 1 {
26 let samples = interleaved.len();
29 let ch =
30 &mut channels[0].as_mut()[start_frame_in_channels..start_frame_in_channels + samples];
31
32 ch.copy_from_slice(interleaved);
33
34 if calculate_silence_mask {
35 if ch.iter().find(|&&s| s != 0.0).is_none() {
36 silence_mask.set_channel(0, true);
37 }
38 }
39
40 (1, samples)
41 } else if num_interleaved_channels == 2 && channels.len() >= 2 {
42 let samples = interleaved.len() / 2;
45
46 let (ch0, ch1) = channels.split_first_mut().unwrap();
47 let ch0 = &mut ch0.as_mut()[start_frame_in_channels..start_frame_in_channels + samples];
48 let ch1 = &mut ch1[0].as_mut()[start_frame_in_channels..start_frame_in_channels + samples];
49
50 for (in_chunk, (ch0_s, ch1_s)) in interleaved
51 .chunks_exact(2)
52 .zip(ch0.iter_mut().zip(ch1.iter_mut()))
53 {
54 *ch0_s = in_chunk[0];
55 *ch1_s = in_chunk[1];
56 }
57
58 if calculate_silence_mask {
59 for (ch_i, ch) in channels.iter_mut().enumerate() {
60 if ch.as_mut()[0..samples]
61 .iter()
62 .find(|&&s| s != 0.0)
63 .is_none()
64 {
65 silence_mask.set_channel(ch_i, true);
66 }
67 }
68 }
69
70 (2, samples)
71 } else {
72 let mut num_filled_channels = 0;
73 let samples = interleaved.len() / num_interleaved_channels;
74
75 for (ch_i, ch) in (0..num_interleaved_channels).zip(channels.iter_mut()) {
76 let ch = &mut ch.as_mut()[start_frame_in_channels..start_frame_in_channels + samples];
77
78 for (in_chunk, out_s) in interleaved
79 .chunks_exact(num_interleaved_channels)
80 .zip(ch.iter_mut())
81 {
82 *out_s = in_chunk[ch_i];
83 }
84
85 if calculate_silence_mask && ch_i < 64 {
86 if ch.iter().find(|&&s| s != 0.0).is_none() {
87 silence_mask.set_channel(ch_i, true);
88 }
89 }
90
91 num_filled_channels += 1;
92 }
93
94 (num_filled_channels, samples)
95 };
96
97 if num_filled_channels < channels.len() {
98 for (ch_i, ch) in channels.iter_mut().enumerate().skip(num_filled_channels) {
99 ch.as_mut()[start_frame_in_channels..start_frame_in_channels + samples].fill(0.0);
100
101 if calculate_silence_mask && ch_i < 64 {
102 silence_mask.set_channel(ch_i, true);
103 }
104 }
105 }
106
107 silence_mask
108}
109
110pub fn interleave<V: AsRef<[f32]>>(
112 channels: &[V],
113 start_frame_in_channels: usize,
114 interleaved: &mut [f32],
115 num_interleaved_channels: usize,
116 silence_mask: Option<SilenceMask>,
117) {
118 if channels.is_empty() || num_interleaved_channels == 0 {
119 interleaved.fill(0.0);
120 return;
121 }
122
123 if let Some(silence_mask) = silence_mask {
124 if channels.len() <= 64 {
125 if silence_mask.all_channels_silent(channels.len()) {
126 interleaved.fill(0.0);
127 return;
128 }
129 }
130 }
131
132 if num_interleaved_channels == 1 {
133 interleaved.copy_from_slice(
135 &channels[0].as_ref()
136 [start_frame_in_channels..start_frame_in_channels + interleaved.len()],
137 );
138 return;
139 }
140
141 if num_interleaved_channels == 2 && channels.len() >= 2 {
142 let samples = interleaved.len() / 2;
144
145 let ch1 = &channels[0].as_ref()[start_frame_in_channels..start_frame_in_channels + samples];
146 let ch2 = &channels[1].as_ref()[start_frame_in_channels..start_frame_in_channels + samples];
147
148 for (out_chunk, (&ch1_s, &ch2_s)) in interleaved
149 .chunks_exact_mut(2)
150 .zip(ch1.iter().zip(ch2.iter()))
151 {
152 out_chunk[0] = ch1_s;
153 out_chunk[1] = ch2_s;
154 }
155
156 return;
157 }
158
159 let any_channel_silent = if let Some(silence_mask) = silence_mask {
160 if channels.len() <= 64 {
161 silence_mask.any_channel_silent(channels.len())
162 } else {
163 true
164 }
165 } else {
166 false
167 };
168
169 if num_interleaved_channels > channels.len() || any_channel_silent {
170 interleaved.fill(0.0);
171 }
172
173 for (ch_i, ch) in (0..num_interleaved_channels).zip(channels.iter()) {
174 if let Some(silence_mask) = silence_mask {
175 if ch_i < 64 {
176 if silence_mask.is_channel_silent(ch_i) {
177 continue;
178 }
179 }
180 }
181
182 for (out_chunk, &in_s) in interleaved
183 .chunks_exact_mut(num_interleaved_channels)
184 .zip(ch.as_ref()[start_frame_in_channels..].iter())
185 {
186 out_chunk[ch_i] = in_s;
187 }
188 }
189}