Add audio, fix timing

This commit is contained in:
2024-11-04 09:59:58 -05:00
parent 8bba7b9e1b
commit 70373647fb
6 changed files with 597 additions and 17 deletions
+65 -1
View File
@@ -1,6 +1,7 @@
use std::{ffi::c_void, ptr};
use std::{ffi::c_void, ptr, slice};
use anyhow::{anyhow, Result};
use num_derive::{FromPrimitive, ToPrimitive};
#[repr(C)]
struct VB {
@@ -9,6 +10,20 @@ struct VB {
#[allow(non_camel_case_types)]
type c_int = i32;
#[allow(non_camel_case_types)]
type c_uint = u32;
#[repr(u32)]
#[derive(FromPrimitive, ToPrimitive)]
enum VBDataType {
S8 = 0,
U8 = 1,
S16 = 2,
U16 = 3,
S32 = 4,
F32 = 5,
}
type OnFrame = extern "C" fn(sim: *mut VB) -> c_int;
#[link(name = "vb")]
@@ -27,6 +42,13 @@ extern "C" {
right_stride_x: c_int,
right_stride_y: c_int,
);
#[link_name = "vbGetSamples"]
fn vb_get_samples(
sim: *mut VB,
typ_: *mut VBDataType,
capacity: *mut c_uint,
position: *mut c_uint,
) -> *mut c_void;
#[link_name = "vbGetUserData"]
fn vb_get_user_data(sim: *mut VB) -> *mut c_void;
#[link_name = "vbInit"]
@@ -39,6 +61,13 @@ extern "C" {
fn vb_set_keys(sim: *mut VB, keys: u16) -> u16;
#[link_name = "vbSetFrameCallback"]
fn vb_set_frame_callback(sim: *mut VB, on_frame: OnFrame);
#[link_name = "vbSetSamples"]
fn vb_set_samples(
sim: *mut VB,
samples: *mut c_void,
typ_: VBDataType,
capacity: c_uint,
) -> c_int;
#[link_name = "vbSetUserData"]
fn vb_set_user_data(sim: *mut VB, tag: *mut c_void);
#[link_name = "vbSizeOf"]
@@ -53,6 +82,9 @@ extern "C" fn on_frame(sim: *mut VB) -> i32 {
1
}
const AUDIO_CAPACITY_SAMPLES: usize = 834 * 4;
const AUDIO_CAPACITY_FLOATS: usize = AUDIO_CAPACITY_SAMPLES * 2;
struct VBState {
frame_seen: bool,
}
@@ -79,6 +111,11 @@ impl CoreVB {
unsafe { vb_set_user_data(sim, Box::into_raw(Box::new(state)).cast()) };
unsafe { vb_set_frame_callback(sim, on_frame) };
// set up audio buffer
let audio_buffer = vec![0.0f32; AUDIO_CAPACITY_FLOATS];
let samples: *mut c_void = Box::into_raw(audio_buffer.into_boxed_slice()).cast();
unsafe { vb_set_samples(sim, samples, VBDataType::F32, AUDIO_CAPACITY_SAMPLES as u32) };
CoreVB { sim }
}
@@ -138,6 +175,25 @@ impl CoreVB {
true
}
pub fn read_samples(&mut self, samples: &mut Vec<f32>) {
let mut position = 0;
let ptr =
unsafe { vb_get_samples(self.sim, ptr::null_mut(), ptr::null_mut(), &mut position) };
// SAFETY: position is an offset in a buffer of (f32, f32). so, position * 2 is an offset in a buffer of f32.
let read_samples: &mut [f32] =
unsafe { slice::from_raw_parts_mut(ptr.cast(), position as usize * 2) };
samples.extend_from_slice(read_samples);
unsafe {
vb_set_samples(
self.sim,
ptr,
VBDataType::F32,
AUDIO_CAPACITY_SAMPLES as u32,
)
};
}
pub fn set_keys(&mut self, keys: u16) {
unsafe { vb_set_keys(self.sim, keys) };
}
@@ -145,6 +201,14 @@ impl CoreVB {
impl Drop for CoreVB {
fn drop(&mut self) {
let ptr =
unsafe { vb_get_samples(self.sim, ptr::null_mut(), ptr::null_mut(), ptr::null_mut()) };
// SAFETY: the audio buffer originally came from a Vec<u32>
let floats: Vec<f32> = unsafe {
Vec::from_raw_parts(ptr.cast(), AUDIO_CAPACITY_FLOATS, AUDIO_CAPACITY_FLOATS)
};
drop(floats);
// SAFETY: the *mut VB owns its userdata.
// There is no way for the userdata to be null or otherwise invalid.
let ptr: *mut VBState = unsafe { vb_get_user_data(self.sim).cast() };