From e0b7e88f2a830f1f9663dcfbeaed5e453a3c7642 Mon Sep 17 00:00:00 2001 From: James Prevett Date: Thu, 7 Nov 2024 16:12:46 -0600 Subject: [PATCH] Fixed framebuffer, dsp --- demo/demo.js | 44 +++++++++++++++++++++----------------------- demo/index.html | 6 +++--- src/dsp.ts | 13 +++++-------- src/framebuffer.ts | 3 +++ 4 files changed, 32 insertions(+), 34 deletions(-) diff --git a/demo/demo.js b/demo/demo.js index 2e781dd..d4239de 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -1,42 +1,40 @@ import { configure, fs } from '@zenfs/core'; -import { framebuffer, dsp } from '@zenfs/devices'; +import { framebuffer } from '@zenfs/devices'; -// this is optional, but I set them, so I have control const canvas = document.querySelector('#fb'); const { width, height } = canvas; -const audioContext = new AudioContext(); - -// add initial devices like /dev/null, etc await configure({ addDevices: true }); -const devfs = fs.mounts.get('/dev'); - -// mount framebuffer & dsp -devfs.createDevice('/fb0', framebuffer({ canvas })); -devfs.createDevice('/dsp', await dsp({ audioContext })); +fs.mounts.get('/dev').createDevice('/fb0', framebuffer({ canvas })); -// example: write static to framebuffer +// example: write gradient with changing hue to framebuffer const screen = new Uint8Array(width * height * 4); +let hue = 0; + +function hslToRgb(hue, saturation) { + const a = saturation / 2; + const f = n => { + const k = (n + hue / 30) % 12; + return 0.5 - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); + }; + return [f(0) * 255, f(8) * 255, f(4) * 255]; +} + function makeGradientFb() { + hue = (hue + 1) % 360; // Increment hue and keep it in the 0-359 range + for (let y = 0; y < height; y++) { for (let x = 0; x < width; x++) { const index = (y * width + x) * 4; - const gradientValue = (x / width) * 255; - screen.set([gradientValue, gradientValue, 255 - gradientValue, 255], index); + const gradientValue = (x / width) * 100; // Adjust the saturation and lightness effect + const [r, g, b] = hslToRgb(hue, gradientValue / 100, 0.5); // S=gradientValue, L=0.5 for vivid color + + screen.set([r, g, b, 255], index); } } - fs.promises.writeFile('/dev/fb0', screen); + fs.writeFileSync('/dev/fb0', screen, { flag: 'r+' }); requestAnimationFrame(makeGradientFb); } makeGradientFb(); - -// example: write static to audio -const audioBuffer = new Float32Array(audioContext.sampleRate * 4); -setInterval(() => { - for (let i in audioBuffer) { - audioBuffer[i] = Math.random() * 2 - 1; - } - fs.promises.writeFile('/dev/dsp', audioBuffer); -}, 1000); diff --git a/demo/index.html b/demo/index.html index d99a685..7dbea02 100644 --- a/demo/index.html +++ b/demo/index.html @@ -1,11 +1,11 @@ ZenFS Devices - + -

This will demonstrate drawing to a framebuffer & creating audio:

+

Framebuffer demo

- + diff --git a/src/dsp.ts b/src/dsp.ts index 5b85c34..546b084 100644 --- a/src/dsp.ts +++ b/src/dsp.ts @@ -9,14 +9,14 @@ if ('AudioWorkletProcessor' in globalThis) { public constructor() { super(); this.port.onmessage = ({ data }: MessageEvent) => { - this.buffer = data; + this.buffer = new Float32Array(data); }; } public process(inputs: Float32Array[][], outputs: Float32Array[][]): boolean { - if (this.buffer) { - const c = currentFrame % sampleRate; - outputs[0][0].set(this.buffer.slice(c, c + 128)); + if (this.buffer && this.buffer.byteLength >= 128) { + outputs[0][0].set(this.buffer.slice(0, 128)); + this.buffer = this.buffer.slice(128); } return true; } @@ -43,13 +43,11 @@ interface DspOptions { export async function dsp(options: DspOptions = {}): Promise> { const context = options.audioContext || new AudioContext(); - const audioBuffer = new ArrayBuffer(context.sampleRate * 4); await context.audioWorklet.addModule(import.meta.url); const dsp = new AudioWorkletNode(context, 'zenfs:dsp'); dsp.connect(context.destination); - dsp.port.postMessage(audioBuffer); // add a click-handler to resume (due to web security) https://goo.gl/7K7WLu document.addEventListener('click', () => { @@ -67,8 +65,7 @@ export async function dsp(options: DspOptions = {}): Promise