implement backchannel from audio thread

This commit is contained in:
2022-04-22 00:28:19 +02:00
parent df0c169d54
commit e05701300c
4 changed files with 48 additions and 6 deletions

File diff suppressed because one or more lines are too long

View File

@@ -91,6 +91,7 @@ impl MicroW8 {
struct Uw8Sound { struct Uw8Sound {
stream: cpal::Stream, stream: cpal::Stream,
tx: mpsc::SyncSender<[u8; 32]>, tx: mpsc::SyncSender<[u8; 32]>,
rx: mpsc::Receiver<[u8; 32]>,
} }
impl super::Runtime for MicroW8 { impl super::Runtime for MicroW8 {
@@ -260,15 +261,27 @@ impl super::Runtime for MicroW8 {
}; };
let (tx, rx) = mpsc::sync_channel::<[u8; 32]>(1); let (tx, rx) = mpsc::sync_channel::<[u8; 32]>(1);
let (back_tx, back_rx) = mpsc::sync_channel::<[u8; 32]>(2);
let start_time = Instant::now();
let mut sample_index = 0; let mut sample_index = 0;
let stream = { let stream = {
device.build_output_stream( device.build_output_stream(
&config, &config,
move |buffer: &mut [f32], _| { move |buffer: &mut [f32], _| {
if let Ok(regs) = rx.try_recv() { if let Ok(mut regs) = rx.try_recv() {
memory.write(&mut store, 80, &regs).unwrap(); memory.write(&mut store, 80, &regs).unwrap();
memory.read(&mut store, 0x12c80, &mut regs).unwrap();
back_tx.send(regs).unwrap();
} }
{
let time = start_time.elapsed().as_millis() as i32;
let mem = memory.data_mut(&mut store);
mem[64..68].copy_from_slice(&time.to_le_bytes());
}
for v in buffer { for v in buffer {
*v = snd.call(&mut store, (sample_index,)).unwrap_or(0.0); *v = snd.call(&mut store, (sample_index,)).unwrap_or(0.0);
sample_index = sample_index.wrapping_add(1); sample_index = sample_index.wrapping_add(1);
@@ -280,7 +293,11 @@ impl super::Runtime for MicroW8 {
)? )?
}; };
Uw8Sound { stream, tx } Uw8Sound {
stream,
tx,
rx: back_rx,
}
}; };
sound.stream.play()?; sound.stream.play()?;
@@ -302,6 +319,13 @@ 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() {
while let Ok(regs) = instance.sound.rx.try_recv() {
instance
.memory
.write(&mut instance.store, 0x12c80, &regs)
.unwrap();
}
{ {
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;

View File

@@ -5,7 +5,14 @@ class APU extends AudioWorkletProcessor {
this.sampleIndex = 0; this.sampleIndex = 0;
this.port.onmessage = (ev) => { this.port.onmessage = (ev) => {
if(this.memory) { if(this.memory) {
U8(this.memory.buffer, 80, 32).set(U8(ev.data)); if(isNaN(ev.data)) {
let data = U8(ev.data);
U8(this.memory.buffer, 80, 32).set(data);
data.set(U8(this.memory.buffer, 0x12c80, 32));
this.port.postMessage(ev.data);
} else {
this.startTime = ev.data;
}
} else { } else {
this.load(ev.data[0], ev.data[1]); this.load(ev.data[0], ev.data[1]);
} }
@@ -51,7 +58,9 @@ class APU extends AudioWorkletProcessor {
} }
process(inputs, outputs, parameters) { process(inputs, outputs, parameters) {
if(this.snd) { if(this.snd && this.startTime) {
let u32Mem = new Uint32Array(this.memory.buffer);
u32Mem[16] = Date.now() - this.startTime;
let channels = outputs[0]; let channels = outputs[0];
let index = this.sampleIndex; let index = this.sampleIndex;
let numSamples = channels[0].length; let numSamples = channels[0].length;

View File

@@ -126,7 +126,6 @@ export default function MicroW8(screen, config = {}) {
audioReadyResolve = null; audioReadyResolve = null;
} }
}; };
audioNode.port.onmessage = (e) => updateAudioReady(e.data);
let audioStateChange = () => { let audioStateChange = () => {
if(audioContext.state == 'suspended') { if(audioContext.state == 'suspended') {
if(config.startButton) { if(config.startButton) {
@@ -211,6 +210,14 @@ export default function MicroW8(screen, config = {}) {
data = loadModuleData(data); data = loadModuleData(data);
let platform_data = await loadModuleURL(platformUrl); let platform_data = await loadModuleURL(platformUrl);
audioNode.port.onmessage = (e) => {
if(isNaN(e.data)) {
U8(memory.buffer, 0x12c80, 32).set(U8(e.data));
} else {
updateAudioReady(e.data);
}
};
audioNode.port.postMessage([platform_data, data]); audioNode.port.postMessage([platform_data, data]);
let platform_instance = await instantiate(platform_data); let platform_instance = await instantiate(platform_data);
@@ -240,10 +247,12 @@ export default function MicroW8(screen, config = {}) {
isPaused = false; isPaused = false;
audioContext.resume(); audioContext.resume();
startTime += now - pauseTime; startTime += now - pauseTime;
audioNode.port.postMessage(startTime);
} else { } else {
isPaused = true; isPaused = true;
audioContext.suspend(); audioContext.suspend();
pauseTime = now; pauseTime = now;
audioNode.port.postMessage(0);
} }
}; };
window.addEventListener('focus', () => updateVisibility(true), { signal: abortController.signal }); window.addEventListener('focus', () => updateVisibility(true), { signal: abortController.signal });