diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2024-11-18 01:39:52 +0100 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2024-11-18 01:39:52 +0100 |
commit | 96f9236bff9907fc0508f1920ae98bf3076f4755 (patch) | |
tree | 7e8d83721ab171b2006799a7ac64b56cc90362a9 | |
parent | f8896689131d5218e3bf87c92d188ed7eca31267 (diff) | |
download | reduced_system_layer-96f9236bff9907fc0508f1920ae98bf3076f4755.zip |
Audio worklet
-rw-r--r-- | index.htm | 285 | ||||
-rwxr-xr-x | reduced_system_layer.c | 38 |
2 files changed, 206 insertions, 117 deletions
@@ -8,7 +8,133 @@ </head> <body style="margin: 0; height: 100%; overflow: hidden; overflow-x: hidden;"> <canvas style="margin: 0; width: 100%; height: 100%;" id="frame" oncontextmenu="event.preventDefault()"></canvas> + <script type="worklet"> + registerProcessor( + 'Sound_Ring', + class Sound_Ring extends AudioWorkletProcessor { + constructor(options) { + super(); + this.state = options.processorOptions.state; + } + process(input, output, parameters) { + // TODO + return true; + } + } + ); + </script> <script type="text/javascript"> + function key_from_code(code) { + switch (code) { + case "Backspace": return 8; + case "Tab": return 9; + case "Enter": return 10; + case "ControlLeft": return 11; + case "ControlRight": return 12; + case "ShiftLeft": return 13; + case "ShiftRight": return 14; + case "AltLeft": return 15; + case "AltRight": return 16; + case "ArrowLeft": return 17; + case "ArrowRight": return 18; + case "ArrowUp": return 19; + case "ArrowDown": return 20; + case "Pause": return 21; + case "Insert": return 22; + case "Home": return 23; + case "End": return 24; + case "PageUp": return 25; + case "PageDown": return 26; + case "Escape": return 27; + case "PrintScreen": return 28; + case "Space": return 32; + case "MetaLeft": return 33; + case "MetaRight": return 34; + case "Quote": return 39; + case "Comma": return 44; + case "Minus": return 45; + case "Period": return 46; + case "Slash": return 47; + case "Digit0": return 48; + case "Digit1": return 49; + case "Digit2": return 50; + case "Digit3": return 51; + case "Digit4": return 52; + case "Digit5": return 53; + case "Digit6": return 54; + case "Digit7": return 55; + case "Digit8": return 56; + case "Digit9": return 57; + case "Semicolon": return 59; + case "Equal": return 61; + case "BracketLeft": return 91; + case "Backslash": return 92; + case "BracketRight": return 93; + case "Backquote": return 96; + case "KeyA": return 97; + case "KeyB": return 98; + case "KeyC": return 99; + case "KeyD": return 100; + case "KeyE": return 101; + case "KeyF": return 102; + case "KeyG": return 103; + case "KeyH": return 104; + case "KeyI": return 105; + case "KeyJ": return 106; + case "KeyK": return 107; + case "KeyL": return 108; + case "KeyM": return 109; + case "KeyN": return 110; + case "KeyO": return 111; + case "KeyP": return 112; + case "KeyQ": return 113; + case "KeyR": return 114; + case "KeyS": return 115; + case "KeyT": return 116; + case "KeyU": return 117; + case "KeyV": return 118; + case "KeyW": return 119; + case "KeyX": return 120; + case "KeyY": return 121; + case "KeyZ": return 122; + case "Delete": return 127; + case "F1": return 145; + case "F2": return 146; + case "F3": return 147; + case "F4": return 148; + case "F5": return 149; + case "F6": return 150; + case "F7": return 151; + case "F8": return 152; + case "F9": return 153; + case "F10": return 154; + case "F11": return 155; + case "F12": return 156; + case "F13": return 157; + case "F14": return 158; + case "F15": return 159; + case "F16": return 160; + case "F17": return 161; + case "F18": return 162; + case "F19": return 163; + case "F20": return 164; + case "F21": return 165; + case "F22": return 166; + case "F23": return 167; + case "F24": return 168; + } + return 0; + }; + + function mod_from_event(ev) { + let mod = 0; + if (ev.ctrlKey) mod |= 1; + if (ev.shiftKey) mod |= 2; + if (ev.altKey) mod |= 4; + if (ev.metaKey) mod |= 8; + return mod; + }; + function string_from_memory(bytes, offset) { let len = 0; while (bytes[offset + len] != 0) @@ -27,11 +153,49 @@ let context; let animation_frame; - canvas = document.getElementById(attrs.id); + let sound_ready = false; + let sound_context; + let sound_init; + let sound_node; + + let sound_state = { + memory : null, + buffer_address : 0, + }; + + canvas = attrs.canvas; context = canvas.getContext("2d"); + sound_init = async () => { + if (sound_ready || sound_context !== undefined) + return; + + sound_context = new AudioContext({ + sampleRate : program.instance.exports.js_sample_rate(), + }); + + let blob = new Blob( + [ document.querySelector("script[type=worklet]").innerText ], + { type : "application/javascript", } + ); + + await sound_context.audioWorklet.addModule(URL.createObjectURL(blob)); + + sound_node = new AudioWorkletNode( + sound_context, + "Sound_Ring", + { numberOfInputs : 0, + outputChannelCount : [ program.instance.exports.js_num_channels() ], + processorOptions : { state : sound_state }, } + ); + + sound_node.connect(sound_context.destination); + + sound_ready = true; + }; + program = await WebAssembly.instantiateStreaming( - fetch("index.wasm"), + attrs.wasm, { "wasi_snapshot_preview1" : { clock_time_get : () => { return Date.now(); }, @@ -68,7 +232,7 @@ new TextDecoder().decode(memory.subarray(text, text + size)) ).catch((e) => { console.error(e); }); }, - p_cleanup : () => {}, + p_cleanup : () => {}, p_wait_events_impl : () => { wait_for_events = true; }, p_sleep_for : (time) => { sleep_duration += time; }, p_time : Date.now, @@ -123,6 +287,7 @@ }); canvas.addEventListener("mousedown", (ev) => { + sound_init(); program.instance.exports.js_mousedown(ev.buttons); window.requestAnimationFrame(animation_frame); }); @@ -137,117 +302,6 @@ window.requestAnimationFrame(animation_frame); }); - let key_from_code = (code) => { - switch (code) { - case "Backspace": return 8; - case "Tab": return 9; - case "Enter": return 10; - case "ControlLeft": return 11; - case "ControlRight": return 12; - case "ShiftLeft": return 13; - case "ShiftRight": return 14; - case "AltLeft": return 15; - case "AltRight": return 16; - case "ArrowLeft": return 17; - case "ArrowRight": return 18; - case "ArrowUp": return 19; - case "ArrowDown": return 20; - case "Pause": return 21; - case "Insert": return 22; - case "Home": return 23; - case "End": return 24; - case "PageUp": return 25; - case "PageDown": return 26; - case "Escape": return 27; - case "PrintScreen": return 28; - case "Space": return 32; - case "MetaLeft": return 33; - case "MetaRight": return 34; - case "Quote": return 39; - case "Comma": return 44; - case "Minus": return 45; - case "Period": return 46; - case "Slash": return 47; - case "Digit0": return 48; - case "Digit1": return 49; - case "Digit2": return 50; - case "Digit3": return 51; - case "Digit4": return 52; - case "Digit5": return 53; - case "Digit6": return 54; - case "Digit7": return 55; - case "Digit8": return 56; - case "Digit9": return 57; - case "Semicolon": return 59; - case "Equal": return 61; - case "BracketLeft": return 91; - case "Backslash": return 92; - case "BracketRight": return 93; - case "Backquote": return 96; - case "KeyA": return 97; - case "KeyB": return 98; - case "KeyC": return 99; - case "KeyD": return 100; - case "KeyE": return 101; - case "KeyF": return 102; - case "KeyG": return 103; - case "KeyH": return 104; - case "KeyI": return 105; - case "KeyJ": return 106; - case "KeyK": return 107; - case "KeyL": return 108; - case "KeyM": return 109; - case "KeyN": return 110; - case "KeyO": return 111; - case "KeyP": return 112; - case "KeyQ": return 113; - case "KeyR": return 114; - case "KeyS": return 115; - case "KeyT": return 116; - case "KeyU": return 117; - case "KeyV": return 118; - case "KeyW": return 119; - case "KeyX": return 120; - case "KeyY": return 121; - case "KeyZ": return 122; - case "Delete": return 127; - case "F1": return 145; - case "F2": return 146; - case "F3": return 147; - case "F4": return 148; - case "F5": return 149; - case "F6": return 150; - case "F7": return 151; - case "F8": return 152; - case "F9": return 153; - case "F10": return 154; - case "F11": return 155; - case "F12": return 156; - case "F13": return 157; - case "F14": return 158; - case "F15": return 159; - case "F16": return 160; - case "F17": return 161; - case "F18": return 162; - case "F19": return 163; - case "F20": return 164; - case "F21": return 165; - case "F22": return 166; - case "F23": return 167; - case "F24": return 168; - } - return 0; - }; - - let mod_from_event = (ev) => { - let mod = 0; - if (ev.ctrlKey) mod |= 1; - if (ev.shiftKey) mod |= 2; - if (ev.altKey) mod |= 4; - if (ev.metaKey) mod |= 8; - return mod; - }; - window.addEventListener("keydown", (ev) => { ev.preventDefault(); if (!ev.repeat) { @@ -274,7 +328,8 @@ } run({ - id : "frame", + canvas : document.getElementById("frame"), + wasm : fetch("index.wasm"), fit_window : true, }).catch((e) => console.error(e)); </script> diff --git a/reduced_system_layer.c b/reduced_system_layer.c index 692d555..dfc8b4f 100755 --- a/reduced_system_layer.c +++ b/reduced_system_layer.c @@ -1550,7 +1550,7 @@ void p_clipboard_write(i64 size, c8 *data) { // ================================================================ // -// WebAssembly +// Web canvas // // ================================================================ @@ -1592,7 +1592,7 @@ void p_render_frame(void) { p_render_frame_impl(); } -__attribute__((export_name("js_memset"))) void js_memset(void *dst, i32 val, u32 num) { + __attribute__((export_name("js_memset"))) void js_memset(void *dst, i32 val, u32 num) { if (dst == NULL) return; for (u32 i = 0; i < num; ++i) ((u8 *) dst)[i] = (u8) val; @@ -1678,6 +1678,40 @@ __attribute__((export_name("js_keyup"))) void js_keyup(u32 key, u32 mod) { #endif // __wasm__ // ================================================================ +// +// Web audio +// +// ================================================================ + +#ifdef __wasm__ + +void p_handle_audio(i64 samples_elapsed) { + // TODO +} + +void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { + // TODO +} + +__attribute__((export_name("js_sample_rate"))) f64 js_sample_rate(void) { + return (f64) AUDIO_SAMPLE_RATE; +} + +__attribute__((export_name("js_num_channels"))) i32 js_num_channels(void) { + return AUDIO_NUM_CHANNELS; +} + +__attribute__((export_name("js_sound_buffer"))) void *js_sound_buffer(void) { + return NULL; +} + +__attribute__((export_name("js_sound_playback"))) void js_sound_playback(i64 num_samples) { + // TODO +} + +#endif // __wasm__ + +// ================================================================ #endif // REDUCED_SYSTEM_LAYER_IMPL_GUARD_ #endif // REDUCED_SYSTEM_LAYER_HEADER |