mirror of
https://github.com/exoticorn/microw8.git
synced 2026-11-14 15:17:19 +01:00
Compare commits
2
Commits
61941bceeb
...
e05701300c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e05701300c | ||
|
|
df0c169d54 |
No files matched your search
@@ -20,10 +20,10 @@ data 0x20000 {
|
||||
0x44, 0x0, 0x0, 0x47, 0x49, 0x47, 0x45, 0x41,
|
||||
0x44, 0x0, 0x0, 0x0, 0x42, 0x0, 0x0, 0x0,
|
||||
|
||||
0x25, 0, 0x49, 0x25, 0x25, 0, 0x49, 0,
|
||||
0x25, 0, 0x49, 0x25, 0x25, 0, 0x49, 0,
|
||||
0x25, 0, 0x49, 0x25, 0x25, 0, 0x49, 0,
|
||||
0x25, 0, 0x49, 0x25, 0x25, 0, 0x49, 0,
|
||||
0x25, 0, 0x49, 0x25, 0x25, 0, 0x49, 0x38,
|
||||
0x25, 0, 0x49, 0x25, 0x25, 0, 0x49, 0x38,
|
||||
0x25, 0, 0x49, 0x25, 0x25, 0, 0x49, 0x38,
|
||||
0x25, 0, 0x49, 0x25, 0x25, 0, 0x49, 0x38,
|
||||
|
||||
0x2a, 0x0, 0x0, 0x0, 0x2d, 0x0, 0x0, 0x0,
|
||||
0x2c, 0x0, 0x28, 0x0, 0x2a, 0x0, 0x0, 0x0,
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
<!doctype html><html><head><meta charset="utf8"><title>uw8-run</title><style>body,canvas,html{background-color:#202024;margin:0;padding:0}body,html{height:100%}body{display:grid;grid-template-rows:1fr}#screen{align-self:center;border:4px solid #303040;image-rendering:pixelated;justify-self:center}#message{background-color:rgba(0,0,0,.4);color:#c64;font:700 12pt sans-serif;padding:8px;position:absolute;width:calc(100% - 16px);z-index:2}@media (min-width:648px) and (min-height:488px){#screen{height:480px;width:640px}}@media (min-width:968px) and (min-height:728px){#screen{height:720px;width:960px}}</style></head><body> <canvas id="screen" width="320" height="240" tabindex="1"> </canvas> <div id="message"></div> </body><script type="module">function e(e){return e&&e.__esModule?e.default:e}class t extends AudioWorkletNode{constructor(e){super(e,"apu",{outputChannelCount:[2]})}}let A=(...e)=>new Uint8Array(...e),a=(...e)=>new Uint32Array(...e);let B=function(B,n={}){n.setMessage||(n.setMessage=(e,t)=>{t&&console.log("error: "+t)});let s,o,r,i,l=B.getContext("2d"),F=l.createImageData(320,240),g=n.devkitMode,c=0,d=null==n.keyboardElement?B:n.keyboardElement;if(d){let e=e=>{let t,A="keydown"==e.type;switch(e.code){case"ArrowUp":t=1;break;case"ArrowDown":t=2;break;case"ArrowLeft":t=4;break;case"ArrowRight":t=8;break;case"KeyZ":t=16;break;case"KeyX":t=32;break;case"KeyA":t=64;break;case"KeyS":t=128;break;case"KeyR":A&&f(o,!0);break;case"F9":A&&B.toBlob((e=>{u(e,".png")})),e.preventDefault();break;case"F10":A&&function(){if(r)return r.stop(),void(r=null);r=new MediaRecorder(B.captureStream(),{mimeType:"video/webm",videoBitsPerSecond:25e6});let e=[];r.ondataavailable=t=>{e.push(t.data)};let t=n.timerElement;t&&(t.hidden=!1,t.innerText="00:00");function A(){if(i){if(t){let e=Math.floor((Date.now()-i)/1e3);t.innerText=Math.floor(e/60).toString().padStart(2,"0")+":"+(e%60).toString().padStart(2,"0")}setTimeout(A,1e3)}}r.onstop=()=>{t&&(t.hidden=!0),u(new Blob(e,{type:"video/webm"}),".webm")},r.start(),i=Date.now(),setTimeout(A,1e3)}(),e.preventDefault()}A?c|=t:c&=~t};d.onkeydown=e,d.onkeyup=e}async function f(r,i){s&&(s(),s=null);let d=new AudioContext({sampleRate:44100}),u=!0,D=new AbortController;s=()=>{d.close(),u=!1,D.abort()};let E=r.byteLength;if(n.setMessage(E),0==E)return;await d.audioWorklet.addModule(e("data:application/javascript,let%20e%3D%28...e%29%3D%3Enew%20Uint8Array%28...e%29%3Bclass%20s%20extends%20AudioWorkletProcessor%7Bconstructor%28%29%7Bsuper%28%29%2Cthis.sampleIndex%3D0%2Cthis.port.onmessage%3Ds%3D%3E%7Bthis.memory%3Fe%28this.memory.buffer%2C80%2C32%29.set%28e%28s.data%29%29%3Athis.load%28s.data%5B0%5D%2Cs.data%5B1%5D%29%7D%7Dasync%20load%28e%2Cs%29%7Blet%20t%3Dnew%20WebAssembly.Memory%28%7Binitial%3A4%2Cmaximum%3A4%7D%29%2Ca%3D%7Benv%3A%7Bmemory%3At%7D%7D%3Bfor%28let%20e%20of%5B%22acos%22%2C%22asin%22%2C%22atan%22%2C%22atan2%22%2C%22cos%22%2C%22exp%22%2C%22log%22%2C%22sin%22%2C%22tan%22%2C%22pow%22%5D%29a.env%5Be%5D%3DMath%5Be%5D%3Bfor%28let%20e%3D9%3Be%3C64%3B%2B%2Be%29a.env%5B%22reserved%22%2Be%5D%3D%28%29%3D%3E%7B%7D%3Bfor%28let%20e%3D0%3Be%3C16%3B%2B%2Be%29a.env%5B%22g_reserved%22%2Be%5D%3D0%3Blet%20r%3Dasync%20e%3D%3E%28await%20WebAssembly.instantiate%28e%2Ca%29%29.instance%2Cn%3Dawait%20r%28e%29%3Bfor%28let%20e%20in%20n.exports%29a.env%5Be%5D%3Dn.exports%5Be%5D%3Blet%20o%3Dawait%20r%28s%29%3Bthis.memory%3Dt%2Cthis.snd%3Do.exports.snd%7C%7Cn.exports.gesSnd%2Cthis.port.postMessage%282%29%7Dprocess%28e%2Cs%2Ct%29%7Bif%28this.snd%29%7Blet%20e%3Ds%5B0%5D%2Ct%3Dthis.sampleIndex%2Ca%3De%5B0%5D.length%3Bfor%28let%20s%3D0%3Bs%3Ca%3B%2B%2Bs%29e%5B0%5D%5Bs%5D%3Dthis.snd%28t%2B%2B%29%2Ce%5B1%5D%5Bs%5D%3Dthis.snd%28t%2B%2B%29%3Bthis.sampleIndex%3D4294967295%26t%7Dreturn%210%7D%7DregisterProcessor%28%22apu%22%2Cs%29%3B"));let I,m=new t(d),C=0,Q=new Promise((e=>I=e)),p=e=>{C|=e,3==C&&I&&(I(!0),I=null)};m.port.onmessage=e=>p(e.data);let w=()=>{"suspended"==d.state?(n.startButton&&(n.startButton.style="",B.style="display:none"),(n.startButton||B).onclick=()=>{d.resume()}):(n.startButton&&(n.startButton.style="display:none",B.style=""),p(1))};d.onstatechange=w,w(),o=r;let b=window.location.pathname;if(E<=1024&&!i){let e="";for(let t of A(r))e+=String.fromCharCode(t);b+="#"+btoa(e),b!=window.location.pathname+window.location.hash&&history.pushState(null,null,b)}B.width=B.width;try{let t={initial:4};g||(t.maximum=4);let B,s=new WebAssembly.Memory(t),i=A(s.buffer),I={env:{memory:s}},C=e=>{if(B&&(!g||0!=A(e)[0])){i.set(A(e));let t=B.exports.load_uw8(e.byteLength);e=new ArrayBuffer(t),A(e).set(i.slice(0,t))}return e},p=async e=>(await WebAssembly.instantiate(e,I)).instance,w=async e=>C(await(await fetch(e)).arrayBuffer());B=await p(await w(e("data:application/wasm;base64,AGFzbQEAAAABFQRgAX8Bf2ACf38Bf2ADf39%2FAGAAAAIPAQNlbnYGbWVtb3J5AgAEAwkIAAABAgEAAAMGEAN%2FAUEAC38BQQALfwFBAAsHGQIIbG9hZF91dzgAAAp1bmNvbXByZXNzAAQIAQcKngUIxwEBB39BAC0AAEEBayIBQQBIBEAgAA8LQYDAByAAaiECIAFBAXEEQEEBQYHABxAEIQIFQYDAB0EAIAAQAwtBAEGAhA9BCBLine truncated
|
||||
<!doctype html><html><head><meta charset="utf8"><title>uw8-run</title><style>body,canvas,html{background-color:#202024;margin:0;padding:0}body,html{height:100%}body{display:grid;grid-template-rows:1fr}#screen{align-self:center;border:4px solid #303040;image-rendering:pixelated;justify-self:center}#message{background-color:rgba(0,0,0,.4);color:#c64;font:700 12pt sans-serif;padding:8px;position:absolute;width:calc(100% - 16px);z-index:2}@media (min-width:648px) and (min-height:488px){#screen{height:480px;width:640px}}@media (min-width:968px) and (min-height:728px){#screen{height:720px;width:960px}}</style></head><body> <canvas id="screen" width="320" height="240" tabindex="1"> </canvas> <div id="message"></div> </body><script type="module">function e(e){return e&&e.__esModule?e.default:e}class t extends AudioWorkletNode{constructor(e){super(e,"apu",{outputChannelCount:[2]})}}let A=(...e)=>new Uint8Array(...e),a=(...e)=>new Uint32Array(...e);let s=function(s,B={}){B.setMessage||(B.setMessage=(e,t)=>{t&&console.log("error: "+t)});let r,o,n,i,l=s.getContext("2d"),d=l.createImageData(320,240),u=B.devkitMode,F=0,g=null==B.keyboardElement?s:B.keyboardElement;if(g){let e=e=>{let t,A="keydown"==e.type;switch(e.code){case"ArrowUp":t=1;break;case"ArrowDown":t=2;break;case"ArrowLeft":t=4;break;case"ArrowRight":t=8;break;case"KeyZ":t=16;break;case"KeyX":t=32;break;case"KeyA":t=64;break;case"KeyS":t=128;break;case"KeyR":A&&c(o,!0);break;case"F9":A&&s.toBlob((e=>{f(e,".png")})),e.preventDefault();break;case"F10":A&&function(){if(n)return n.stop(),void(n=null);n=new MediaRecorder(s.captureStream(),{mimeType:"video/webm",videoBitsPerSecond:25e6});let e=[];n.ondataavailable=t=>{e.push(t.data)};let t=B.timerElement;t&&(t.hidden=!1,t.innerText="00:00");function A(){if(i){if(t){let e=Math.floor((Date.now()-i)/1e3);t.innerText=Math.floor(e/60).toString().padStart(2,"0")+":"+(e%60).toString().padStart(2,"0")}setTimeout(A,1e3)}}n.onstop=()=>{t&&(t.hidden=!0),f(new Blob(e,{type:"video/webm"}),".webm")},n.start(),i=Date.now(),setTimeout(A,1e3)}(),e.preventDefault()}A?F|=t:F&=~t};g.onkeydown=e,g.onkeyup=e}async function c(n,i){r&&(r(),r=null);let g=new AudioContext({sampleRate:44100}),f=!0,Q=new AbortController;r=()=>{g.close(),f=!1,Q.abort()};let D=n.byteLength;if(B.setMessage(D),0==D)return;await g.audioWorklet.addModule(e("data:application/javascript,let%20e%3D%28...e%29%3D%3Enew%20Uint8Array%28...e%29%3Bclass%20t%20extends%20AudioWorkletProcessor%7Bconstructor%28%29%7Bsuper%28%29%2Cthis.sampleIndex%3D0%2Cthis.port.onmessage%3Dt%3D%3E%7Bif%28this.memory%29if%28isNaN%28t.data%29%29%7Blet%20s%3De%28t.data%29%3Be%28this.memory.buffer%2C80%2C32%29.set%28s%29%2Cs.set%28e%28this.memory.buffer%2C76928%2C32%29%29%2Cthis.port.postMessage%28t.data%29%7Delse%20this.startTime%3Dt.data%3Belse%20this.load%28t.data%5B0%5D%2Ct.data%5B1%5D%29%7D%7Dasync%20load%28e%2Ct%29%7Blet%20s%3Dnew%20WebAssembly.Memory%28%7Binitial%3A4%2Cmaximum%3A4%7D%29%2Ca%3D%7Benv%3A%7Bmemory%3As%7D%7D%3Bfor%28let%20e%20of%5B%22acos%22%2C%22asin%22%2C%22atan%22%2C%22atan2%22%2C%22cos%22%2C%22exp%22%2C%22log%22%2C%22sin%22%2C%22tan%22%2C%22pow%22%5D%29a.env%5Be%5D%3DMath%5Be%5D%3Bfor%28let%20e%3D9%3Be%3C64%3B%2B%2Be%29a.env%5B%22reserved%22%2Be%5D%3D%28%29%3D%3E%7B%7D%3Bfor%28let%20e%3D0%3Be%3C16%3B%2B%2Be%29a.env%5B%22g_reserved%22%2Be%5D%3D0%3Blet%20r%3Dasync%20e%3D%3E%28await%20WebAssembly.instantiate%28e%2Ca%29%29.instance%2Ci%3Dawait%20r%28e%29%3Bfor%28let%20e%20in%20i.exports%29a.env%5Be%5D%3Di.exports%5Be%5D%3Blet%20o%3Dawait%20r%28t%29%3Bthis.memory%3Ds%2Cthis.snd%3Do.exports.snd%7C%7Ci.exports.gesSnd%2Cthis.port.postMessage%282%29%7Dprocess%28e%2Ct%2Cs%29%7Bif%28this.snd%26%26this.startTime%29%7Bnew%20Uint32Array%28this.memory.buffer%29%5B16%5D%3DDate.now%28%29-this.startTime%3Blet%20e%3Dt%5B0%5D%2Cs%3Dthis.sampleIndex%2Ca%3De%5B0%5D.length%3Bfor%28let%20t%3D0%3Bt%3Ca%3B%2B%2Bt%29e%5B0%5D%5Bt%5D%3Dthis.snd%28s%2B%2B%29%2Ce%5B1%5D%5Bt%5D%3Dthis.snd%28s%2B%2B%29%3Bthis.sampleIndex%3D4294967295%26s%7Dreturn%210%7D%7DregisterProcessor%28%22apu%22%2Ct%29%3B"));let w,C=new t(g),E=0,I=new Promise((e=>w=e)),y=e=>{E|=e,3==E&&w&&(w(!0),w=null)},m=()=>{"suspended"==g.state?(B.startButton&&(B.startButton.style="",s.style="display:none"),(B.startButton||s).onclick=()=>{g.resume()}):(B.startButton&&(B.startButton.style="display:none",s.style=""),y(1))};g.onstatechange=m,m(),o=n;let h=window.location.pathname;if(D<=1024&&!i){let e="";for(let t of A(n))e+=String.fromCharCode(t);h+="#"+btoa(e),h!=window.location.pathname+window.location.hash&&history.pushState(null,null,h)}s.width=s.width;try{let t={initial:4};u||(t.maximum=4);let s,r=new WebAssembly.Memory(t),i=A(r.buffer),w={env:{memory:r}},E=e=>{if(s&&(!u||0!=A(e)[0])){i.set(A(e));let t=s.exports.load_uw8(e.byteLength);e=new ArrayBuffer(t),A(e).set(i.slice(0,t))}return e},m=async e=>(await WebAssembly.instantiate(e,w)).instance,h=async e=>E(await(await fetch(e)).arrayBuffer());s=await m(await h(e("data:application/wasm;base64,ALine truncated
|
||||
+26
-2
@@ -91,6 +91,7 @@ impl MicroW8 {
|
||||
struct Uw8Sound {
|
||||
stream: cpal::Stream,
|
||||
tx: mpsc::SyncSender<[u8; 32]>,
|
||||
rx: mpsc::Receiver<[u8; 32]>,
|
||||
}
|
||||
|
||||
impl super::Runtime for MicroW8 {
|
||||
@@ -260,15 +261,27 @@ impl super::Runtime for MicroW8 {
|
||||
};
|
||||
|
||||
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 stream = {
|
||||
device.build_output_stream(
|
||||
&config,
|
||||
move |buffer: &mut [f32], _| {
|
||||
if let Ok(regs) = rx.try_recv() {
|
||||
if let Ok(mut regs) = rx.try_recv() {
|
||||
memory.write(&mut store, 80, ®s).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 {
|
||||
*v = snd.call(&mut store, (sample_index,)).unwrap_or(0.0);
|
||||
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()?;
|
||||
@@ -302,6 +319,13 @@ impl super::Runtime for MicroW8 {
|
||||
fn run_frame(&mut self) -> Result<()> {
|
||||
let mut result = Ok(());
|
||||
if let Some(mut instance) = self.instance.take() {
|
||||
while let Ok(regs) = instance.sound.rx.try_recv() {
|
||||
instance
|
||||
.memory
|
||||
.write(&mut instance.store, 0x12c80, ®s)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
{
|
||||
let time = instance.start_time.elapsed().as_millis() as i32;
|
||||
let mut gamepad: u32 = 0;
|
||||
|
||||
+11
-2
@@ -5,7 +5,14 @@ class APU extends AudioWorkletProcessor {
|
||||
this.sampleIndex = 0;
|
||||
this.port.onmessage = (ev) => {
|
||||
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 {
|
||||
this.load(ev.data[0], ev.data[1]);
|
||||
}
|
||||
@@ -51,7 +58,9 @@ class APU extends AudioWorkletProcessor {
|
||||
}
|
||||
|
||||
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 index = this.sampleIndex;
|
||||
let numSamples = channels[0].length;
|
||||
|
||||
+10
-1
@@ -126,7 +126,6 @@ export default function MicroW8(screen, config = {}) {
|
||||
audioReadyResolve = null;
|
||||
}
|
||||
};
|
||||
audioNode.port.onmessage = (e) => updateAudioReady(e.data);
|
||||
let audioStateChange = () => {
|
||||
if(audioContext.state == 'suspended') {
|
||||
if(config.startButton) {
|
||||
@@ -211,6 +210,14 @@ export default function MicroW8(screen, config = {}) {
|
||||
data = loadModuleData(data);
|
||||
|
||||
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]);
|
||||
|
||||
let platform_instance = await instantiate(platform_data);
|
||||
@@ -240,10 +247,12 @@ export default function MicroW8(screen, config = {}) {
|
||||
isPaused = false;
|
||||
audioContext.resume();
|
||||
startTime += now - pauseTime;
|
||||
audioNode.port.postMessage(startTime);
|
||||
} else {
|
||||
isPaused = true;
|
||||
audioContext.suspend();
|
||||
pauseTime = now;
|
||||
audioNode.port.postMessage(0);
|
||||
}
|
||||
};
|
||||
window.addEventListener('focus', () => updateVisibility(true), { signal: abortController.signal });
|
||||
|
||||
Reference in new issue
Block a user