use rack::prelude::*;
use std::sync::{Arc, Mutex};
use std::time::Duration;
#[link(name = "CoreFoundation", kind = "framework")]
extern "C" {
fn CFRunLoopRunInMode(
mode: CFRunLoopMode,
seconds: f64,
return_after_source_handled: bool,
) -> i32;
static kCFRunLoopDefaultMode: CFRunLoopMode;
}
type CFRunLoopMode = *const std::ffi::c_void;
fn process_main_event_loop(duration_ms: u64) {
unsafe {
CFRunLoopRunInMode(
kCFRunLoopDefaultMode,
duration_ms as f64 / 1000.0,
false,
);
}
}
fn run_event_loop() {
println!("Starting event loop...");
loop {
unsafe {
CFRunLoopRunInMode(
kCFRunLoopDefaultMode,
1.0,
true, );
}
std::thread::sleep(Duration::from_millis(10));
}
}
fn main() -> Result<()> {
println!("AudioUnit Plugin GUI Example");
println!("=============================\n");
println!("Creating scanner...");
let scanner = Scanner::new()?;
println!("Scanning for AudioUnit plugins...");
let plugins = scanner.scan()?;
if plugins.is_empty() {
println!("No plugins found!");
return Ok(());
}
println!("Found {} plugin(s)\n", plugins.len());
let plugin_info = plugins
.iter()
.find(|p| {
p.plugin_type == PluginType::Instrument
})
.or_else(|| {
plugins.iter().find(|p| {
p.plugin_type == PluginType::Effect && !p.name.contains("Bandpass")
})
})
.or_else(|| plugins.first());
let Some(info) = plugin_info else {
println!("No suitable plugin found");
return Ok(());
};
println!("Selected plugin:");
println!(" Name: {}", info.name);
println!(" Manufacturer: {}", info.manufacturer);
println!(" Type: {:?}", info.plugin_type);
println!();
println!("Creating plugin instance...");
let mut plugin = scanner.load(info)?;
println!("✓ Plugin instance created");
println!("Initializing plugin (48kHz, 512 samples)...");
plugin.initialize(48000.0, 512)?;
println!("✓ Plugin initialized successfully!\n");
println!("Creating plugin GUI...");
println!("This may take a moment as we try AUv3 → AUv2 → generic UI...\n");
let gui_handle: Arc<Mutex<Option<AudioUnitGui>>> = Arc::new(Mutex::new(None));
let gui_clone = gui_handle.clone();
let plugin_name = info.name.clone();
plugin.create_gui(move |result| {
match result {
Ok(gui) => {
println!("✓ GUI created successfully!");
if let Ok((width, height)) = gui.get_size() {
println!(" GUI size: {:.0}x{:.0} points", width, height);
}
if let Some(view_ptr) = gui.get_native_view() {
println!(" NSView pointer: {:?}", view_ptr);
}
println!("\nShowing plugin window...");
if let Err(e) = gui.show_window(Some(&plugin_name)) {
eprintln!("Failed to show window: {}", e);
return Err(e);
}
println!("✓ Window is now visible!");
println!("\nThe plugin GUI window should now be visible.");
println!("Close the window or press Ctrl+C to exit.\n");
*gui_clone.lock().unwrap() = Some(gui);
}
Err(e) => {
eprintln!("✗ GUI creation failed: {}", e);
return Err(e);
}
}
Ok(())
});
println!("GUI creation initiated...");
println!("Waiting for window to be created and displayed...\n");
println!("Processing events...");
for _ in 0..30 {
process_main_event_loop(100);
let gui = gui_handle.lock().unwrap();
if gui.is_some() {
println!("\n✓ GUI window should now be visible!");
println!("The window will stay open. Press Ctrl+C to exit.\n");
drop(gui);
break;
}
}
{
let gui = gui_handle.lock().unwrap();
if gui.is_none() {
println!("Timeout waiting for GUI creation");
return Ok(());
}
}
println!("Running event loop (window is now interactive)...");
run_event_loop();
println!("\nCleaning up...");
{
let mut gui = gui_handle.lock().unwrap();
*gui = None;
}
println!("✓ Example complete!");
Ok(())
}