cxx_juce/
juce_audio_devices.rs

1//! Play and record from audio and MIDI I/O devices.
2
3use {
4    crate::{juce, Result, JUCE},
5    slotmap::SlotMap,
6    std::{
7        ops::{Index, IndexMut},
8        pin::Pin,
9    },
10};
11
12/// A multi-channel buffer of read-only audio samples.
13pub struct InputAudioSampleBuffer<'a> {
14    buffer: &'a juce::AudioSampleBuffer,
15}
16
17impl<'a> InputAudioSampleBuffer<'a> {
18    pub(crate) fn new(buffer: &'a juce::AudioSampleBuffer) -> Self {
19        Self { buffer }
20    }
21
22    /// Returns the numbers of channels in the buffer.
23    pub fn channels(&self) -> usize {
24        self.buffer.get_num_channels() as usize
25    }
26
27    /// Returns the number of samples for each channel.
28    pub fn samples(&self) -> usize {
29        self.buffer.get_num_samples() as usize
30    }
31}
32
33impl Index<usize> for InputAudioSampleBuffer<'_> {
34    type Output = [f32];
35
36    fn index(&self, channel: usize) -> &Self::Output {
37        if self.channels() < channel {
38            panic!("channel out of bounds");
39        }
40
41        let ptr = self.buffer.get_read_pointer(channel as i32);
42        let len = self.samples();
43
44        unsafe { std::slice::from_raw_parts(ptr, len) }
45    }
46}
47
48/// A multi-channel buffer of read-write audio samples.
49pub struct OutputAudioSampleBuffer<'a> {
50    buffer: Pin<&'a mut juce::AudioSampleBuffer>,
51}
52
53impl<'a> OutputAudioSampleBuffer<'a> {
54    pub(crate) fn new(buffer: Pin<&'a mut juce::AudioSampleBuffer>) -> Self {
55        Self { buffer }
56    }
57
58    /// Returns the numbers of channels in the buffer.
59    pub fn channels(&self) -> usize {
60        self.buffer.get_num_channels() as usize
61    }
62
63    /// Returns the number of samples for each channel.
64    pub fn samples(&self) -> usize {
65        self.buffer.get_num_samples() as usize
66    }
67
68    /// Clear all the samples for all the channels.
69    pub fn clear(&mut self) {
70        self.buffer.as_mut().clear();
71    }
72}
73
74impl Index<usize> for OutputAudioSampleBuffer<'_> {
75    type Output = [f32];
76
77    fn index(&self, channel: usize) -> &Self::Output {
78        if self.channels() < channel {
79            panic!("channel out of bounds");
80        }
81
82        let ptr = self.buffer.get_read_pointer(channel as i32);
83        let len = self.samples();
84
85        unsafe { std::slice::from_raw_parts(ptr, len) }
86    }
87}
88
89impl IndexMut<usize> for OutputAudioSampleBuffer<'_> {
90    fn index_mut(&mut self, channel: usize) -> &mut Self::Output {
91        if self.channels() < channel {
92            panic!("channel out of bounds");
93        }
94
95        let ptr = self.buffer.as_mut().get_write_pointer(channel as i32);
96        let len = self.samples();
97
98        unsafe { std::slice::from_raw_parts_mut(ptr, len) }
99    }
100}
101
102/// The properties of an audio device.
103pub struct AudioDeviceSetup(cxx::UniquePtr<juce::AudioDeviceSetup>);
104
105unsafe impl Send for AudioDeviceSetup {}
106
107impl Default for AudioDeviceSetup {
108    fn default() -> Self {
109        Self(juce::create_audio_device_setup())
110    }
111}
112
113/// The number of channels to use.
114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
115pub enum ChannelCount {
116    /// Use the default number of channels for the device.
117    Default,
118
119    /// Use a custom number of channels.
120    Custom(i32),
121}
122
123unsafe impl Send for ChannelCount {}
124
125impl AudioDeviceSetup {
126    /// The name of the output device.
127    pub fn output_device_name(&self) -> &str {
128        self.0.output_device_name()
129    }
130
131    /// Set the name of the output device.
132    pub fn with_output_device_name(mut self, name: impl AsRef<str>) -> Self {
133        self.0.pin_mut().set_output_device_name(name.as_ref());
134        self
135    }
136
137    /// The name of the input device.
138    pub fn input_device_name(&self) -> &str {
139        self.0.input_device_name()
140    }
141
142    /// Set the name of the input device.
143    pub fn with_input_device_name(mut self, name: impl AsRef<str>) -> Self {
144        self.0.pin_mut().set_input_device_name(name.as_ref());
145        self
146    }
147
148    /// The sample rate in Hertz.
149    pub fn sample_rate(&self) -> f64 {
150        self.0.sample_rate()
151    }
152
153    /// Set the sample rate in Hertz.
154    pub fn with_sample_rate(mut self, sample_rate: f64) -> Self {
155        self.0.pin_mut().set_sample_rate(sample_rate);
156        self
157    }
158
159    /// The buffer size.
160    pub fn buffer_size(&self) -> usize {
161        self.0.buffer_size() as usize
162    }
163
164    /// The buffer size to use.
165    pub fn with_buffer_size(mut self, buffer_size: usize) -> Self {
166        self.0.pin_mut().set_buffer_size(buffer_size as i32);
167        self
168    }
169
170    /// The number of input channels.
171    pub fn input_channels(&self) -> ChannelCount {
172        if self.0.using_default_input_channels() {
173            ChannelCount::Default
174        } else {
175            ChannelCount::Custom(self.0.number_of_input_channels())
176        }
177    }
178
179    // Set the number of input channels.
180    pub fn with_input_channels(mut self, channels: ChannelCount) -> Self {
181        match channels {
182            ChannelCount::Default => {
183                self.0.pin_mut().use_default_input_channels(true);
184            }
185            ChannelCount::Custom(count) => {
186                self.0.pin_mut().use_default_input_channels(false);
187                self.0.pin_mut().set_number_of_input_channels(count);
188            }
189        }
190
191        self
192    }
193
194    /// The number of output channels.
195    pub fn output_channels(&self) -> ChannelCount {
196        if self.0.using_default_output_channels() {
197            ChannelCount::Default
198        } else {
199            ChannelCount::Custom(self.0.number_of_output_channels())
200        }
201    }
202
203    /// Set the number of output channels.
204    pub fn with_output_channels(mut self, channels: ChannelCount) -> Self {
205        match channels {
206            ChannelCount::Default => {
207                self.0.pin_mut().use_default_output_channels(true);
208            }
209            ChannelCount::Custom(count) => {
210                self.0.pin_mut().use_default_output_channels(false);
211                self.0.pin_mut().set_number_of_output_channels(count);
212            }
213        }
214
215        self
216    }
217}
218
219slotmap::new_key_type! {
220    struct AudioCallbackKey;
221}
222
223/// Manages the state of an audio device.
224pub struct AudioDeviceManager {
225    device_manager: cxx::UniquePtr<juce::AudioDeviceManager>,
226    callbacks: SlotMap<AudioCallbackKey, cxx::UniquePtr<juce::AudioCallbackWrapper>>,
227    _juce: JUCE,
228}
229
230impl AudioDeviceManager {
231    /// Create a new [`AudioDeviceManager`].
232    pub fn new(juce: &JUCE) -> Self {
233        Self {
234            device_manager: juce::create_audio_device_manager(),
235            callbacks: SlotMap::with_key(),
236            _juce: juce.clone(),
237        }
238    }
239
240    /// Resets to a default device setup.
241    pub fn initialise(&mut self, input_channels: usize, output_channels: usize) -> Result<()> {
242        self.device_manager
243            .pin_mut()
244            .initialise_with_default_devices(input_channels as i32, output_channels as i32)
245    }
246
247    /// Get the current device setup.
248    pub fn audio_device_setup(&self) -> AudioDeviceSetup {
249        AudioDeviceSetup(self.device_manager.get_audio_device_setup())
250    }
251
252    /// Changes the current device or its settings.
253    pub fn set_audio_device_setup(&mut self, setup: &AudioDeviceSetup) {
254        self.device_manager
255            .pin_mut()
256            .set_audio_device_setup(&setup.0);
257    }
258
259    /// Play a test sound.
260    pub fn play_test_sound(&mut self) {
261        self.device_manager.pin_mut().play_test_sound();
262    }
263
264    /// Get the available device types.
265    pub fn device_types(&mut self) -> Vec<impl AudioIODeviceType + '_> {
266        let available_device_types = self.device_manager.pin_mut().get_available_device_types();
267
268        (0..available_device_types.size())
269            .map(|i| available_device_types.get_unchecked(i))
270            .collect()
271    }
272
273    /// Get the current device type.
274    pub fn current_device_type(&self) -> Option<impl AudioIODeviceType + '_> {
275        let device_type = self.device_manager.get_current_device_type_object();
276        if !device_type.is_null() {
277            Some(device_type)
278        } else {
279            None
280        }
281    }
282
283    /// Get the current [`AudioIODevice`].
284    pub fn current_device(&self) -> Option<impl AudioIODevice + '_> {
285        let current_device = self.device_manager.get_current_audio_device();
286        if !current_device.is_null() {
287            Some(current_device)
288        } else {
289            None
290        }
291    }
292
293    /// Registers an audio callback.
294    pub fn add_audio_callback(
295        &mut self,
296        callback: impl AudioIODeviceCallback + 'static,
297    ) -> AudioCallbackHandle {
298        let callback = Box::new(callback);
299        let callback = juce::wrap_audio_callback(Box::new(callback));
300
301        self.device_manager.pin_mut().add_audio_callback(&callback);
302        let key = self.callbacks.insert(callback);
303
304        AudioCallbackHandle { key }
305    }
306
307    /// Removes an audio callback.
308    pub fn remove_audio_callback(&mut self, handle: AudioCallbackHandle) {
309        if let Some(callback) = self.callbacks.remove(handle.key) {
310            self.device_manager
311                .pin_mut()
312                .remove_audio_callback(&callback);
313        }
314    }
315
316    /// Registers an audio device type.
317    pub fn add_audio_device_type(&mut self, device_type: impl AudioIODeviceType + 'static) {
318        let device_type = Box::new(device_type);
319        self.device_manager
320            .pin_mut()
321            .add_audio_device_type(Box::new(device_type));
322    }
323
324    /// Set the current audio device type to use.
325    pub fn set_current_audio_device_type(&mut self, device_type: &str) {
326        self.device_manager
327            .pin_mut()
328            .set_current_audio_device_type(device_type);
329    }
330}
331
332/// A trait that can be implemented to receive audio callbacks.
333///
334/// Types that implement this trait can be registered with [`AudioDeviceManager::add_audio_callback`].
335///
336/// This trait requires that implementors are [`Send`] because the callbacks will occur on the audio thread.
337pub trait AudioIODeviceCallback: Send {
338    /// Called when the audio device is about to start.
339    fn about_to_start(&mut self, device: &mut dyn AudioIODevice);
340
341    /// Process a block of incoming and outgoing audio.
342    fn process_block(
343        &mut self,
344        input: &InputAudioSampleBuffer<'_>,
345        output: &mut OutputAudioSampleBuffer<'_>,
346    );
347
348    /// Called when the audio device has stopped.
349    fn stopped(&mut self);
350}
351
352pub(crate) type BoxedAudioIODeviceCallback = Box<dyn AudioIODeviceCallback>;
353pub(crate) type BoxedAudioIODeviceType = Box<dyn AudioIODeviceType>;
354pub(crate) type BoxedAudioIODevice = Box<dyn AudioIODevice>;
355
356/// A handle to a registered audio callback.
357#[must_use]
358pub struct AudioCallbackHandle {
359    key: AudioCallbackKey,
360}
361
362/// A trait representing a type of audio driver (e.g. CoreAudio, ASIO, etc.).
363pub trait AudioIODeviceType {
364    /// The name of the type of driver.
365    fn name(&self) -> String;
366
367    /// Refreshes the drivers cached list of known devices.
368    fn scan_for_devices(&mut self);
369
370    /// Returns a list of known input devices.
371    fn input_devices(&self) -> Vec<String>;
372
373    /// Returns a list of the known output devices.
374    fn output_devices(&self) -> Vec<String>;
375
376    /// Create an [`AudioIODevice`].
377    fn create_device(
378        &mut self,
379        input_device_name: &str,
380        output_device_name: &str,
381    ) -> Option<Box<dyn AudioIODevice>>;
382}
383
384impl AudioIODeviceType for *mut juce::AudioIODeviceType {
385    fn name(&self) -> String {
386        if self.is_null() {
387            return String::default();
388        }
389
390        let this = unsafe { &*self.cast_const() };
391        juce::get_type_name(this)
392    }
393
394    fn scan_for_devices(&mut self) {
395        if let Some(this) = unsafe { self.as_mut().map(|ptr| Pin::new_unchecked(ptr)) } {
396            this.scan_for_devices();
397        }
398    }
399
400    fn input_devices(&self) -> Vec<String> {
401        if self.is_null() {
402            return vec![];
403        }
404
405        let this = unsafe { &*self.cast_const() };
406        juce::get_input_device_names(this)
407    }
408
409    fn output_devices(&self) -> Vec<String> {
410        if self.is_null() {
411            return vec![];
412        }
413
414        let this = unsafe { &*self.cast_const() };
415        juce::get_output_device_names(this)
416    }
417
418    fn create_device(
419        &mut self,
420        input_device_name: &str,
421        output_device_name: &str,
422    ) -> Option<Box<dyn AudioIODevice>> {
423        unsafe { self.as_mut().map(|ptr| Pin::new_unchecked(ptr)) }
424            .map(|this| juce::new_device(this, input_device_name, output_device_name))
425            .filter(|device| !device.is_null())
426            .map(|device| Box::new(device) as _)
427    }
428}
429
430/// A trait representing an audio device.
431pub trait AudioIODevice {
432    /// The name of the device.
433    fn name(&self) -> &str;
434
435    /// The type of the device.
436    fn type_name(&self) -> &str;
437
438    /// The current sample rate.
439    fn sample_rate(&mut self) -> f64;
440
441    /// The current buffer size.
442    fn buffer_size(&mut self) -> usize;
443
444    /// The available sample rates.
445    fn available_sample_rates(&mut self) -> Vec<f64>;
446
447    /// The available buffer sizes.
448    fn available_buffer_sizes(&mut self) -> Vec<usize>;
449
450    /// Tries to open the device so that it can be used for audio processing.
451    fn open(&mut self, sample_rate: f64, buffer_size: usize) -> Result<()>;
452
453    /// Close the device.
454    fn close(&mut self);
455
456    /// The number of input channels.
457    fn input_channels(&self) -> i32;
458
459    /// The number of output channels.
460    fn output_channels(&self) -> i32;
461}
462
463impl AudioIODevice for *mut juce::AudioIODevice {
464    fn name(&self) -> &str {
465        unsafe { self.as_ref() }
466            .map(juce::get_device_name)
467            .unwrap_or_default()
468    }
469
470    fn type_name(&self) -> &str {
471        unsafe { self.as_ref() }
472            .map(juce::get_device_type_name)
473            .unwrap_or_default()
474    }
475
476    fn sample_rate(&mut self) -> f64 {
477        unsafe { self.as_mut().map(|this| Pin::new_unchecked(this)) }
478            .map(|this| this.get_current_sample_rate())
479            .unwrap_or_default()
480    }
481
482    fn buffer_size(&mut self) -> usize {
483        unsafe { self.as_mut().map(|this| Pin::new_unchecked(this)) }
484            .map(|this| this.get_current_buffer_size_samples() as usize)
485            .unwrap_or_default()
486    }
487
488    fn available_sample_rates(&mut self) -> Vec<f64> {
489        unsafe { self.as_mut().map(|this| Pin::new_unchecked(this)) }
490            .map(juce::get_available_sample_rates)
491            .unwrap_or_default()
492    }
493
494    fn available_buffer_sizes(&mut self) -> Vec<usize> {
495        unsafe { self.as_mut().map(|this| Pin::new_unchecked(this)) }
496            .map(juce::get_available_buffer_sizes)
497            .unwrap_or_default()
498    }
499
500    fn open(&mut self, sample_rate: f64, buffer_size: usize) -> Result<()> {
501        if let Some(this) = unsafe { self.as_mut().map(|this| Pin::new_unchecked(this)) } {
502            juce::open(this, sample_rate, buffer_size)?;
503        }
504
505        Ok(())
506    }
507
508    fn close(&mut self) {
509        if let Some(this) = unsafe { self.as_mut().map(|this| Pin::new_unchecked(this)) } {
510            this.close();
511        }
512    }
513
514    fn input_channels(&self) -> i32 {
515        unsafe { self.as_ref() }
516            .map(juce::count_active_input_channels)
517            .unwrap_or_default()
518    }
519
520    fn output_channels(&self) -> i32 {
521        unsafe { self.as_ref() }
522            .map(juce::count_active_output_channels)
523            .unwrap_or_default()
524    }
525}
526
527impl AudioIODevice for Pin<&mut juce::AudioIODevice> {
528    fn name(&self) -> &str {
529        juce::get_device_name(self)
530    }
531
532    fn type_name(&self) -> &str {
533        juce::get_device_type_name(self)
534    }
535
536    fn sample_rate(&mut self) -> f64 {
537        juce::AudioIODevice::get_current_sample_rate(self.as_mut())
538    }
539
540    fn buffer_size(&mut self) -> usize {
541        juce::AudioIODevice::get_current_buffer_size_samples(self.as_mut()) as usize
542    }
543
544    fn available_sample_rates(&mut self) -> Vec<f64> {
545        juce::get_available_sample_rates(self.as_mut())
546    }
547
548    fn available_buffer_sizes(&mut self) -> Vec<usize> {
549        juce::get_available_buffer_sizes(self.as_mut())
550    }
551
552    fn open(&mut self, sample_rate: f64, buffer_size: usize) -> Result<()> {
553        juce::open(self.as_mut(), sample_rate, buffer_size)
554    }
555
556    fn close(&mut self) {
557        juce::AudioIODevice::close(self.as_mut());
558    }
559
560    fn input_channels(&self) -> i32 {
561        juce::count_active_input_channels(self)
562    }
563
564    fn output_channels(&self) -> i32 {
565        juce::count_active_output_channels(self)
566    }
567}
568
569impl AudioIODevice for cxx::UniquePtr<juce::AudioIODevice> {
570    fn name(&self) -> &str {
571        self.as_ref().map(juce::get_device_name).unwrap_or_default()
572    }
573
574    fn type_name(&self) -> &str {
575        self.as_ref()
576            .map(juce::get_device_type_name)
577            .unwrap_or_default()
578    }
579
580    fn sample_rate(&mut self) -> f64 {
581        self.as_mut()
582            .map(|this| this.get_current_sample_rate())
583            .unwrap_or_default()
584    }
585
586    fn buffer_size(&mut self) -> usize {
587        self.as_mut()
588            .map(|this| this.get_current_buffer_size_samples() as usize)
589            .unwrap_or_default()
590    }
591
592    fn available_sample_rates(&mut self) -> Vec<f64> {
593        self.as_mut()
594            .map(juce::get_available_sample_rates)
595            .unwrap_or_default()
596    }
597
598    fn available_buffer_sizes(&mut self) -> Vec<usize> {
599        self.as_mut()
600            .map(juce::get_available_buffer_sizes)
601            .unwrap_or_default()
602    }
603
604    fn open(&mut self, sample_rate: f64, buffer_size: usize) -> Result<()> {
605        if let Some(this) = self.as_mut() {
606            juce::open(this, sample_rate, buffer_size)?;
607        }
608
609        Ok(())
610    }
611
612    fn close(&mut self) {
613        if let Some(this) = self.as_mut() {
614            this.close();
615        }
616    }
617
618    fn input_channels(&self) -> i32 {
619        self.as_ref()
620            .map(juce::count_active_input_channels)
621            .unwrap_or_default()
622    }
623
624    fn output_channels(&self) -> i32 {
625        self.as_ref()
626            .map(juce::count_active_output_channels)
627            .unwrap_or_default()
628    }
629}
630
631pub(crate) mod ffi {
632    use super::*;
633
634    pub mod audio_io_device_callback {
635        use super::*;
636
637        pub fn about_to_start(
638            mut self_: Pin<&mut BoxedAudioIODeviceCallback>,
639            mut device: Pin<&mut juce::AudioIODevice>,
640        ) {
641            self_.about_to_start(&mut device.as_mut());
642        }
643
644        pub fn process_block(
645            mut self_: Pin<&mut BoxedAudioIODeviceCallback>,
646            input: &juce::AudioSampleBuffer,
647            output: Pin<&mut juce::AudioSampleBuffer>,
648        ) {
649            let input = InputAudioSampleBuffer::new(input);
650            let mut output = OutputAudioSampleBuffer::new(output);
651
652            self_.process_block(&input, &mut output);
653        }
654
655        pub fn stopped(mut self_: Pin<&mut BoxedAudioIODeviceCallback>) {
656            self_.stopped()
657        }
658    }
659
660    pub mod audio_io_device_type {
661        use {super::*, std::ptr::null_mut};
662
663        pub fn name(self_: &BoxedAudioIODeviceType) -> String {
664            self_.name()
665        }
666
667        pub fn scan_for_devices(mut self_: Pin<&mut BoxedAudioIODeviceType>) {
668            self_.scan_for_devices()
669        }
670
671        pub fn get_device_names(self_: &BoxedAudioIODeviceType, input: bool) -> Vec<String> {
672            if input {
673                self_.input_devices()
674            } else {
675                self_.output_devices()
676            }
677        }
678
679        pub fn create_device(
680            mut self_: Pin<&mut BoxedAudioIODeviceType>,
681            input_name: &str,
682            output_name: &str,
683        ) -> *mut BoxedAudioIODevice {
684            let device = self_.as_mut().create_device(input_name, output_name);
685
686            device
687                .map(|device| Box::into_raw(Box::new(device)))
688                .unwrap_or(null_mut())
689        }
690
691        pub fn destroy_device(device: *mut BoxedAudioIODevice) {
692            if device.is_null() {
693                return;
694            }
695
696            let _ = unsafe { Box::from_raw(device) };
697        }
698    }
699
700    pub mod audio_io_device {
701        use super::*;
702
703        pub fn device_name(self_: &BoxedAudioIODevice) -> String {
704            self_.name().to_string()
705        }
706
707        pub fn device_type_name(self_: &BoxedAudioIODevice) -> String {
708            self_.type_name().to_string()
709        }
710
711        pub fn device_sample_rate(mut self_: Pin<&mut BoxedAudioIODevice>) -> f64 {
712            self_.sample_rate()
713        }
714
715        pub fn device_buffer_size(mut self_: Pin<&mut BoxedAudioIODevice>) -> usize {
716            self_.buffer_size()
717        }
718
719        pub fn device_available_sample_rates(mut self_: Pin<&mut BoxedAudioIODevice>) -> Vec<f64> {
720            self_.available_sample_rates()
721        }
722
723        pub fn device_available_buffer_sizes(
724            mut self_: Pin<&mut BoxedAudioIODevice>,
725        ) -> Vec<usize> {
726            self_.available_buffer_sizes()
727        }
728
729        pub fn device_open(
730            mut self_: Pin<&mut BoxedAudioIODevice>,
731            sample_rate: f64,
732            buffer_size: usize,
733        ) -> String {
734            match self_.open(sample_rate, buffer_size) {
735                Ok(()) => String::default(),
736                Err(error) => error.to_string(),
737            }
738        }
739
740        pub fn device_close(mut self_: Pin<&mut BoxedAudioIODevice>) {
741            self_.close()
742        }
743    }
744}
745
746/// Controls for the system volume.
747pub struct SystemAudioVolume;
748
749impl SystemAudioVolume {
750    /// Get the current system volume.
751    pub fn get_gain() -> f32 {
752        juce::get_gain()
753    }
754
755    /// Set the system volume.
756    pub fn set_gain(gain: f32) {
757        juce::set_gain(gain.clamp(0.0, 1.0))
758    }
759
760    /// Returns true if the system audio output is muted.
761    pub fn is_muted() -> bool {
762        juce::is_muted()
763    }
764
765    /// Mute the system audio output.
766    pub fn mute() {
767        juce::set_muted(true);
768    }
769
770    /// Unmute the system audio output.
771    pub fn unmute() {
772        juce::set_muted(false);
773    }
774}