nice-plug-au2 0.1.1

Audio Unit (AU2) support for nice-plug
Documentation
use std::ffi::c_void;

use objc2::MainThreadMarker;
use objc2::rc::Retained;
use objc2_app_kit::NSView;
use objc2_audio_toolbox::AudioUnit;
use objc2_foundation::{NSPoint, NSRect, NSSize};

use super::editor::EditorView;
use crate::bridge::nice_au2_get_editor_size;

const NICE_AU2_PROPERTY_RUST_INSTANCE: u32 = 0x4E41_7269;
const AUDIO_UNIT_SCOPE_GLOBAL: u32 = 0;

unsafe extern "C" {
    fn AudioUnitGetProperty(
        audio_unit: AudioUnit,
        property: u32,
        scope: u32,
        element: u32,
        data: *mut c_void,
        size: *mut u32,
    ) -> i32;
}

pub(super) fn create_view(audio_unit: AudioUnit) -> *mut NSView {
    let Some(mtm) = MainThreadMarker::new() else {
        return std::ptr::null_mut();
    };
    let Some(view) = make_view(mtm, audio_unit) else {
        return std::ptr::null_mut();
    };
    Retained::autorelease_ptr(view)
}

fn make_view(mtm: MainThreadMarker, audio_unit: AudioUnit) -> Option<Retained<NSView>> {
    let mut instance: *mut c_void = std::ptr::null_mut();
    let mut size = std::mem::size_of_val(&instance) as u32;
    if unsafe {
        AudioUnitGetProperty(
            audio_unit,
            NICE_AU2_PROPERTY_RUST_INSTANCE,
            AUDIO_UNIT_SCOPE_GLOBAL,
            0,
            (&mut instance as *mut *mut c_void).cast(),
            &mut size,
        )
    } != 0
        || instance.is_null()
    {
        return None;
    }
    let (mut width, mut height) = (0, 0);
    if !nice_au2_get_editor_size(instance.cast(), &mut width, &mut height) {
        return None;
    }
    let frame = NSRect::new(
        NSPoint::new(0.0, 0.0),
        NSSize::new(width as f64, height as f64),
    );
    Some(EditorView::new(mtm, frame, instance).into_super())
}