1use crate::util::check_collection_clap_size_overflow;
4use clack_common::process::AudioPortProcessingInfo;
5use clap_sys::audio_buffer::clap_audio_buffer;
6use core::array::IntoIter;
7
8pub struct InputChannel<'a, T> {
9 pub buffer: &'a mut [T],
10 pub is_constant: bool,
11}
12
13impl<'a, T> InputChannel<'a, T> {
14 #[inline]
15 pub fn from_buffer<D: ?Sized + AsMut<[T]> + 'a>(buffer: &'a mut D, is_constant: bool) -> Self {
16 Self {
17 buffer: buffer.as_mut(),
18 is_constant,
19 }
20 }
21
22 #[inline]
23 pub fn variable<D: ?Sized + AsMut<[T]> + 'a>(buffer: &'a mut D) -> Self {
24 Self::from_buffer(buffer, false)
25 }
26
27 #[inline]
28 pub fn constant<D: ?Sized + AsMut<[T]> + 'a>(buffer: &'a mut D) -> Self {
29 Self::from_buffer(buffer, true)
30 }
31}
32
33pub enum AudioPortBufferType<I32, I64> {
34 F32(I32),
35 F64(I64),
36}
37
38impl<I32> AudioPortBufferType<I32, IntoIter<InputChannel<'static, f64>, 0>> {
39 #[inline]
40 pub fn f32_input_only(iterator: I32) -> Self {
41 Self::F32(iterator)
42 }
43}
44
45impl<I32> AudioPortBufferType<I32, IntoIter<&'static mut [f64], 0>> {
46 #[inline]
47 pub fn f32_output_only(iterator: I32) -> Self {
48 Self::F32(iterator)
49 }
50}
51
52impl<I64> AudioPortBufferType<IntoIter<InputChannel<'static, f32>, 0>, I64> {
53 #[inline]
54 pub fn f64_input_only(iterator: I64) -> Self {
55 Self::F64(iterator)
56 }
57}
58
59impl<I64> AudioPortBufferType<IntoIter<&'static mut [f32], 0>, I64> {
60 #[inline]
61 pub fn f64_output_only(iterator: I64) -> Self {
62 Self::F64(iterator)
63 }
64}
65
66pub struct AudioPortBuffer<I32, I64> {
67 pub channels: AudioPortBufferType<I32, I64>,
68 pub latency: u32,
69}
70
71pub struct AudioPorts {
73 buffer_lists: Vec<*mut f32>, buffer_configs: Vec<clap_audio_buffer>,
75}
76
77unsafe impl Send for AudioPorts {}
79unsafe impl Sync for AudioPorts {}
81
82impl AudioPorts {
83 #[cfg(feature = "clack-plugin")]
84 pub fn from_plugin_audio_mut<'a>(
85 audio: &'a mut clack_plugin::prelude::Audio,
86 ) -> (InputAudioBuffers<'a>, OutputAudioBuffers<'a>) {
87 let frames_count = audio.frames_count();
88 let (ins, outs) = audio.raw_buffers();
89
90 unsafe {
92 (
93 InputAudioBuffers::from_raw_buffers(ins, frames_count),
94 OutputAudioBuffers::from_raw_buffers(outs, frames_count),
95 )
96 }
97 }
98
99 #[cfg(feature = "clack-plugin")]
100 pub fn from_plugin_audio(
101 audio: clack_plugin::prelude::Audio,
102 ) -> (InputAudioBuffers, OutputAudioBuffers) {
103 let frames_count = audio.frames_count();
104 let (ins, outs) = audio.to_raw_buffers();
105
106 unsafe {
108 (
109 InputAudioBuffers::from_raw_buffers(ins, frames_count),
110 OutputAudioBuffers::from_raw_buffers(outs, frames_count),
111 )
112 }
113 }
114
115 pub fn with_capacity(total_channel_count: usize, port_count: usize) -> Self {
116 let mut bufs = Self {
117 buffer_configs: Vec::with_capacity(port_count),
118 buffer_lists: Vec::with_capacity(total_channel_count),
119 };
120 bufs.resize_buffer_configs(port_count);
121
122 bufs
123 }
124
125 #[inline]
126 pub fn port_capacity(&self) -> usize {
127 self.buffer_configs.len()
128 }
129
130 fn resize_buffer_configs(&mut self, new_size: usize) {
131 if new_size > self.buffer_configs.len() {
132 self.buffer_configs.resize(
133 new_size,
134 clap_audio_buffer {
135 data32: core::ptr::null_mut(),
136 data64: core::ptr::null_mut(),
137 channel_count: 0,
138 latency: 0,
139 constant_mask: 0,
140 },
141 );
142 }
143 }
144
145 pub fn with_input_buffers<'a, I, Iter, ChannelIter32, ChannelIter64>(
146 &'a mut self,
147 iter: I,
148 ) -> InputAudioBuffers<'a>
149 where
150 I: IntoIterator<Item = AudioPortBuffer<ChannelIter32, ChannelIter64>, IntoIter = Iter>,
151 Iter: ExactSizeIterator<Item = AudioPortBuffer<ChannelIter32, ChannelIter64>>,
152 ChannelIter32: IntoIterator<Item = InputChannel<'a, f32>>,
153 ChannelIter64: IntoIterator<Item = InputChannel<'a, f64>>,
154 {
155 let iter = iter.into_iter();
156 self.resize_buffer_configs(iter.len());
157 self.buffer_lists.clear();
158
159 let mut min_channel_buffer_length = u32::MAX;
160 let mut total = 0;
161 let mut has_reallocated = false;
162
163 for (i, port) in iter.enumerate() {
164 total = i + 1;
165
166 let last = self.buffer_lists.len();
167
168 let mut constant_mask = 0u64;
169 let is_f64 = match port.channels {
170 AudioPortBufferType::F32(channels) => {
171 for channel in channels {
172 min_channel_buffer_length = min_channel_buffer_length
173 .min(saturate_usize_to_clap_size(channel.buffer.len()));
174 if channel.is_constant {
175 constant_mask |= 1 << i as u64
176 }
177
178 check_collection_clap_size_overflow(&self.buffer_lists);
179
180 if self.buffer_lists.len() >= self.buffer_lists.capacity() {
181 has_reallocated = true;
182 }
183
184 self.buffer_lists.push(channel.buffer.as_mut_ptr().cast())
185 }
186 false
187 }
188 AudioPortBufferType::F64(channels) => {
189 for channel in channels {
190 min_channel_buffer_length = min_channel_buffer_length
191 .min(saturate_usize_to_clap_size(channel.buffer.len()));
192 if channel.is_constant {
193 constant_mask |= 1 << i as u64
194 }
195
196 check_collection_clap_size_overflow(&self.buffer_lists);
197
198 if self.buffer_lists.len() >= self.buffer_lists.capacity() {
199 has_reallocated = true;
200 }
201
202 self.buffer_lists.push(channel.buffer.as_mut_ptr().cast())
203 }
204 true
205 }
206 };
207
208 let buffers = self.buffer_lists.get_mut(last..).unwrap_or(&mut []);
209
210 let descriptor = &mut self.buffer_configs[i];
212 #[allow(clippy::cast_possible_truncation)]
213 {
215 descriptor.channel_count = buffers.len() as u32;
216 }
217 descriptor.latency = port.latency;
218 descriptor.constant_mask = constant_mask;
219
220 if is_f64 {
221 descriptor.data64 = buffers.as_mut_ptr().cast();
222 descriptor.data32 = core::ptr::null_mut();
223 } else {
224 descriptor.data64 = core::ptr::null_mut();
225 descriptor.data32 = buffers.as_mut_ptr();
226 }
227 }
228
229 if has_reallocated {
233 let mut last_len = 0;
234 for descriptor in &mut self.buffer_configs[..total] {
235 let channel_count = descriptor.channel_count as usize;
236 let buffers = self
237 .buffer_lists
238 .get_mut(last_len..channel_count)
239 .unwrap_or(&mut []);
240 last_len += channel_count;
241
242 if descriptor.data32.is_null() {
243 descriptor.data64 = buffers.as_mut_ptr().cast();
244 } else {
245 descriptor.data32 = buffers.as_mut_ptr();
246 }
247 }
248 }
249
250 InputAudioBuffers {
251 buffers: &self.buffer_configs[..total],
252 frames_count: if min_channel_buffer_length == u32::MAX {
253 None
254 } else {
255 Some(min_channel_buffer_length)
256 },
257 }
258 }
259
260 pub fn with_output_buffers<'a, I, Iter, ChannelIter32, ChannelIter64>(
261 &'a mut self,
262 iter: I,
263 ) -> OutputAudioBuffers<'a>
264 where
265 I: IntoIterator<Item = AudioPortBuffer<ChannelIter32, ChannelIter64>, IntoIter = Iter>,
266 Iter: ExactSizeIterator<Item = AudioPortBuffer<ChannelIter32, ChannelIter64>>,
267 ChannelIter32: IntoIterator<Item = &'a mut [f32]>,
268 ChannelIter64: IntoIterator<Item = &'a mut [f64]>,
269 {
270 let iter = iter.into_iter();
271 self.resize_buffer_configs(iter.len());
272 self.buffer_lists.clear();
273
274 let mut min_channel_buffer_length = u32::MAX;
275 let mut total = 0;
276 let mut has_reallocated = false;
277
278 for (i, port) in iter.enumerate() {
279 total = i + 1;
280
281 let last = self.buffer_lists.len();
282
283 let is_f64 = match port.channels {
284 AudioPortBufferType::F32(channels) => {
285 for channel in channels {
286 min_channel_buffer_length = min_channel_buffer_length
287 .min(saturate_usize_to_clap_size(channel.len()));
288
289 check_collection_clap_size_overflow(&self.buffer_lists);
290
291 if self.buffer_lists.len() >= self.buffer_lists.capacity() {
292 has_reallocated = true;
293 }
294
295 self.buffer_lists.push(channel.as_mut_ptr().cast())
296 }
297 false
298 }
299 AudioPortBufferType::F64(channels) => {
300 for channel in channels {
301 min_channel_buffer_length = min_channel_buffer_length
302 .min(saturate_usize_to_clap_size(channel.len()));
303
304 check_collection_clap_size_overflow(&self.buffer_lists);
305
306 if self.buffer_lists.len() >= self.buffer_lists.capacity() {
307 has_reallocated = true;
308 }
309
310 self.buffer_lists.push(channel.as_mut_ptr().cast())
311 }
312 true
313 }
314 };
315
316 let buffers = self.buffer_lists.get_mut(last..).unwrap_or(&mut []);
317
318 let descriptor = &mut self.buffer_configs[i];
320 #[allow(clippy::cast_possible_truncation)]
321 {
323 descriptor.channel_count = buffers.len() as u32;
324 }
325 descriptor.latency = port.latency;
326 descriptor.constant_mask = 0;
327
328 if is_f64 {
329 descriptor.data64 = buffers.as_mut_ptr().cast();
330 descriptor.data32 = core::ptr::null_mut();
331 } else {
332 descriptor.data64 = core::ptr::null_mut();
333 descriptor.data32 = buffers.as_mut_ptr();
334 }
335 }
336
337 if has_reallocated {
341 let mut last_len = 0;
342 for descriptor in &mut self.buffer_configs[..total] {
343 let channel_count = descriptor.channel_count as usize;
344 let buffers = self
345 .buffer_lists
346 .get_mut(last_len..channel_count)
347 .unwrap_or(&mut []);
348 last_len += channel_count;
349
350 if descriptor.data32.is_null() {
351 descriptor.data64 = buffers.as_mut_ptr().cast();
352 } else {
353 descriptor.data32 = buffers.as_mut_ptr();
354 }
355 }
356 }
357
358 OutputAudioBuffers {
359 buffers: &mut self.buffer_configs[..total],
360 frames_count: if min_channel_buffer_length == u32::MAX {
361 None
362 } else {
363 Some(min_channel_buffer_length)
364 },
365 }
366 }
367
368 #[inline]
369 pub fn port_count(&self) -> usize {
370 self.buffer_configs.len()
371 }
372}
373
374#[inline]
375const fn saturate_usize_to_clap_size(value: usize) -> u32 {
376 if value > u32::MAX as usize {
377 u32::MAX - 1
378 } else {
379 #[allow(clippy::cast_possible_truncation)] {
381 value as u32
382 }
383 }
384}
385
386pub struct InputAudioBuffers<'a> {
387 buffers: &'a [clap_audio_buffer],
388 frames_count: Option<u32>,
389}
390
391impl<'a> InputAudioBuffers<'a> {
392 #[inline]
393 pub const fn empty() -> Self {
394 Self {
395 buffers: &[],
396 frames_count: None,
397 }
398 }
399
400 pub fn truncate(&mut self, max_buffer_size: u32) {
409 if let Some(frames_count) = self.frames_count {
410 self.frames_count = Some(frames_count.min(max_buffer_size))
411 }
412 }
413
414 #[inline]
422 pub unsafe fn from_raw_buffers(buffers: &'a [clap_audio_buffer], frames_count: u32) -> Self {
423 check_collection_clap_size_overflow(buffers);
424
425 Self {
426 buffers,
427 frames_count: Some(frames_count),
428 }
429 }
430
431 #[cfg(feature = "clack-plugin")]
432 pub fn from_plugin_audio(audio: &clack_plugin::prelude::Audio<'a>) -> InputAudioBuffers<'a> {
433 let frames_count = audio.frames_count();
434 let ins = audio.raw_input_buffers();
435
436 unsafe { InputAudioBuffers::from_raw_buffers(ins, frames_count) }
438 }
439
440 #[cfg(feature = "clack-plugin")]
441 pub fn as_plugin_audio(&self) -> clack_plugin::prelude::Audio<'a> {
442 unsafe {
444 clack_plugin::prelude::Audio::from_raw_buffers(
445 self.buffers,
446 &mut [],
447 self.frames_count.unwrap_or(0),
448 )
449 }
450 }
451
452 #[inline]
453 pub fn as_raw_buffers(&self) -> &'a [clap_audio_buffer] {
454 self.buffers
455 }
456
457 #[inline]
459 pub fn port_count(&self) -> u32 {
460 #[allow(clippy::cast_possible_truncation)]
461 {
463 self.buffers.len() as u32
464 }
465 }
466
467 #[inline]
473 pub fn frames_count(&self) -> Option<u32> {
474 self.frames_count
475 }
476
477 #[inline]
478 pub fn port_info(&self, port_index: u32) -> Option<AudioPortProcessingInfo> {
479 self.buffers
480 .get(port_index as usize)
481 .map(AudioPortProcessingInfo::from_raw)
482 }
483
484 #[inline]
485 pub fn port_infos(&self) -> impl Iterator<Item = AudioPortProcessingInfo> + '_ {
486 self.buffers.iter().map(AudioPortProcessingInfo::from_raw)
487 }
488
489 pub fn min_available_frames_with(&self, outputs: &OutputAudioBuffers) -> u32 {
495 match (self.frames_count, outputs.frames_count) {
496 (Some(a), Some(b)) => a.min(b),
497 (Some(a), None) | (None, Some(a)) => a,
498 (None, None) => 0,
499 }
500 }
501}
502
503pub struct OutputAudioBuffers<'a> {
504 buffers: &'a mut [clap_audio_buffer],
505 frames_count: Option<u32>,
506}
507
508impl<'a> OutputAudioBuffers<'a> {
509 #[inline]
510 pub fn empty() -> Self {
511 Self {
512 buffers: &mut [],
513 frames_count: None,
514 }
515 }
516
517 pub fn truncate(&mut self, max_buffer_size: u32) {
526 if let Some(frames_count) = self.frames_count {
527 self.frames_count = Some(frames_count.min(max_buffer_size))
528 }
529 }
530
531 #[inline]
539 pub unsafe fn from_raw_buffers(
540 buffers: &'a mut [clap_audio_buffer],
541 frames_count: u32,
542 ) -> Self {
543 check_collection_clap_size_overflow(buffers);
544
545 Self {
546 buffers,
547 frames_count: Some(frames_count),
548 }
549 }
550
551 #[cfg(feature = "clack-plugin")]
552 pub fn from_plugin_audio(audio: clack_plugin::prelude::Audio<'a>) -> OutputAudioBuffers<'a> {
553 let frames_count = audio.frames_count();
554 let outs = audio.to_raw_output_buffers();
555
556 unsafe { OutputAudioBuffers::from_raw_buffers(outs, frames_count) }
558 }
559
560 #[cfg(feature = "clack-plugin")]
561 pub fn from_plugin_audio_mut(
562 audio: &'a mut clack_plugin::prelude::Audio,
563 ) -> OutputAudioBuffers<'a> {
564 let frames_count = audio.frames_count();
565 let outs = audio.raw_output_buffers();
566
567 unsafe { OutputAudioBuffers::from_raw_buffers(outs, frames_count) }
569 }
570
571 #[cfg(feature = "clack-plugin")]
572 pub fn as_plugin_audio(&'a mut self) -> clack_plugin::prelude::Audio<'a> {
573 unsafe {
575 clack_plugin::prelude::Audio::from_raw_buffers(
576 &[],
577 self.buffers,
578 self.frames_count.unwrap_or(0),
579 )
580 }
581 }
582
583 #[cfg(feature = "clack-plugin")]
584 pub fn to_plugin_audio(self) -> clack_plugin::prelude::Audio<'a> {
585 unsafe {
587 clack_plugin::prelude::Audio::from_raw_buffers(
588 &[],
589 self.buffers,
590 self.frames_count.unwrap_or(0),
591 )
592 }
593 }
594
595 #[cfg(feature = "clack-plugin")]
596 pub fn as_plugin_audio_with_inputs(
597 &'a mut self,
598 inputs: &InputAudioBuffers<'a>,
599 ) -> clack_plugin::prelude::Audio<'a> {
600 let frames_count = inputs.min_available_frames_with(self);
601
602 unsafe {
604 clack_plugin::prelude::Audio::from_raw_buffers(
605 inputs.buffers,
606 self.buffers,
607 frames_count,
608 )
609 }
610 }
611
612 #[cfg(feature = "clack-plugin")]
613 pub fn to_plugin_audio_with_inputs(
614 self,
615 inputs: &InputAudioBuffers<'a>,
616 ) -> clack_plugin::prelude::Audio<'a> {
617 let frames_count = inputs.min_available_frames_with(&self);
618
619 unsafe {
621 clack_plugin::prelude::Audio::from_raw_buffers(
622 inputs.buffers,
623 self.buffers,
624 frames_count,
625 )
626 }
627 }
628
629 #[inline]
630 pub fn as_raw_buffers(&mut self) -> &mut [clap_audio_buffer] {
631 self.buffers
632 }
633
634 #[inline]
635 pub fn into_raw_buffers(self) -> &'a mut [clap_audio_buffer] {
636 self.buffers
637 }
638
639 #[inline]
641 pub fn port_count(&self) -> u32 {
642 #[allow(clippy::cast_possible_truncation)]
643 {
645 self.buffers.len() as u32
646 }
647 }
648
649 #[inline]
655 pub fn frames_count(&self) -> Option<u32> {
656 self.frames_count
657 }
658
659 #[inline]
660 pub fn port_info(&self, port_index: u32) -> Option<AudioPortProcessingInfo> {
661 self.buffers
662 .get(port_index as usize)
663 .map(AudioPortProcessingInfo::from_raw)
664 }
665
666 #[inline]
667 pub fn port_infos(&self) -> impl Iterator<Item = AudioPortProcessingInfo> + '_ {
668 self.buffers.iter().map(AudioPortProcessingInfo::from_raw)
669 }
670}
671
672#[cfg(test)]
673mod test {
674 use super::*;
675 use clack_plugin::prelude::*;
676 use clap_sys::process::clap_process;
677 use std::cell::RefCell;
678 use std::ptr::null_mut;
679
680 #[test]
681 pub fn input_audio_buffers_work() {
682 let mut ports = AudioPorts::with_capacity(2, 1);
683 let mut bufs = [[0f32; 4]; 2];
684
685 let buffers = ports.with_input_buffers([AudioPortBuffer {
686 latency: 0,
687 channels: AudioPortBufferType::f32_input_only(bufs.iter_mut().map(|b| InputChannel {
688 buffer: b.as_mut_slice(),
689 is_constant: false,
690 })),
691 }]);
692
693 assert_eq!(buffers.buffers.len(), 1);
694 assert_eq!(buffers.frames_count, Some(4));
695 }
696
697 #[test]
698 pub fn output_audio_buffers_work() {
699 let mut ports = AudioPorts::with_capacity(2, 1);
700 let mut bufs = [[0f32; 4]; 2];
701
702 let buffers = ports.with_output_buffers([AudioPortBuffer {
703 latency: 0,
704 channels: AudioPortBufferType::f32_output_only(
705 bufs.iter_mut().map(|b| b.as_mut_slice()),
706 ),
707 }]);
708
709 assert_eq!(buffers.buffers.len(), 1);
710 assert_eq!(buffers.frames_count, Some(4));
711
712 assert_eq!(bufs.len(), 2); assert_eq!(ports.port_count(), 1);
714 }
715
716 #[test]
717 pub fn input_audio_buffers_work_with_refcell() {
718 let mut ports = AudioPorts::with_capacity(2, 1);
719 let bufs = [RefCell::new([0f32; 4]), RefCell::new([0f32; 4])];
720 let mut borrowed: Vec<_> = bufs.iter().map(|c| c.borrow_mut()).collect();
721
722 let buffers = ports.with_input_buffers([AudioPortBuffer {
723 latency: 0,
724 channels: AudioPortBufferType::f32_input_only(borrowed.iter_mut().map(|b| {
725 InputChannel {
726 buffer: b.as_mut_slice(),
727 is_constant: false,
728 }
729 })),
730 }]);
731
732 assert_eq!(buffers.buffers.len(), 1);
733 assert_eq!(buffers.frames_count, Some(4));
734 }
735
736 #[test]
737 pub fn output_audio_buffers_work_with_refcell() {
738 let mut ports = AudioPorts::with_capacity(2, 1);
739 let bufs = [RefCell::new([0f32; 4]), RefCell::new([0f32; 4])];
740 let mut borrowed: Vec<_> = bufs.iter().map(|c| c.borrow_mut()).collect();
741
742 let buffers = ports.with_output_buffers([AudioPortBuffer {
743 latency: 0,
744 channels: AudioPortBufferType::f32_output_only(
745 borrowed.iter_mut().map(|b| b.as_mut_slice()),
746 ),
747 }]);
748
749 assert_eq!(buffers.buffers.len(), 1);
750 assert_eq!(buffers.frames_count, Some(4));
751
752 assert_eq!(bufs.len(), 2); assert_eq!(ports.port_count(), 1);
754 }
755
756 #[test]
757 pub fn audio_buffers_work_with_wrong_capacity() {
758 let mut input_ports = AudioPorts::with_capacity(1, 1);
759 let mut output_ports = AudioPorts::with_capacity(1, 1);
760 let mut input_bufs = [[[42f32; 4]; 128], [[69f32; 4]; 128]];
761 let mut output_bufs = [[[42f32; 4]; 128], [[69f32; 4]; 128]];
762
763 let input_buffers =
764 input_ports.with_input_buffers(input_bufs.iter_mut().map(|bufs| AudioPortBuffer {
765 latency: 0,
766 channels: AudioPortBufferType::f32_input_only(bufs.iter_mut().map(|b| {
767 InputChannel {
768 buffer: b.as_mut_slice(),
769 is_constant: false,
770 }
771 })),
772 }));
773
774 let mut output_buffers =
775 output_ports.with_output_buffers(output_bufs.iter_mut().map(|bufs| AudioPortBuffer {
776 latency: 0,
777 channels: AudioPortBufferType::f32_output_only(
778 bufs.iter_mut().map(|b| b.as_mut_slice()),
779 ),
780 }));
781
782 assert_eq!(input_buffers.buffers.len(), 2);
783 assert_eq!(input_buffers.frames_count, Some(4));
784 assert_eq!(output_buffers.buffers.len(), 2);
785 assert_eq!(output_buffers.frames_count, Some(4));
786
787 let raw_input_buffers = input_buffers.as_raw_buffers();
788 let raw_output_buffers = output_buffers.as_raw_buffers();
789 let process = clap_process {
790 audio_inputs: raw_input_buffers.as_ptr(),
791 audio_outputs: raw_output_buffers.as_ptr() as *mut _,
792 audio_inputs_count: input_buffers.port_count(),
793 audio_outputs_count: output_buffers.port_count(),
794
795 steady_time: 0,
796 frames_count: 4,
797 transport: null_mut(),
798 in_events: null_mut(),
799 out_events: null_mut(),
800 };
801
802 let mut audio = unsafe { Audio::from_raw(&process) };
804
805 for (port, bufs) in audio.input_ports().zip(&input_bufs) {
806 let channels = port.channels().unwrap().into_f32().unwrap();
807
808 assert_eq!(channels.channel_count(), 128);
809 for (channel, buf) in channels.iter().zip(bufs.iter()) {
810 assert_eq!(buf, channel)
811 }
812 }
813
814 for (mut port, bufs) in audio.output_ports().zip(&output_bufs) {
815 let channels = port.channels().unwrap().into_f32().unwrap();
816
817 assert_eq!(channels.channel_count(), 128);
818 for (channel, buf) in channels.iter().zip(bufs.iter()) {
819 assert_eq!(buf, channel)
820 }
821 }
822 }
823}