Skip to content

Commit

Permalink
Fixed framebuffer, dsp
Browse files Browse the repository at this point in the history
  • Loading branch information
james-pre committed Nov 7, 2024
1 parent 15ca560 commit e0b7e88
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 34 deletions.
44 changes: 21 additions & 23 deletions demo/demo.js
Original file line number Diff line number Diff line change
@@ -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);
6 changes: 3 additions & 3 deletions demo/index.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<html>
<head>
<title>ZenFS Devices</title>
<link rel="stylesheet" href="./demo.css" />
<link rel="stylesheet" href="./framebuffer.css" />
</head>
<body>
<p>This will demonstrate drawing to a framebuffer & creating audio:</p>
<p>Framebuffer demo</p>
<canvas id="fb"></canvas>
<script type="module" src="./demo.js"></script>
<script type="module" src="./framebuffer.js"></script>
</body>
</html>
13 changes: 5 additions & 8 deletions src/dsp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ if ('AudioWorkletProcessor' in globalThis) {
public constructor() {
super();
this.port.onmessage = ({ data }: MessageEvent<Float32Array>) => {
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;
}
Expand All @@ -43,13 +43,11 @@ interface DspOptions {

export async function dsp(options: DspOptions = {}): Promise<DeviceDriver<AudioWorkletNode>> {
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', () => {
Expand All @@ -67,8 +65,7 @@ export async function dsp(options: DspOptions = {}): Promise<DeviceDriver<AudioW
return 0;
},
write(file: DeviceFile, data: Uint8Array): number {
new Uint8Array(audioBuffer).set(data);
dsp.port.postMessage(new Float32Array(audioBuffer));
dsp.port.postMessage(data.buffer);
return data.byteLength;
},
};
Expand Down
3 changes: 3 additions & 0 deletions src/framebuffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ export function framebuffer({ canvas }: FramebufferOptions = {}): DeviceDriver<C
return 0;
},
write(file: DeviceFile, data: Uint8Array) {
if (data.byteLength < 4 * canvas.width * canvas.height) {
return 0;
}
const imageData = new ImageData(new Uint8ClampedArray(data), canvas.width, canvas.height);
ctx.putImageData(imageData, 0, 0);
return data.byteLength;
Expand Down

0 comments on commit e0b7e88

Please sign in to comment.