mirror of
https://github.com/exoticorn/microw8.git
synced 2026-01-20 11:16:42 +01:00
implement scheduled sound updates in native runtime
This commit is contained in:
@@ -5,7 +5,7 @@ include "../include/microw8-api.cwa"
|
|||||||
const MUSIC_DATA = 0x20000;
|
const MUSIC_DATA = 0x20000;
|
||||||
|
|
||||||
export fn upd() {
|
export fn upd() {
|
||||||
let inline t = 32!32 / 16;
|
let inline t = 32!32 * 6 / 100;
|
||||||
let inline p = t / 1024;
|
let inline p = t / 1024;
|
||||||
|
|
||||||
let channel:i32;
|
let channel:i32;
|
||||||
|
|||||||
@@ -197,8 +197,8 @@ impl super::Runtime for MicroW8 {
|
|||||||
fn run_frame(&mut self) -> Result<()> {
|
fn run_frame(&mut self) -> Result<()> {
|
||||||
let mut result = Ok(());
|
let mut result = Ok(());
|
||||||
if let Some(mut instance) = self.instance.take() {
|
if let Some(mut instance) = self.instance.take() {
|
||||||
|
let time = instance.start_time.elapsed().as_millis() as i32;
|
||||||
{
|
{
|
||||||
let time = instance.start_time.elapsed().as_millis() as i32;
|
|
||||||
let mut gamepad: u32 = 0;
|
let mut gamepad: u32 = 0;
|
||||||
for key in self.window.get_keys() {
|
for key in self.window.get_keys() {
|
||||||
if let Some(index) = GAMEPAD_KEYS
|
if let Some(index) = GAMEPAD_KEYS
|
||||||
@@ -232,7 +232,10 @@ impl super::Runtime for MicroW8 {
|
|||||||
let mut sound_regs = [0u8; 32];
|
let mut sound_regs = [0u8; 32];
|
||||||
sound_regs.copy_from_slice(&memory[80..112]);
|
sound_regs.copy_from_slice(&memory[80..112]);
|
||||||
if let Some(ref sound) = instance.sound {
|
if let Some(ref sound) = instance.sound {
|
||||||
sound.tx.send(sound_regs)?;
|
sound.tx.send(RegisterUpdate {
|
||||||
|
time,
|
||||||
|
data: sound_regs,
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let framebuffer = &memory[120..(120 + 320 * 240)];
|
let framebuffer = &memory[120..(120 + 320 * 240)];
|
||||||
@@ -312,9 +315,14 @@ fn instantiate_platform(
|
|||||||
Ok(platform_instance)
|
Ok(platform_instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct RegisterUpdate {
|
||||||
|
time: i32,
|
||||||
|
data: [u8; 32],
|
||||||
|
}
|
||||||
|
|
||||||
struct Uw8Sound {
|
struct Uw8Sound {
|
||||||
stream: cpal::Stream,
|
stream: cpal::Stream,
|
||||||
tx: mpsc::SyncSender<[u8; 32]>,
|
tx: mpsc::SyncSender<RegisterUpdate>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_sound(
|
fn init_sound(
|
||||||
@@ -368,7 +376,7 @@ fn init_sound(
|
|||||||
let buffer_size = match *config.buffer_size() {
|
let buffer_size = match *config.buffer_size() {
|
||||||
cpal::SupportedBufferSize::Unknown => cpal::BufferSize::Default,
|
cpal::SupportedBufferSize::Unknown => cpal::BufferSize::Default,
|
||||||
cpal::SupportedBufferSize::Range { min, max } => {
|
cpal::SupportedBufferSize::Range { min, max } => {
|
||||||
cpal::BufferSize::Fixed(256.max(min).min(max))
|
cpal::BufferSize::Fixed(65536.max(min).min(max))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let config = cpal::StreamConfig {
|
let config = cpal::StreamConfig {
|
||||||
@@ -378,9 +386,7 @@ fn init_sound(
|
|||||||
|
|
||||||
let sample_rate = config.sample_rate.0 as usize;
|
let sample_rate = config.sample_rate.0 as usize;
|
||||||
|
|
||||||
let (tx, rx) = mpsc::sync_channel::<[u8; 32]>(1);
|
let (tx, rx) = mpsc::sync_channel::<RegisterUpdate>(30);
|
||||||
|
|
||||||
let start_time = Instant::now();
|
|
||||||
|
|
||||||
struct Resampler {
|
struct Resampler {
|
||||||
resampler: rubato::FftFixedIn<f32>,
|
resampler: rubato::FftFixedIn<f32>,
|
||||||
@@ -403,60 +409,91 @@ fn init_sound(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut sample_index = 0;
|
let mut sample_index = 0;
|
||||||
|
let mut pending_updates: Vec<RegisterUpdate> = Vec::with_capacity(30);
|
||||||
|
let mut current_time = 0;
|
||||||
let stream = device.build_output_stream(
|
let stream = device.build_output_stream(
|
||||||
&config,
|
&config,
|
||||||
move |mut buffer: &mut [f32], _| {
|
move |mut outer_buffer: &mut [f32], _| {
|
||||||
if let Ok(regs) = rx.try_recv() {
|
let mut first_update = true;
|
||||||
memory.write(&mut store, 80, ®s).unwrap();
|
while let Ok(update) = rx.try_recv() {
|
||||||
|
if first_update {
|
||||||
|
current_time += update.time.wrapping_sub(current_time) / 8;
|
||||||
|
first_update = false;
|
||||||
|
}
|
||||||
|
pending_updates.push(update);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
while !outer_buffer.is_empty() {
|
||||||
let time = start_time.elapsed().as_millis() as i32;
|
while pending_updates
|
||||||
let mem = memory.data_mut(&mut store);
|
.first()
|
||||||
mem[64..68].copy_from_slice(&time.to_le_bytes());
|
.into_iter()
|
||||||
}
|
.any(|u| u.time.wrapping_sub(current_time) <= 0)
|
||||||
|
{
|
||||||
|
let update = pending_updates.remove(0);
|
||||||
|
memory.write(&mut store, 80, &update.data).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(ref mut resampler) = resampler {
|
let duration = if let Some(update) = pending_updates.first() {
|
||||||
while !buffer.is_empty() {
|
((update.time.wrapping_sub(current_time) as usize) * sample_rate + 999) / 1000
|
||||||
let copy_size = resampler.output_buffers[0]
|
} else {
|
||||||
.len()
|
outer_buffer.len()
|
||||||
.saturating_sub(resampler.output_index)
|
};
|
||||||
.min(buffer.len() / 2);
|
let step_size = (duration.max(64) * 2).min(outer_buffer.len());
|
||||||
if copy_size == 0 {
|
|
||||||
resampler.input_buffers[0].clear();
|
|
||||||
resampler.input_buffers[1].clear();
|
|
||||||
for _ in 0..resampler.resampler.input_frames_next() {
|
|
||||||
resampler.input_buffers[0]
|
|
||||||
.push(snd.call(&mut store, (sample_index,)).unwrap_or(0.0));
|
|
||||||
resampler.input_buffers[1]
|
|
||||||
.push(snd.call(&mut store, (sample_index + 1,)).unwrap_or(0.0));
|
|
||||||
sample_index = sample_index.wrapping_add(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
resampler
|
let mut buffer = &mut outer_buffer[..step_size];
|
||||||
.resampler
|
|
||||||
.process_into_buffer(
|
{
|
||||||
&resampler.input_buffers,
|
let mem = memory.data_mut(&mut store);
|
||||||
&mut resampler.output_buffers,
|
mem[64..68].copy_from_slice(¤t_time.to_le_bytes());
|
||||||
None,
|
}
|
||||||
)
|
|
||||||
.unwrap();
|
if let Some(ref mut resampler) = resampler {
|
||||||
resampler.output_index = 0;
|
while !buffer.is_empty() {
|
||||||
} else {
|
let copy_size = resampler.output_buffers[0]
|
||||||
for i in 0..copy_size {
|
.len()
|
||||||
buffer[i * 2] = resampler.output_buffers[0][resampler.output_index + i];
|
.saturating_sub(resampler.output_index)
|
||||||
buffer[i * 2 + 1] =
|
.min(buffer.len() / 2);
|
||||||
resampler.output_buffers[1][resampler.output_index + i];
|
if copy_size == 0 {
|
||||||
|
resampler.input_buffers[0].clear();
|
||||||
|
resampler.input_buffers[1].clear();
|
||||||
|
for _ in 0..resampler.resampler.input_frames_next() {
|
||||||
|
resampler.input_buffers[0]
|
||||||
|
.push(snd.call(&mut store, (sample_index,)).unwrap_or(0.0));
|
||||||
|
resampler.input_buffers[1]
|
||||||
|
.push(snd.call(&mut store, (sample_index + 1,)).unwrap_or(0.0));
|
||||||
|
sample_index = sample_index.wrapping_add(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
resampler
|
||||||
|
.resampler
|
||||||
|
.process_into_buffer(
|
||||||
|
&resampler.input_buffers,
|
||||||
|
&mut resampler.output_buffers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
resampler.output_index = 0;
|
||||||
|
} else {
|
||||||
|
for i in 0..copy_size {
|
||||||
|
buffer[i * 2] =
|
||||||
|
resampler.output_buffers[0][resampler.output_index + i];
|
||||||
|
buffer[i * 2 + 1] =
|
||||||
|
resampler.output_buffers[1][resampler.output_index + i];
|
||||||
|
}
|
||||||
|
resampler.output_index += copy_size;
|
||||||
|
buffer = &mut buffer[copy_size * 2..];
|
||||||
}
|
}
|
||||||
resampler.output_index += copy_size;
|
}
|
||||||
buffer = &mut buffer[copy_size * 2..];
|
} else {
|
||||||
|
for v in buffer {
|
||||||
|
*v = snd.call(&mut store, (sample_index,)).unwrap_or(0.0);
|
||||||
|
sample_index = sample_index.wrapping_add(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
for v in buffer {
|
outer_buffer = &mut outer_buffer[step_size..];
|
||||||
*v = snd.call(&mut store, (sample_index,)).unwrap_or(0.0);
|
current_time =
|
||||||
sample_index = sample_index.wrapping_add(1);
|
current_time.wrapping_add((step_size * 500 / sample_rate).max(1) as i32);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
move |err| {
|
move |err| {
|
||||||
|
|||||||
Reference in New Issue
Block a user