sea-codec 0.7.0

Low-complexity, lossy audio codec designed for embedded devices
Documentation
extern "C" {
    fn js_error(ptr: *const std::os::raw::c_char);
}

#[no_mangle]
pub extern "C" fn setup() {
    use std::ffi::CString;
    use std::panic;

    panic::set_hook(Box::new(|info| {
        let file = info.location().unwrap().file();
        let line = info.location().unwrap().line();
        let col = info.location().unwrap().column();

        let msg = match info.payload().downcast_ref::<&'static str>() {
            Some(s) => *s,
            None => match info.payload().downcast_ref::<String>() {
                Some(s) => &s[..],
                None => "Box<Any>",
            },
        };

        let err_info = format!("Panicked at '{}', {}:{}:{}", msg, file, line, col);
        let cstring = CString::new(err_info).unwrap();

        unsafe {
            js_error(cstring.as_ptr());
        }
    }));
}

#[no_mangle]
pub extern "C" fn wasm_sea_encode(
    input_samples: *const i16,
    input_length: usize,
    sample_rate: u32,
    channels: u32,
    bitrate: f32,
    vbr: bool,
    output_buffer: *mut u8,
    output_length: usize,
) -> usize {
    use crate::encoder::EncoderSettings;
    use crate::sea_encode;

    let input_samples = unsafe { std::slice::from_raw_parts(input_samples, input_length / 2) };
    let encoded_data = sea_encode(
        input_samples,
        sample_rate,
        channels,
        EncoderSettings {
            residual_bits: bitrate,
            vbr,
            ..Default::default()
        },
    );

    assert!(encoded_data.len() <= output_length);

    unsafe {
        std::ptr::copy_nonoverlapping(encoded_data.as_ptr(), output_buffer, encoded_data.len());
    }

    encoded_data.len()
}

#[no_mangle]
pub extern "C" fn wasm_sea_decode(
    encoded: *const u8,
    encoded_length: usize,
    output_buffer: *mut i16,
    output_length: usize,
    sample_rate: *mut u32,
    channels: *mut u32,
) -> usize {
    use crate::sea_decode;

    let encoded_data = unsafe { std::slice::from_raw_parts(encoded, encoded_length) };
    let decoded_data = sea_decode(encoded_data);

    assert!(decoded_data.samples.len() * 2 <= output_length);

    unsafe {
        std::ptr::copy_nonoverlapping(
            decoded_data.samples.as_ptr(),
            output_buffer,
            decoded_data.samples.len(),
        );

        *sample_rate = decoded_data.sample_rate;
        *channels = decoded_data.channels;
    }

    decoded_data.samples.len() * 2
}

#[no_mangle]
pub unsafe extern "C" fn allocate(size: usize) -> *mut u8 {
    use std::alloc::{alloc, Layout};

    let layout = Layout::from_size_align(size, 1).unwrap();
    alloc(layout)
}

#[no_mangle]
pub unsafe extern "C" fn deallocate(ptr: *mut u8, size: usize) {
    use std::alloc::{dealloc, Layout};

    let layout = Layout::from_size_align(size, 1).unwrap();
    dealloc(ptr, layout);
}

#[no_mangle]
pub extern "C" fn wasm_resample(
    input_samples: *const i16,
    input_length: usize,
    source_rate: u32,
    target_rate: u32,
    channels: u32,
    output_buffer: *mut i16,
    output_length: usize,
) -> usize {
    use crate::resample::resample;

    let input_samples = unsafe { std::slice::from_raw_parts(input_samples, input_length / 2) };
    let resampled = resample(input_samples, source_rate, target_rate, channels);

    assert!(resampled.len() * 2 <= output_length);

    unsafe {
        std::ptr::copy_nonoverlapping(resampled.as_ptr(), output_buffer, resampled.len());
    }

    resampled.len() * 2
}