Skip to content

Commit

Permalink
Add devices from @zenfs/devices
Browse files Browse the repository at this point in the history
  • Loading branch information
james-pre committed Nov 8, 2024
1 parent 66a8959 commit 1d28b4d
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 0 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
"type": "module",
"homepage": "https://github.com/zen-fs/dom",
"author": "James Prevett <[email protected]> (https://jamespre.dev)",
"contributors": [
"David Konsumer <[email protected]>"
],
"license": "MIT",
"repository": {
"type": "git",
Expand Down
32 changes: 32 additions & 0 deletions src/devices/audioworklet.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* Types pulled from @types/audioworklet */

/* eslint-disable no-var, @typescript-eslint/no-explicit-any */

/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/AudioWorkletProcessor) */
interface AudioWorkletProcessor {
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/AudioWorkletProcessor/port) */
readonly port: MessagePort;

process(inputs: Float32Array[][], outputs: Float32Array[][], parameters: Record<string, Float32Array>): boolean;
}

declare var AudioWorkletProcessor: {
prototype: AudioWorkletProcessor;
new (): AudioWorkletProcessor;
};

interface AudioWorkletProcessorConstructor {
new (options: any): AudioWorkletProcessor;
}

/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/AudioWorkletGlobalScope/currentFrame) */
declare var currentFrame: number;

/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/AudioWorkletGlobalScope/currentTime) */
declare var currentTime: number;

/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/AudioWorkletGlobalScope/sampleRate) */
declare var sampleRate: number;

/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/AudioWorkletGlobalScope/registerProcessor) */
declare function registerProcessor(name: string, processor: AudioWorkletProcessorConstructor): void;
72 changes: 72 additions & 0 deletions src/devices/dsp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/* Credit: David Konsumer */
import type { DeviceDriver, DeviceFile } from '@zenfs/core';
import './audioworklet.d.ts';

if ('AudioWorkletProcessor' in globalThis) {
class Dsp extends AudioWorkletProcessor {
protected buffer?: Float32Array;

public constructor() {
super();
this.port.onmessage = ({ data }: MessageEvent<Float32Array>) => {
this.buffer = new Float32Array(data);
};
}

public process(inputs: Float32Array[][], outputs: Float32Array[][]): boolean {
if (this.buffer && this.buffer.byteLength >= 128) {
outputs[0][0].set(this.buffer.slice(0, 128));
this.buffer = this.buffer.slice(128);
}
return true;
}

public static get parameterDescriptors() {
return [
{
name: 'gain',
defaultValue: 1,
minValue: 0,
maxValue: 1,
automationRate: 'a-rate',
},
];
}
}

registerProcessor('zenfs:dsp', Dsp);
}

export interface DspOptions {
audioContext?: AudioContext;
}

export async function dsp(options: DspOptions = {}): Promise<DeviceDriver<AudioWorkletNode>> {

Check failure on line 44 in src/devices/dsp.ts

View workflow job for this annotation

GitHub Actions / CI

Type 'DeviceDriver' is not generic.
const context = options.audioContext || new AudioContext();

await context.audioWorklet.addModule(import.meta.url);

const dsp = new AudioWorkletNode(context, 'zenfs:dsp');
dsp.connect(context.destination);

// add a click-handler to resume (due to web security) https://goo.gl/7K7WLu
document.addEventListener('click', () => {
if (context.state != 'running') {
void context.resume().catch(() => {});
}
});

return {
name: 'dsp',
init() {
return { data: dsp, major: 14, minor: 3 };
},
read() {
return 0;
},
write(file: DeviceFile, data: Uint8Array): number {
dsp.port.postMessage(data.buffer);
return data.byteLength;
},
};
}
39 changes: 39 additions & 0 deletions src/devices/framebuffer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* Credit: David Konsumer */
import { Errno, ErrnoError } from '@zenfs/core';
import type { DeviceDriver, DeviceFile } from '@zenfs/core';

export interface FramebufferOptions {
canvas?: HTMLCanvasElement | null;
}

let framebufferN = 0;

export function framebuffer({ canvas }: FramebufferOptions = {}): DeviceDriver<CanvasRenderingContext2D> {

Check failure on line 11 in src/devices/framebuffer.ts

View workflow job for this annotation

GitHub Actions / CI

Type 'DeviceDriver' is not generic.
if (!canvas) {
canvas = document.createElement('canvas');
document.body.appendChild(canvas);
}
const ctx = canvas.getContext('2d');

if (!ctx) {
throw new ErrnoError(Errno.EIO, 'Could not get context from canvas whilst initializing frame buffer.');
}

return {
name: 'framebuffer',
init() {
return { data: ctx, major: 29, minor: framebufferN++ };
},
read() {
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;
},
};
}
2 changes: 2 additions & 0 deletions src/devices/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './dsp.js';
export * from './framebuffer.js';

0 comments on commit 1d28b4d

Please sign in to comment.