1pub mod juce_audio_basics;
4pub mod juce_audio_devices;
5
6use {
7 juce_audio_devices::{
8 ffi::{
9 audio_io_device::{
10 device_available_buffer_sizes, device_available_sample_rates, device_buffer_size,
11 device_close, device_name, device_open, device_sample_rate, device_type_name,
12 },
13 audio_io_device_callback::{about_to_start, process_block, stopped},
14 audio_io_device_type::{
15 create_device, destroy_device, get_device_names, name, scan_for_devices,
16 },
17 },
18 BoxedAudioIODevice, BoxedAudioIODeviceCallback, BoxedAudioIODeviceType,
19 },
20 std::{
21 rc::Rc,
22 sync::atomic::{AtomicBool, Ordering},
23 },
24};
25
26pub fn juce_version() -> String {
28 juce::version()
29}
30
31#[must_use]
35#[derive(Clone)]
36pub struct JUCE {
37 _app: Rc<JuceApp>,
38}
39
40static IS_JUCE_RUNNING: AtomicBool = AtomicBool::new(false);
41
42struct JuceApp;
43
44impl JuceApp {
45 fn new() -> Self {
46 juce::initialise_juce();
47
48 #[cfg(target_os = "macos")]
49 juce::initialise_ns_application();
50
51 Self
52 }
53}
54
55impl Drop for JuceApp {
56 fn drop(&mut self) {
57 juce::shutdown_juce();
58
59 IS_JUCE_RUNNING.store(false, Ordering::SeqCst);
60 }
61}
62
63#[derive(Debug)]
64enum InitialiseError {
65 JuceAlreadyInitialised,
66}
67
68impl std::error::Error for InitialiseError {}
69
70impl std::fmt::Display for InitialiseError {
71 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
72 match self {
73 Self::JuceAlreadyInitialised => write!(f, "JUCE has already been initialised"),
74 }
75 }
76}
77
78impl JUCE {
79 pub fn initialise() -> Self {
85 Self::try_initialise().unwrap()
86 }
87
88 fn try_initialise() -> std::result::Result<Self, InitialiseError> {
89 let result =
90 IS_JUCE_RUNNING.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst);
91
92 if result.is_err() {
93 return Err(InitialiseError::JuceAlreadyInitialised);
94 }
95
96 Ok(Self {
97 _app: Rc::new(JuceApp::new()),
98 })
99 }
100}
101
102pub type Exception = cxx::Exception;
103pub type Result<T> = std::result::Result<T, Exception>;
104
105#[cxx::bridge(namespace = "cxx_juce")]
106pub(crate) mod juce {
107 extern "Rust" {
108 type BoxedAudioIODeviceCallback;
109
110 #[namespace = "audio_io_device_callback"]
111 #[cxx_name = "aboutToStart"]
112 fn about_to_start(
113 callback: Pin<&mut BoxedAudioIODeviceCallback>,
114 device: Pin<&mut AudioIODevice>,
115 );
116
117 #[namespace = "audio_io_device_callback"]
118 #[cxx_name = "processBlock"]
119 fn process_block(
120 callback: Pin<&mut BoxedAudioIODeviceCallback>,
121 input: &AudioSampleBuffer,
122 output: Pin<&mut AudioSampleBuffer>,
123 );
124
125 #[namespace = "audio_io_device_callback"]
126 #[cxx_name = "stopped"]
127 fn stopped(callback: Pin<&mut BoxedAudioIODeviceCallback>);
128
129 type BoxedAudioIODeviceType;
130
131 #[namespace = "audio_io_device_type"]
132 #[cxx_name = "name"]
133 fn name(self_: &BoxedAudioIODeviceType) -> String;
134
135 #[namespace = "audio_io_device_type"]
136 #[cxx_name = "scanForDevices"]
137 fn scan_for_devices(self_: Pin<&mut BoxedAudioIODeviceType>);
138
139 #[namespace = "audio_io_device_type"]
140 #[cxx_name = "getDeviceNames"]
141 fn get_device_names(self_: &BoxedAudioIODeviceType, input: bool) -> Vec<String>;
142
143 #[namespace = "audio_io_device_type"]
144 #[cxx_name = "createDevice"]
145 fn create_device(
146 self_: Pin<&mut BoxedAudioIODeviceType>,
147 input_device_name: &str,
148 output_device_name: &str,
149 ) -> *mut BoxedAudioIODevice;
150
151 #[namespace = "audio_io_device_type"]
152 #[cxx_name = "destroyDevice"]
153 unsafe fn destroy_device(self_: *mut BoxedAudioIODevice);
154
155 type BoxedAudioIODevice;
156
157 #[namespace = "audio_io_device"]
158 #[cxx_name = "deviceName"]
159 pub fn device_name(self_: &BoxedAudioIODevice) -> String;
160
161 #[namespace = "audio_io_device"]
162 #[cxx_name = "typeName"]
163 pub fn device_type_name(self_: &BoxedAudioIODevice) -> String;
164
165 #[namespace = "audio_io_device"]
166 #[cxx_name = "sampleRate"]
167 pub fn device_sample_rate(self_: Pin<&mut BoxedAudioIODevice>) -> f64;
168
169 #[namespace = "audio_io_device"]
170 #[cxx_name = "bufferSize"]
171 pub fn device_buffer_size(self_: Pin<&mut BoxedAudioIODevice>) -> usize;
172
173 #[namespace = "audio_io_device"]
174 #[cxx_name = "availableSampleRates"]
175 pub fn device_available_sample_rates(self_: Pin<&mut BoxedAudioIODevice>) -> Vec<f64>;
176
177 #[namespace = "audio_io_device"]
178 #[cxx_name = "availableBufferSizes"]
179 pub fn device_available_buffer_sizes(self_: Pin<&mut BoxedAudioIODevice>) -> Vec<usize>;
180
181 #[namespace = "audio_io_device"]
182 #[cxx_name = "open"]
183 pub fn device_open(
184 self_: Pin<&mut BoxedAudioIODevice>,
185 sample_rate: f64,
186 buffer_size: usize,
187 ) -> String;
188
189 #[namespace = "audio_io_device"]
190 #[cxx_name = "close"]
191 pub fn device_close(self_: Pin<&mut BoxedAudioIODevice>);
192 }
193
194 unsafe extern "C++" {
195 include!("cxx-juce/bridge/cxx_juce.h");
196
197 #[rust_name = "version"]
198 pub fn juceVersion() -> String;
199
200 #[rust_name = "initialise_juce"]
201 pub fn initialiseJuce();
202
203 #[rust_name = "shutdown_juce"]
204 pub fn shutdownJuce();
205
206 #[cfg(target_os = "macos")]
207 #[namespace = "juce"]
208 #[rust_name = "initialise_ns_application"]
209 pub fn initialiseNSApplication();
210
211 #[namespace = "juce"]
212 pub type AudioIODeviceTypeArray;
213
214 pub fn size(self: &AudioIODeviceTypeArray) -> i32;
215
216 #[rust_name = "get_unchecked"]
217 pub fn getUnchecked(self: &AudioIODeviceTypeArray, index: i32) -> *mut AudioIODeviceType;
218
219 pub type AudioDeviceSetup;
220
221 #[rust_name = "create_audio_device_setup"]
222 pub fn createAudioDeviceSetup() -> UniquePtr<AudioDeviceSetup>;
223
224 #[rust_name = "output_device_name"]
225 pub fn outputDeviceName(self: &AudioDeviceSetup) -> &str;
226
227 #[rust_name = "input_device_name"]
228 pub fn inputDeviceName(self: &AudioDeviceSetup) -> &str;
229
230 #[rust_name = "sample_rate"]
231 pub fn sampleRate(self: &AudioDeviceSetup) -> f64;
232
233 #[rust_name = "buffer_size"]
234 pub fn bufferSize(self: &AudioDeviceSetup) -> i32;
235
236 #[rust_name = "set_output_device_name"]
237 pub fn setOutputDeviceName(self: Pin<&mut AudioDeviceSetup>, name: &str);
238
239 #[rust_name = "set_input_device_name"]
240 pub fn setInputDeviceName(self: Pin<&mut AudioDeviceSetup>, name: &str);
241
242 #[rust_name = "set_sample_rate"]
243 pub fn setSampleRate(self: Pin<&mut AudioDeviceSetup>, sample_rate: f64);
244
245 #[rust_name = "set_buffer_size"]
246 pub fn setBufferSize(self: Pin<&mut AudioDeviceSetup>, buffer_size: i32);
247
248 #[rust_name = "number_of_input_channels"]
249 pub fn numberOfInputChannels(self: &AudioDeviceSetup) -> i32;
250
251 #[rust_name = "set_number_of_input_channels"]
252 pub fn setNumberOfInputChannels(
253 self: Pin<&mut AudioDeviceSetup>,
254 number_of_input_channels: i32,
255 );
256
257 #[rust_name = "use_default_input_channels"]
258 pub fn useDefaultInputChannels(self: Pin<&mut AudioDeviceSetup>, use_default: bool);
259
260 #[rust_name = "using_default_input_channels"]
261 pub fn usingDefaultInputChannels(self: &AudioDeviceSetup) -> bool;
262
263 #[rust_name = "number_of_output_channels"]
264 pub fn numberOfOutputChannels(self: &AudioDeviceSetup) -> i32;
265
266 #[rust_name = "set_number_of_output_channels"]
267 pub fn setNumberOfOutputChannels(
268 self: Pin<&mut AudioDeviceSetup>,
269 number_of_output_channels: i32,
270 );
271
272 #[rust_name = "use_default_output_channels"]
273 pub fn useDefaultOutputChannels(self: Pin<&mut AudioDeviceSetup>, use_default: bool);
274
275 #[rust_name = "using_default_output_channels"]
276 pub fn usingDefaultOutputChannels(self: &AudioDeviceSetup) -> bool;
277
278 pub type AudioDeviceManager;
279
280 #[rust_name = "create_audio_device_manager"]
281 pub fn createAudioDeviceManager() -> UniquePtr<AudioDeviceManager>;
282
283 #[rust_name = "wrap_audio_callback"]
284 pub fn wrapAudioCallback(
285 callback: Box<BoxedAudioIODeviceCallback>,
286 ) -> UniquePtr<AudioCallbackWrapper>;
287
288 #[rust_name = "initialise_with_default_devices"]
289 pub fn initialiseWithDefaultDevices(
290 self: Pin<&mut AudioDeviceManager>,
291 num_input_channels: i32,
292 num_output_channels: i32,
293 ) -> Result<()>;
294
295 #[rust_name = "get_audio_device_setup"]
296 pub fn getAudioDeviceSetup(self: &AudioDeviceManager) -> UniquePtr<AudioDeviceSetup>;
297
298 #[rust_name = "set_audio_device_setup"]
299 pub fn setAudioDeviceSetup(self: Pin<&mut AudioDeviceManager>, setup: &AudioDeviceSetup);
300
301 #[rust_name = "get_current_audio_device"]
302 pub fn getCurrentAudioDevice(self: &AudioDeviceManager) -> *mut AudioIODevice;
303
304 #[rust_name = "get_available_device_types"]
305 pub fn getAvailableDeviceTypes(
306 self: Pin<&mut AudioDeviceManager>,
307 ) -> &AudioIODeviceTypeArray;
308
309 #[rust_name = "get_current_device_type_object"]
310 pub fn getCurrentDeviceTypeObject(self: &AudioDeviceManager) -> *mut AudioIODeviceType;
311
312 #[rust_name = "play_test_sound"]
313 pub fn playTestSound(self: Pin<&mut AudioDeviceManager>);
314
315 #[rust_name = "add_audio_callback"]
316 pub fn addAudioCallback(
317 self: Pin<&mut AudioDeviceManager>,
318 callback: &UniquePtr<AudioCallbackWrapper>,
319 );
320
321 #[rust_name = "remove_audio_callback"]
322 pub fn removeAudioCallback(
323 self: Pin<&mut AudioDeviceManager>,
324 callback: &UniquePtr<AudioCallbackWrapper>,
325 );
326
327 #[rust_name = "add_audio_device_type"]
328 pub fn addAudioDeviceType(
329 self: Pin<&mut AudioDeviceManager>,
330 device_type: Box<BoxedAudioIODeviceType>,
331 );
332
333 #[rust_name = "set_current_audio_device_type"]
334 pub fn setCurrentAudioDeviceType(self: Pin<&mut AudioDeviceManager>, device_type: &str);
335
336 #[namespace = "juce"]
337 pub type AudioIODevice;
338
339 #[namespace = "cxx_juce::audio_io_device"]
340 #[rust_name = "get_device_name"]
341 pub fn getDeviceName(self_: &AudioIODevice) -> &str;
342
343 #[namespace = "cxx_juce::audio_io_device"]
344 #[rust_name = "get_device_type_name"]
345 pub fn getDeviceTypeName(self_: &AudioIODevice) -> &str;
346
347 #[rust_name = "get_current_sample_rate"]
348 pub fn getCurrentSampleRate(self: Pin<&mut AudioIODevice>) -> f64;
349
350 #[rust_name = "get_current_buffer_size_samples"]
351 pub fn getCurrentBufferSizeSamples(self: Pin<&mut AudioIODevice>) -> i32;
352
353 #[namespace = "cxx_juce::audio_io_device"]
354 #[rust_name = "get_available_sample_rates"]
355 pub fn getAvailableSampleRates(self_: Pin<&mut AudioIODevice>) -> Vec<f64>;
356
357 #[namespace = "cxx_juce::audio_io_device"]
358 #[rust_name = "get_available_buffer_sizes"]
359 pub fn getAvailableBufferSizes(self_: Pin<&mut AudioIODevice>) -> Vec<usize>;
360
361 #[namespace = "cxx_juce::audio_io_device"]
362 #[rust_name = "open"]
363 pub fn open(
364 self_: Pin<&mut AudioIODevice>,
365 sample_rate: f64,
366 buffer_size: usize,
367 ) -> Result<()>;
368
369 #[rust_name = "close"]
370 pub fn close(self: Pin<&mut AudioIODevice>);
371
372 #[namespace = "cxx_juce::audio_io_device"]
373 #[rust_name = "count_active_input_channels"]
374 pub fn countActiveInputChannels(self_: &AudioIODevice) -> i32;
375
376 #[namespace = "cxx_juce::audio_io_device"]
377 #[rust_name = "count_active_output_channels"]
378 pub fn countActiveOutputChannels(self_: &AudioIODevice) -> i32;
379
380 #[namespace = "juce"]
381 pub type AudioIODeviceType;
382
383 #[namespace = "cxx_juce::audio_io_device_type"]
384 #[rust_name = "get_type_name"]
385 pub fn getTypeName(self_: &AudioIODeviceType) -> String;
386
387 #[rust_name = "scan_for_devices"]
388 pub fn scanForDevices(self: Pin<&mut AudioIODeviceType>);
389
390 #[namespace = "cxx_juce::audio_io_device_type"]
391 #[rust_name = "get_input_device_names"]
392 pub fn getInputDeviceNames(self_: &AudioIODeviceType) -> Vec<String>;
393
394 #[namespace = "cxx_juce::audio_io_device_type"]
395 #[rust_name = "get_output_device_names"]
396 pub fn getOutputDeviceNames(self_: &AudioIODeviceType) -> Vec<String>;
397
398 #[namespace = "cxx_juce::audio_io_device_type"]
399 #[rust_name = "new_device"]
400 pub fn createDevice(
401 self_: Pin<&mut AudioIODeviceType>,
402 input_device_name: &str,
403 output_device_name: &str,
404 ) -> UniquePtr<AudioIODevice>;
405
406 #[namespace = "juce"]
407 pub type AudioSampleBuffer;
408
409 #[rust_name = "get_num_channels"]
410 pub fn getNumChannels(self: &AudioSampleBuffer) -> i32;
411
412 #[rust_name = "get_num_samples"]
413 pub fn getNumSamples(self: &AudioSampleBuffer) -> i32;
414
415 #[rust_name = "get_read_pointer"]
416 pub fn getReadPointer(self: &AudioSampleBuffer, channel: i32) -> *const f32;
417
418 #[rust_name = "get_write_pointer"]
419 pub fn getWritePointer(self: Pin<&mut AudioSampleBuffer>, channel: i32) -> *mut f32;
420
421 #[rust_name = "clear"]
422 pub fn clear(self: Pin<&mut AudioSampleBuffer>);
423
424 pub type AudioCallbackWrapper;
425
426 #[namespace = "cxx_juce::system_audio_volume"]
427 #[rust_name = "set_muted"]
428 pub fn setMuted(muted: bool);
429
430 #[namespace = "cxx_juce::system_audio_volume"]
431 #[rust_name = "is_muted"]
432 pub fn isMuted() -> bool;
433
434 #[namespace = "cxx_juce::system_audio_volume"]
435 #[rust_name = "set_gain"]
436 pub fn setGain(gain: f32);
437
438 #[namespace = "cxx_juce::system_audio_volume"]
439 #[rust_name = "get_gain"]
440 pub fn getGain() -> f32;
441
442 #[namespace = "juce"]
443 pub type SingleThreadedIIRFilter;
444
445 #[namespace = "cxx_juce::iir_filter"]
446 #[rust_name = "create_iir_filter"]
447 pub fn createIIRFilter(coefficients: [f32; 5]) -> UniquePtr<SingleThreadedIIRFilter>;
448
449 #[namespace = "juce"]
450 #[rust_name = "process_samples"]
451 pub unsafe fn processSamples(
452 self: Pin<&mut SingleThreadedIIRFilter>,
453 samples: *mut f32,
454 num_samples: i32,
455 );
456
457 #[namespace = "cxx_juce::iir_filter"]
458 #[rust_name = "make_low_pass"]
459 pub fn makeLowPass(sample_rate: f64, frequency: f64, q: f64) -> [f32; 5];
460
461 #[namespace = "cxx_juce::iir_filter"]
462 #[rust_name = "make_high_pass"]
463 pub fn makeHighPass(sample_rate: f64, frequency: f64, q: f64) -> [f32; 5];
464
465 #[namespace = "cxx_juce::iir_filter"]
466 #[rust_name = "make_notch_filter"]
467 pub fn makeNotchFilter(sample_rate: f64, frequency: f64, q: f64) -> [f32; 5];
468 }
469}
470
471#[cfg(test)]
472mod test {
473 use super::*;
474
475 fn try_to_initialise_juce_on_new_thread() -> std::thread::Result<()> {
476 std::thread::spawn(move || {
477 let _juce = JUCE::initialise();
478 })
479 .join()
480 }
481
482 #[test]
483 #[should_panic]
484 fn initialising_juce_twice_on_the_same_thread_should_panic() {
485 let _juce = JUCE::initialise();
486 let _juce = JUCE::initialise();
487 }
488
489 #[test]
490 fn initialising_juce_again_on_the_same_thread_after_shutdown_is_ok() {
491 let juce = JUCE::initialise();
492 drop(juce);
493
494 let _juce = JUCE::initialise();
495 }
496
497 #[test]
498 fn juce_cant_be_initialised_simultaneously_on_two_different_threads() {
499 let _juce = JUCE::initialise();
500
501 assert!(try_to_initialise_juce_on_new_thread().is_err());
502 }
503
504 #[test]
505 fn juce_can_run_on_a_different_thread_after_finishing_on_another() {
506 let juce = JUCE::initialise();
507 drop(juce);
508
509 assert!(try_to_initialise_juce_on_new_thread().is_ok());
510 }
511
512 #[test]
513 fn juce_is_shutdown_once_all_references_have_been_dropped() {
514 let a = JUCE::initialise();
515 let b = a.clone();
516
517 drop(a);
518
519 assert!(try_to_initialise_juce_on_new_thread().is_err());
520
521 drop(b);
522
523 assert!(try_to_initialise_juce_on_new_thread().is_ok());
524 }
525}