From 2244be4e294133106e5b09bb6fb58095ba516afa Mon Sep 17 00:00:00 2001 From: danigb Date: Sat, 7 Sep 2024 15:04:41 +0200 Subject: [PATCH 1/4] feat: generate dsp from Faust --- packages/dattorro-reverb/README.md | 7 + packages/dattorro-reverb/package.json | 36 +++++ packages/dattorro-reverb/src/_worklet.ts | 119 ++++++++++++++ packages/dattorro-reverb/src/dsp.ts | 189 ++++++++++++++++++++++ packages/dattorro-reverb/src/index.ts | 32 ++++ packages/dattorro-reverb/src/processor.ts | 1 + packages/dattorro-reverb/src/worklet.ts | 64 ++++++++ 7 files changed, 448 insertions(+) create mode 100644 packages/dattorro-reverb/README.md create mode 100644 packages/dattorro-reverb/package.json create mode 100644 packages/dattorro-reverb/src/_worklet.ts create mode 100644 packages/dattorro-reverb/src/dsp.ts create mode 100644 packages/dattorro-reverb/src/index.ts create mode 100644 packages/dattorro-reverb/src/processor.ts create mode 100644 packages/dattorro-reverb/src/worklet.ts diff --git a/packages/dattorro-reverb/README.md b/packages/dattorro-reverb/README.md new file mode 100644 index 0000000..51472b8 --- /dev/null +++ b/packages/dattorro-reverb/README.md @@ -0,0 +1,7 @@ +# @synthlet/dattorro-reverb + +> DattorroReverb + +Part of [Synthlet](https://github.com/danigb/synthlet) + +This is reverb is generated using Faust. All credits to Jakob Zerbian. diff --git a/packages/dattorro-reverb/package.json b/packages/dattorro-reverb/package.json new file mode 100644 index 0000000..e024740 --- /dev/null +++ b/packages/dattorro-reverb/package.json @@ -0,0 +1,36 @@ +{ + "name": "@synthlet/dattorro-reverb", + "version": "0.1.0", + "description": "Dattorro reverb as an audio worklet", + "keywords": [ + "reverb", + "dattorro", + "modular", + "synthesis", + "synthlet" + ], + "main": "dist/index.js", + "module": "dist/index.mjs", + "types": "dist/index.d.ts", + "files": [ + "dist" + ], + "author": "danigb@gmail.com", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "devDependencies": { + "@types/jest": "^29.5.11", + "jest": "^29.7.0", + "ts-jest": "^29.1.1" + }, + "jest": { + "preset": "ts-jest" + }, + "scripts": { + "worklet": "esbuild src/worklet.ts --bundle --minify | sed -e 's/^/export const PROCESSOR = \\`/' -e 's/$/\\`;/' > src/processor.ts", + "lib": "tsup src/index.ts --sourcemap --dts --format esm,cjs", + "build": "npm run worklet && npm run lib" + } +} diff --git a/packages/dattorro-reverb/src/_worklet.ts b/packages/dattorro-reverb/src/_worklet.ts new file mode 100644 index 0000000..9a26891 --- /dev/null +++ b/packages/dattorro-reverb/src/_worklet.ts @@ -0,0 +1,119 @@ +// DON'T EDIT THIS FILE unless inside scripts/_worklet.ts +// use ./scripts/copy_files.ts to copy this file to the right place +// the goal is to avoid external dependencies on packages + +// A "Connector" is a function that takes an AudioContext and returns an AudioNode +// or an custom object with a connect method (that returns a disconnect method) +export type Connector = (context: AudioContext) => N; + +export type ParamInput = number | Connector | AudioNode; + +type CreateWorkletOptions = { + processorName: string; + paramNames: readonly string[]; + workletOptions: (params: Partial

) => AudioWorkletNodeOptions; + postCreate?: (node: N) => void; +}; + +export type Disposable = N & { dispose: () => void }; + +export function createWorkletConstructor< + N extends AudioWorkletNode, + P extends Record +>(options: CreateWorkletOptions) { + return ( + audioContext: AudioContext, + inputs: Partial

= {} + ): Disposable => { + const node = new AudioWorkletNode( + audioContext, + options.processorName, + options.workletOptions(inputs) + ) as N; + + (node as any).__PROCESSOR_NAME__ = options.processorName; + const connected = connectParams(node, options.paramNames, inputs); + options.postCreate?.(node); + return disposable(node, connected); + }; +} + +type ConnectedUnit = AudioNode | (() => void); + +export function connectParams( + node: any, + paramNames: readonly string[], + inputs: any +): ConnectedUnit[] { + const connected: ConnectedUnit[] = []; + + for (const paramName of paramNames) { + if (node.parameters) { + node[paramName] = node.parameters.get(paramName); + } + const param = node[paramName]; + if (!param) throw Error("Invalid param name: " + paramName); + const input = inputs[paramName]; + if (typeof input === "number") { + param.value = input; + } else if (input instanceof AudioNode) { + param.value = 0; + input.connect(param); + connected.push(input); + } else if (typeof input === "function") { + param.value = 0; + const source = input(node.context); + source.connect(param); + connected.push(source); + } + } + + return connected; +} + +export function disposable( + node: N, + dependencies?: ConnectedUnit[] +): Disposable { + let disposed = false; + return Object.assign(node, { + dispose() { + if (disposed) return; + disposed = true; + + node.disconnect(); + (node as any).port?.postMessage({ type: "DISPOSE" }); + if (!dependencies) return; + + while (dependencies.length) { + const conn = dependencies.pop(); + if (conn instanceof AudioNode) { + if (typeof (conn as any).dispose === "function") { + (conn as any).dispose?.(); + } else { + conn.disconnect(); + } + } else if (typeof conn === "function") { + conn(); + } + } + }, + }); +} + +export function createRegistrar(processorName: string, processor: string) { + return function (context: AudioContext): Promise { + const key = "__" + processorName + "__"; + if (key in context) return (context as any)[key]; + + if (!context.audioWorklet || !context.audioWorklet.addModule) { + throw Error("AudioWorklet not supported"); + } + + const blob = new Blob([processor], { type: "application/javascript" }); + const url = URL.createObjectURL(blob); + const promise = context.audioWorklet.addModule(url); + (context as any)[key] = promise; + return promise; + }; +} diff --git a/packages/dattorro-reverb/src/dsp.ts b/packages/dattorro-reverb/src/dsp.ts new file mode 100644 index 0000000..5355ada --- /dev/null +++ b/packages/dattorro-reverb/src/dsp.ts @@ -0,0 +1,189 @@ +export type UpdateFn = ReturnType["update"]; +export type ComputeFn = ReturnType["compute"]; + +// This is a dsp code generated from Faust to test if the Faust -> Rust -> Typescript conversion works +export function createDsp(sampleRate: number) { + let fConst0 = 44.1 / sampleRate; + let fConst1 = 1 - fConst0; + let fVslider0 = -6.0; + let fVslider1 = 0.0; + let fVslider2 = 0.7; + let fVslider3 = 0.625; + let fVslider4 = 0.625; + let fVslider5 = 0.7; + let fVslider6 = 0.625; + let fVslider7 = 0.625; + let fVslider8 = 0.625; + let IOTA0 = 0; + let fRec0 = [0.0, 0.0]; + let fRec1 = [0.0, 0.0]; + let fRec13 = [0.0, 0.0]; + let fRec12 = [0.0, 0.0, 0.0]; + let fRec14 = [0.0, 0.0]; + let fVec0 = new Array(256).fill(0.0); + let fRec10 = [0.0, 0.0]; + let fVec1 = new Array(128).fill(0.0); + let fRec8 = [0.0, 0.0]; + let fRec15 = [0.0, 0.0]; + let fVec2 = new Array(512).fill(0.0); + let fRec6 = [0.0, 0.0]; + let fVec3 = new Array(512).fill(0.0); + let fRec4 = [0.0, 0.0]; + let fRec16 = [0.0, 0.0]; + let fRec20 = [0.0, 0.0]; + let fRec23 = [0.0, 0.0]; + let fVec4 = new Array(1024).fill(0.0); + let fRec21 = [0.0, 0.0]; + let fVec5 = new Array(8192).fill(0.0); + let fRec19 = [0.0, 0.0]; + let fRec24 = [0.0, 0.0]; + let fVec6 = new Array(4096).fill(0.0); + let fRec17 = [0.0, 0.0]; + let fVec7 = new Array(4096).fill(0.0); + let fRec2 = [0.0, 0.0]; + let fVec8 = new Array(1024).fill(0.0); + let fRec28 = [0.0, 0.0]; + let fVec9 = new Array(8192).fill(0.0); + let fRec27 = [0.0, 0.0]; + let fVec10 = new Array(2048).fill(0.0); + let fRec25 = [0.0, 0.0]; + let fVec11 = new Array(2048).fill(0.0); + let fRec3 = [0.0, 0.0]; + + function update( + lpFilter: number, + diffussion1: number, + diffussion2: number, + feedback1: number, + feedback2: number, + decayRate: number, + damping: number, + dryWet: number, + volume: number + ) { + fVslider0 = lpFilter; + fVslider1 = diffussion1; + fVslider2 = diffussion2; + fVslider3 = feedback1; + fVslider4 = feedback2; + fVslider5 = decayRate; + fVslider6 = damping; + fVslider7 = dryWet; + fVslider8 = volume; + } + + function compute( + inputs: Float32Array[], + outputs: Float32Array[], + count: number + ) { + let inputs0 = inputs[0]; + let inputs1 = inputs.length === 1 ? inputs[0] : inputs[1]; + let outputs0 = outputs[0]; + let outputs1 = outputs[1]; + + let fSlow0 = fConst0 * Math.pow(10, 0.05 * fVslider0); + let fSlow1 = fConst0 * fVslider1; + let fSlow2 = fConst0 * fVslider2; + let fSlow3 = fConst0 * fVslider3; + let fSlow4 = fConst0 * fVslider4; + let fSlow5 = fConst0 * fVslider5; + let fSlow6 = fConst0 * fVslider6; + let fSlow7 = fConst0 * fVslider7; + let fSlow8 = fConst0 * fVslider8; + + for (let i = 0; i < count; i++) { + let input0 = inputs0[i]; + let input1 = inputs1[i]; + + fRec0[0] = fSlow0 + fConst1 * fRec0[1]; + let fTemp0 = input0; + fRec1[0] = fSlow1 + fConst1 * fRec1[1]; + let fTemp1 = fRec1[0] + 1.0; + let fTemp2 = 1.0 - 0.5 * fTemp1; + fRec13[0] = fSlow2 + fConst1 * fRec13[1]; + let fTemp3 = input1; + fRec12[0] = + (1.0 - fRec13[0]) * fRec12[2] + 0.5 * (fTemp0 + fTemp3) * fRec13[0]; + fRec14[0] = fSlow3 + fConst1 * fRec14[1]; + let fTemp4 = fRec12[0] - fRec14[0] * fRec10[1]; + fVec0[IOTA0 & 255] = fTemp4; + fRec10[0] = fVec0[(IOTA0 - 142) & 255]; + let fRec11 = fRec14[0] * fTemp4; + let fTemp5 = fRec11 + fRec10[1] - fRec14[0] * fRec8[1]; + fVec1[IOTA0 & 127] = fTemp5; + fRec8[0] = fVec1[(IOTA0 - 107) & 127]; + let fRec9 = fRec14[0] * fTemp5; + fRec15[0] = fSlow4 + fConst1 * fRec15[1]; + let fTemp6 = fRec9 + fRec8[1] - fRec15[0] * fRec6[1]; + fVec2[IOTA0 & 511] = fTemp6; + fRec6[0] = fVec2[(IOTA0 - 379) & 511]; + let fRec7 = fRec15[0] * fTemp6; + let fTemp7 = fRec7 + fRec6[1] - fRec15[0] * fRec4[1]; + fVec3[IOTA0 & 511] = fTemp7; + fRec4[0] = fVec3[(IOTA0 - 277) & 511]; + let fRec5 = fRec15[0] * fTemp7; + + fRec16[0] = fSlow5 + fConst1 * fRec16[1]; + fRec20[0] = fSlow6 + fConst1 * fRec20[1]; + let fTemp8 = 1.0 - fRec20[0]; + fRec23[0] = fSlow7 + fConst1 * fRec23[1]; + let fTemp9 = fRec23[0] * fRec21[1] + fRec3[1]; + fVec4[IOTA0 & 1023] = fTemp9; + fRec21[0] = fVec4[(IOTA0 - 908) & 1023]; + let fRec22 = -(fRec23[0] * fTemp9); + fVec5[IOTA0 & 8191] = fRec22 + fRec21[1]; + fRec19[0] = fRec20[0] * fRec19[1] + fTemp8 * fVec5[(IOTA0 - 4217) & 8191]; + fRec24[0] = fSlow8 + fConst1 * fRec24[1]; + let fTemp10 = fRec19[0] * fRec16[0] - fRec24[0] * fRec17[1]; + fVec6[IOTA0 & 4095] = fTemp10; + fRec17[0] = fVec6[(IOTA0 - 2656) & 4095]; + let fRec18 = fRec24[0] * fTemp10; + fVec7[IOTA0 & 4095] = fRec18 + fRec17[1]; + fRec2[0] = fRec5 + fRec16[0] * fVec7[(IOTA0 - 2656) & 4095] + fRec4[1]; + let fTemp11 = fRec23[0] * fRec28[1] + fRec2[1]; + fVec8[IOTA0 & 1023] = fTemp11; + fRec28[0] = fVec8[(IOTA0 - 672) & 1023]; + let fRec29 = -(fRec23[0] * fTemp11); + fVec9[IOTA0 & 8191] = fRec29 + fRec28[1]; + fRec27[0] = fRec20[0] * fRec27[1] + fTemp8 * fVec9[(IOTA0 - 4453) & 8191]; + let fTemp12 = fRec16[0] * fRec27[0] - fRec24[0] * fRec25[1]; + fVec10[IOTA0 & 2047] = fTemp12; + fRec25[0] = fVec10[(IOTA0 - 1800) & 2047]; + let fRec26 = fRec24[0] * fTemp12; + fVec11[IOTA0 & 2047] = fRec26 + fRec25[1]; + fRec3[0] = fRec5 + fRec4[1] + fRec16[0] * fVec11[(IOTA0 - 1800) & 2047]; + + outputs0[i] = fRec0[0] * (fTemp0 * fTemp2 + 0.5 * fTemp1 * fRec2[0]); + outputs1[i] = fRec0[0] * (fTemp3 * fTemp2 + 0.5 * fTemp1 * fRec3[0]); + + // Update history + fRec0[1] = fRec0[0]; + fRec1[1] = fRec1[0]; + fRec13[1] = fRec13[0]; + fRec12[2] = fRec12[1]; + fRec12[1] = fRec12[0]; + fRec14[1] = fRec14[0]; + IOTA0++; + fRec10[1] = fRec10[0]; + fRec8[1] = fRec8[0]; + fRec15[1] = fRec15[0]; + fRec6[1] = fRec6[0]; + fRec4[1] = fRec4[0]; + fRec16[1] = fRec16[0]; + fRec20[1] = fRec20[0]; + fRec23[1] = fRec23[0]; + fRec21[1] = fRec21[0]; + fRec19[1] = fRec19[0]; + fRec24[1] = fRec24[0]; + fRec17[1] = fRec17[0]; + fRec2[1] = fRec2[0]; + fRec28[1] = fRec28[0]; + fRec27[1] = fRec27[0]; + fRec25[1] = fRec25[0]; + fRec3[1] = fRec3[0]; + } + } + + return { update, compute }; +} diff --git a/packages/dattorro-reverb/src/index.ts b/packages/dattorro-reverb/src/index.ts new file mode 100644 index 0000000..0250abd --- /dev/null +++ b/packages/dattorro-reverb/src/index.ts @@ -0,0 +1,32 @@ +import { + createRegistrar, + createWorkletConstructor, + ParamInput, +} from "./_worklet"; +import { PROCESSOR } from "./processor"; + +export const registerDattorroReverbWorklet = createRegistrar( + "DATTORRO_REVERB", + PROCESSOR +); + +export type DattorroReverbInputs = { + trigger: ParamInput; +}; + +export type DattorroReverbWorkletNode = AudioWorkletNode & { + trigger: AudioParam; + dispose(): void; +}; + +export const DattorroReverb = createWorkletConstructor< + DattorroReverbWorkletNode, + DattorroReverbInputs +>({ + processorName: "DattorroReverbProcessor", + paramNames: ["trigger"], + workletOptions: () => ({ + numberOfInputs: 0, + numberOfOutputs: 1, + }), +}); diff --git a/packages/dattorro-reverb/src/processor.ts b/packages/dattorro-reverb/src/processor.ts new file mode 100644 index 0000000..3f7ef2a --- /dev/null +++ b/packages/dattorro-reverb/src/processor.ts @@ -0,0 +1 @@ +export const PROCESSOR = `"use strict";(()=>{function V0(M){let t=44.1/M,l=1-t,f=-6,q=0,z=.7,B=.625,G=.625,H=.7,J=.625,K=.625,L=.625,e=0,s=[0,0],d=[0,0],p=[0,0],o=[0,0,0],r=[0,0],N=new Array(256).fill(0),w=[0,0],Q=new Array(128).fill(0),V=[0,0],c=[0,0],X=new Array(512).fill(0),A=[0,0],Y=new Array(512).fill(0),m=[0,0],n=[0,0],u=[0,0],i=[0,0],Z=new Array(1024).fill(0),T=[0,0],_=new Array(8192).fill(0),b=[0,0],a=[0,0],$=new Array(4096).fill(0),D=[0,0],e0=new Array(4096).fill(0),h=[0,0],t0=new Array(1024).fill(0),S=[0,0],l0=new Array(8192).fill(0),F=[0,0],f0=new Array(2048).fill(0),g=[0,0],r0=new Array(2048).fill(0),C=[0,0];function A0(R,k,x,O,P,U,W,v,I){f=R,q=k,z=x,B=O,G=P,H=U,J=W,K=v,L=I}function T0(R,k,x){let O=R[0],P=R.length===1?R[0]:R[1],U=k[0],W=k[1],v=t*Math.pow(10,.05*f),I=t*q,b0=t*z,D0=t*B,h0=t*G,S0=t*H,F0=t*J,g0=t*K,C0=t*L;for(let y=0;y{switch(f.data.type){case"DISPOSE":this.r=!1;break}}}process(t,l,f){return this.u(f.filter[0],f.inputDiffusion1[0],f.inputDiffusion2[0],f.decayDiffusion1[0],f.decayDiffusion2[0],f.decay[0],f.damping[0],f.dryWet[0],f.level[0]),this.c(t[0],l[0],l[0][0].length),this.r}static get parameterDescriptors(){return[["filter",.7,0,1],["inputDiffusion1",.75,0,1],["inputDiffusion2",.625,0,1],["decayDiffusion1",.7,0,.999999],["decayDiffusion2",.5,0,.999999],["decay",.7,0,1],["damping",.25,0,1],["dryWet",1,-1,1],["level",0,0,1]].map(t=>new Object({name:t[0],defaultValue:t[1],minValue:t[2],maxValue:t[3],automationRate:"k-rate"}))}};registerProcessor("DattorroReverbProcessor",E);})();`; diff --git a/packages/dattorro-reverb/src/worklet.ts b/packages/dattorro-reverb/src/worklet.ts new file mode 100644 index 0000000..08436a8 --- /dev/null +++ b/packages/dattorro-reverb/src/worklet.ts @@ -0,0 +1,64 @@ +import { ComputeFn, createDsp, UpdateFn } from "./dsp"; + +export class DattorroReverbProcessor extends AudioWorkletProcessor { + r: boolean; // running + u: UpdateFn; + c: ComputeFn; + + constructor() { + super(); + this.r = true; + const { update, compute } = createDsp(sampleRate); + this.u = update; + this.c = compute; + + this.port.onmessage = (event) => { + switch (event.data.type) { + case "DISPOSE": + this.r = false; + break; + } + }; + } + + process(inputs: Float32Array[][], outputs: Float32Array[][], p: any) { + this.u( + p.filter[0], + p.inputDiffusion1[0], + p.inputDiffusion2[0], + p.decayDiffusion1[0], + p.decayDiffusion2[0], + p.decay[0], + p.damping[0], + p.dryWet[0], + p.level[0] + ); + this.c(inputs[0], outputs[0], outputs[0][0].length); + return this.r; + } + + static get parameterDescriptors() { + return [ + ["filter", 0.7, 0, 1], + ["inputDiffusion1", 0.75, 0, 1], + ["inputDiffusion2", 0.625, 0, 1], + ["decayDiffusion1", 0.7, 0, 0.999999], + ["decayDiffusion2", 0.5, 0, 0.999999], + ["decay", 0.7, 0, 1], + ["damping", 0.25, 0, 1], + ["dryWet", 1, -1, 1], // -1 dry, 0 equal, 1 wet + ["level", 0.0, 0, 1], // decibels + ].map( + (x) => + new Object({ + name: x[0], + defaultValue: x[1], + minValue: x[2], + maxValue: x[3], + automationRate: "k-rate", + }) + ); + } +} + +registerProcessor("DattorroReverbProcessor", DattorroReverbProcessor); From ae748a24a329591c0367fc5706d9d073b9c44d79 Mon Sep 17 00:00:00 2001 From: danigb Date: Sat, 7 Sep 2024 17:08:49 +0200 Subject: [PATCH 2/4] feat: datorro example --- package-lock.json | 65 ++++++++++--------- packages/dattorro-reverb/package.json | 2 +- packages/dattorro-reverb/src/index.ts | 35 +++++++++-- packages/dattorro-reverb/src/processor.ts | 2 +- packages/dattorro-reverb/src/worklet.ts | 12 +++- packages/synthlet/package.json | 2 +- packages/synthlet/src/index.ts | 3 + site/.source/index.js | 55 ++++++++-------- site/content/docs/(effects)/dattorro.mdx | 27 ++++++++ site/examples/DattorroExample.tsx | 76 +++++++++++++++++++++++ site/examples/components/ExamplePane.tsx | 10 ++- 11 files changed, 223 insertions(+), 66 deletions(-) create mode 100644 site/content/docs/(effects)/dattorro.mdx create mode 100644 site/examples/DattorroExample.tsx diff --git a/package-lock.json b/package-lock.json index 027a0cd..a453b9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -706,12 +706,12 @@ } }, "node_modules/@changesets/logger": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.1.0.tgz", - "integrity": "sha512-pBrJm4CQm9VqFVwWnSqKEfsS2ESnwqwH+xR7jETxIErZcfd1u2zBSqrHbRHR7xjhSgep9x2PSKFKY//FAshA3g==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.1.1.tgz", + "integrity": "sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==", "dev": true, "dependencies": { - "chalk": "^2.1.0" + "picocolors": "^1.1.0" } }, "node_modules/@changesets/parse": { @@ -754,12 +754,11 @@ } }, "node_modules/@changesets/should-skip-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/@changesets/should-skip-package/-/should-skip-package-0.1.0.tgz", - "integrity": "sha512-FxG6Mhjw7yFStlSM7Z0Gmg3RiyQ98d/9VpQAZ3Fzr59dCOM9G6ZdYbjiSAt0XtFr9JR5U2tBaJWPjrkGGc618g==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@changesets/should-skip-package/-/should-skip-package-0.1.1.tgz", + "integrity": "sha512-H9LjLbF6mMHLtJIc/eHR9Na+MifJ3VxtgP/Y+XLn4BF7tDTEN1HNYtH6QMcjP1uxp9sjaFYmW8xqloaCi/ckTg==", "dev": true, "dependencies": { - "@babel/runtime": "^7.20.1", "@changesets/types": "^6.0.0", "@manypkg/get-packages": "^1.1.3" } @@ -2321,8 +2320,8 @@ "resolved": "packages/clock", "link": true }, - "node_modules/@synthlet/drum8": { - "resolved": "packages/drum8", + "node_modules/@synthlet/dattorro-reverb": { + "resolved": "packages/dattorro-reverb", "link": true }, "node_modules/@synthlet/euclid": { @@ -3669,7 +3668,7 @@ } }, "node_modules/get-package-type": { - "version": "0.0.0", + "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, @@ -6286,9 +6285,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", "dev": true }, "node_modules/picomatch": { @@ -7715,7 +7714,7 @@ } }, "node_modules/yocto-queue": { - "version": "0.0.0", + "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, @@ -7728,7 +7727,7 @@ }, "packages/ad": { "name": "@synthlet/ad", - "version": "0.0.0", + "version": "0.1.0", "license": "MIT", "devDependencies": { "@types/jest": "^29.5.11", @@ -7738,7 +7737,7 @@ }, "packages/adsr": { "name": "@synthlet/adsr", - "version": "0.0.0", + "version": "0.1.0", "license": "MIT", "devDependencies": { "@types/jest": "^29.5.12", @@ -7758,7 +7757,7 @@ }, "packages/chorus-t": { "name": "@synthlet/chorus-t", - "version": "0.0.0", + "version": "0.1.0", "license": "MIT", "devDependencies": { "@types/jest": "^29.5.12", @@ -7768,7 +7767,7 @@ }, "packages/clip-amp": { "name": "@synthlet/clip-amp", - "version": "0.0.0", + "version": "0.1.0", "license": "MIT", "devDependencies": { "@types/jest": "^29.5.11", @@ -7778,6 +7777,15 @@ }, "packages/clock": { "name": "@synthlet/clock", + "version": "0.1.0", + "license": "MIT", + "devDependencies": { + "@types/jest": "^29.5.11", + "jest": "^29.7.0", + "ts-jest": "^29.1.1" + } + }, + "packages/dattorro-reverb": { "version": "0.0.0", "license": "MIT", "devDependencies": { @@ -7789,6 +7797,7 @@ "packages/drum8": { "name": "@synthlet/drum8", "version": "0.0.0", + "extraneous": true, "license": "MIT", "devDependencies": { "@types/jest": "^29.5.11", @@ -7798,7 +7807,7 @@ }, "packages/euclid": { "name": "@synthlet/euclid", - "version": "0.0.0", + "version": "0.1.0", "license": "MIT", "devDependencies": { "@types/jest": "^29.5.11", @@ -7808,7 +7817,7 @@ }, "packages/impulse": { "name": "@synthlet/impulse", - "version": "0.0.0", + "version": "0.1.0", "license": "MIT", "devDependencies": { "@types/jest": "^29.5.11", @@ -7818,7 +7827,7 @@ }, "packages/lfo": { "name": "@synthlet/lfo", - "version": "0.0.0", + "version": "0.1.0", "license": "MIT", "devDependencies": { "@types/jest": "^29.5.12", @@ -7828,7 +7837,7 @@ }, "packages/noise": { "name": "@synthlet/noise", - "version": "0.0.0", + "version": "0.1.0", "license": "MIT", "devDependencies": { "@types/jest": "^29.5.11", @@ -7838,7 +7847,7 @@ }, "packages/param": { "name": "@synthlet/param", - "version": "0.0.0", + "version": "0.1.0", "license": "MIT", "devDependencies": { "@types/jest": "^29.5.11", @@ -7848,7 +7857,7 @@ }, "packages/polyblep-oscillator": { "name": "@synthlet/polyblep-oscillator", - "version": "0.0.0", + "version": "0.1.0", "license": "MIT", "devDependencies": { "@types/jest": "^29.5.11", @@ -7858,7 +7867,7 @@ }, "packages/state-variable-filter": { "name": "@synthlet/state-variable-filter", - "version": "0.0.0", + "version": "0.1.0", "license": "MIT", "devDependencies": { "@types/jest": "^29.5.11", @@ -7875,7 +7884,7 @@ "@synthlet/chorus-t": "^0.1.0", "@synthlet/clip-amp": "^0.1.0", "@synthlet/clock": "^0.1.0", - "@synthlet/drum8": "^0.1.0", + "@synthlet/dattorro-reverb": "^0.0.0", "@synthlet/euclid": "^0.1.0", "@synthlet/impulse": "^0.1.0", "@synthlet/lfo": "^0.1.0", @@ -7888,7 +7897,7 @@ }, "packages/wavetable-oscillator": { "name": "@synthlet/wavetable-oscillator", - "version": "0.0.0", + "version": "0.1.0", "license": "MIT", "devDependencies": { "@types/jest": "^29.5.11", diff --git a/packages/dattorro-reverb/package.json b/packages/dattorro-reverb/package.json index e024740..ce26525 100644 --- a/packages/dattorro-reverb/package.json +++ b/packages/dattorro-reverb/package.json @@ -1,6 +1,6 @@ { "name": "@synthlet/dattorro-reverb", - "version": "0.1.0", + "version": "0.0.0", "description": "Dattorro reverb as an audio worklet", "keywords": [ "reverb", diff --git a/packages/dattorro-reverb/src/index.ts b/packages/dattorro-reverb/src/index.ts index 0250abd..e07d1a6 100644 --- a/packages/dattorro-reverb/src/index.ts +++ b/packages/dattorro-reverb/src/index.ts @@ -11,11 +11,27 @@ export const registerDattorroReverbWorklet = createRegistrar( ); export type DattorroReverbInputs = { - trigger: ParamInput; + filter?: ParamInput; + inputDiffusion1?: ParamInput; + inputDiffusion2?: ParamInput; + decayDiffusion1?: ParamInput; + decayDiffusion2?: ParamInput; + decay?: ParamInput; + damping?: ParamInput; + // dryWet?: ParamInput; + // level?: ParamInput; }; export type DattorroReverbWorkletNode = AudioWorkletNode & { - trigger: AudioParam; + filter: AudioParam; + inputDiffusion1: AudioParam; + inputDiffusion2: AudioParam; + decayDiffusion1: AudioParam; + decayDiffusion2: AudioParam; + decay: AudioParam; + damping: AudioParam; + // dryWet: AudioParam; + // level: AudioParam; dispose(): void; }; @@ -24,9 +40,20 @@ export const DattorroReverb = createWorkletConstructor< DattorroReverbInputs >({ processorName: "DattorroReverbProcessor", - paramNames: ["trigger"], + paramNames: [ + "filter", + "inputDiffusion1", + "inputDiffusion2", + "decayDiffusion1", + "decayDiffusion2", + "decay", + "damping", + // "dryWet", + // "level", + ], workletOptions: () => ({ - numberOfInputs: 0, + numberOfInputs: 1, numberOfOutputs: 1, + outputChannelCount: [2], }), }); diff --git a/packages/dattorro-reverb/src/processor.ts b/packages/dattorro-reverb/src/processor.ts index 3f7ef2a..0899ed0 100644 --- a/packages/dattorro-reverb/src/processor.ts +++ b/packages/dattorro-reverb/src/processor.ts @@ -1 +1 @@ -export const PROCESSOR = `"use strict";(()=>{function V0(M){let t=44.1/M,l=1-t,f=-6,q=0,z=.7,B=.625,G=.625,H=.7,J=.625,K=.625,L=.625,e=0,s=[0,0],d=[0,0],p=[0,0],o=[0,0,0],r=[0,0],N=new Array(256).fill(0),w=[0,0],Q=new Array(128).fill(0),V=[0,0],c=[0,0],X=new Array(512).fill(0),A=[0,0],Y=new Array(512).fill(0),m=[0,0],n=[0,0],u=[0,0],i=[0,0],Z=new Array(1024).fill(0),T=[0,0],_=new Array(8192).fill(0),b=[0,0],a=[0,0],$=new Array(4096).fill(0),D=[0,0],e0=new Array(4096).fill(0),h=[0,0],t0=new Array(1024).fill(0),S=[0,0],l0=new Array(8192).fill(0),F=[0,0],f0=new Array(2048).fill(0),g=[0,0],r0=new Array(2048).fill(0),C=[0,0];function A0(R,k,x,O,P,U,W,v,I){f=R,q=k,z=x,B=O,G=P,H=U,J=W,K=v,L=I}function T0(R,k,x){let O=R[0],P=R.length===1?R[0]:R[1],U=k[0],W=k[1],v=t*Math.pow(10,.05*f),I=t*q,b0=t*z,D0=t*B,h0=t*G,S0=t*H,F0=t*J,g0=t*K,C0=t*L;for(let y=0;y{switch(f.data.type){case"DISPOSE":this.r=!1;break}}}process(t,l,f){return this.u(f.filter[0],f.inputDiffusion1[0],f.inputDiffusion2[0],f.decayDiffusion1[0],f.decayDiffusion2[0],f.decay[0],f.damping[0],f.dryWet[0],f.level[0]),this.c(t[0],l[0],l[0][0].length),this.r}static get parameterDescriptors(){return[["filter",.7,0,1],["inputDiffusion1",.75,0,1],["inputDiffusion2",.625,0,1],["decayDiffusion1",.7,0,.999999],["decayDiffusion2",.5,0,.999999],["decay",.7,0,1],["damping",.25,0,1],["dryWet",1,-1,1],["level",0,0,1]].map(t=>new Object({name:t[0],defaultValue:t[1],minValue:t[2],maxValue:t[3],automationRate:"k-rate"}))}};registerProcessor("DattorroReverbProcessor",E);})();`; +export const PROCESSOR = `"use strict";(()=>{function V0(z){let t=44.1/z,f=1-t,l=-6,w=0,s=.7,B=.625,G=.625,H=.7,J=.625,K=.625,L=.625,e=0,p=[0,0],V=[0,0],m=[0,0],o=[0,0,0],r=[0,0],N=new Array(256).fill(0),A=[0,0],Q=new Array(128).fill(0),T=[0,0],c=[0,0],X=new Array(512).fill(0),h=[0,0],Y=new Array(512).fill(0),R=[0,0],n=[0,0],u=[0,0],i=[0,0],Z=new Array(1024).fill(0),b=[0,0],_=new Array(8192).fill(0),D=[0,0],a=[0,0],$=new Array(4096).fill(0),S=[0,0],e0=new Array(4096).fill(0),F=[0,0],t0=new Array(1024).fill(0),g=[0,0],l0=new Array(8192).fill(0),C=[0,0],f0=new Array(2048).fill(0),k=[0,0],r0=new Array(2048).fill(0),x=[0,0];function A0(y,O,P,U,W,v,I,j,E){l=y,w=O,s=P,B=U,G=W,H=v,J=I,K=j,L=E}function T0(y,O,P){let U=y[0],W=y.length===1?y[0]:y[1],v=O[0],I=O[1],j=t*Math.pow(10,.05*l),E=t*w,h0=t*s,b0=t*B,D0=t*G,S0=t*H,F0=t*J,g0=t*K,C0=t*L;for(let d=0;d{switch(l.data.type){case"DISPOSE":this.r=!1;break}}}process(t,f,l){this.u(l.filter[0],l.inputDiffusion1[0],l.inputDiffusion2[0],l.decayDiffusion1[0],l.decayDiffusion2[0],l.decay[0],l.damping[0],l.dryWet[0],l.level[0]);let w=t[0],s=f[0];return w.length===0||s.length===0?this.r:(this.c(w,s,s[0].length),this.r)}static get parameterDescriptors(){return[["filter",.7,0,1],["inputDiffusion1",.75,0,1],["inputDiffusion2",.625,0,1],["decayDiffusion1",.7,0,.999999],["decayDiffusion2",.5,0,.999999],["decay",.5,0,1],["damping",.25,0,1],["dryWet",1,-1,1],["level",0,0,1]].map(t=>new Object({name:t[0],defaultValue:t[1],minValue:t[2],maxValue:t[3],automationRate:"k-rate"}))}};registerProcessor("DattorroReverbProcessor",q);})();`; diff --git a/packages/dattorro-reverb/src/worklet.ts b/packages/dattorro-reverb/src/worklet.ts index 08436a8..c3e9b97 100644 --- a/packages/dattorro-reverb/src/worklet.ts +++ b/packages/dattorro-reverb/src/worklet.ts @@ -33,7 +33,15 @@ export class DattorroReverbProcessor extends AudioWorkletProcessor { p.dryWet[0], p.level[0] ); - this.c(inputs[0], outputs[0], outputs[0][0].length); + + const in1 = inputs[0]; + const out1 = outputs[0]; + + if (in1.length === 0 || out1.length === 0) { + return this.r; + } + + this.c(in1, out1, out1[0].length); return this.r; } @@ -44,7 +52,7 @@ export class DattorroReverbProcessor extends AudioWorkletProcessor { ["inputDiffusion2", 0.625, 0, 1], ["decayDiffusion1", 0.7, 0, 0.999999], ["decayDiffusion2", 0.5, 0, 0.999999], - ["decay", 0.7, 0, 1], + ["decay", 0.5, 0, 1], ["damping", 0.25, 0, 1], ["dryWet", 1, -1, 1], // -1 dry, 0 equal, 1 wet ["level", 0.0, 0, 1], // decibels diff --git a/packages/synthlet/package.json b/packages/synthlet/package.json index 671da19..d145c71 100644 --- a/packages/synthlet/package.json +++ b/packages/synthlet/package.json @@ -25,7 +25,7 @@ "@synthlet/chorus-t": "^0.1.0", "@synthlet/clip-amp": "^0.1.0", "@synthlet/clock": "^0.1.0", - "@synthlet/drum8": "^0.0.0", + "@synthlet/dattorro-reverb": "^0.0.0", "@synthlet/euclid": "^0.1.0", "@synthlet/impulse": "^0.1.0", "@synthlet/lfo": "^0.1.0", diff --git a/packages/synthlet/src/index.ts b/packages/synthlet/src/index.ts index d78ac97..21baa98 100644 --- a/packages/synthlet/src/index.ts +++ b/packages/synthlet/src/index.ts @@ -3,6 +3,7 @@ import { registerAdsrWorklet } from "@synthlet/adsr"; import { registerChorusTWorklet } from "@synthlet/chorus-t"; import { registerClipAmpWorklet } from "@synthlet/clip-amp"; import { registerClockWorklet } from "@synthlet/clock"; +import { registerDattorroReverbWorklet } from "@synthlet/dattorro-reverb"; import { registerEuclidWorklet } from "@synthlet/euclid"; import { registerImpulseWorklet } from "@synthlet/impulse"; import { registerLfoWorklet } from "@synthlet/lfo"; @@ -17,6 +18,7 @@ export * from "@synthlet/adsr"; export * from "@synthlet/chorus-t"; export * from "@synthlet/clip-amp"; export * from "@synthlet/clock"; +export * from "@synthlet/dattorro-reverb"; export * from "@synthlet/euclid"; export * from "@synthlet/impulse"; export * from "@synthlet/lfo"; @@ -39,6 +41,7 @@ export function registerSynthlet(context: AudioContext): Promise { registerChorusTWorklet(context), registerClipAmpWorklet(context), registerClockWorklet(context), + registerDattorroReverbWorklet(context), registerEuclidWorklet(context), registerImpulseWorklet(context), registerPolyblepOscillatorWorklet(context), diff --git a/site/.source/index.js b/site/.source/index.js index b0756d1..db484a9 100644 --- a/site/.source/index.js +++ b/site/.source/index.js @@ -1,28 +1,29 @@ import { toRuntime } from "fumadocs-mdx" -import * as file_0 from "../content/docs/meta.json?collection=meta&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_1 from "../content/docs/(effects)/meta.json?collection=meta&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_2 from "../content/docs/(modifiers)/meta.json?collection=meta&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_3 from "../content/docs/(sequencers)/meta.json?collection=meta&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_4 from "../content/docs/(sources)/meta.json?collection=meta&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_5 from "../content/docs/(modulators)/meta.json?collection=meta&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_6 from "../content/docs/dsl.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_7 from "../content/docs/guide.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_8 from "../content/docs/quick-start.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_9 from "../content/docs/synths.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_10 from "../content/docs/troubleshoo.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_11 from "../content/docs/(effects)/chorus-t.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_12 from "../content/docs/(modifiers)/clip-amp.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_13 from "../content/docs/(modifiers)/state-variable-filter.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_14 from "../content/docs/(modifiers)/vca.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_15 from "../content/docs/(modulators)/ad.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_16 from "../content/docs/(modulators)/adsr.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_17 from "../content/docs/(modulators)/lfo.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_18 from "../content/docs/(modulators)/param.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_19 from "../content/docs/(sources)/impulse.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_20 from "../content/docs/(sources)/noise.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_21 from "../content/docs/(sources)/polyblep.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_22 from "../content/docs/(sources)/wavetable.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_23 from "../content/docs/(sequencers)/clock.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -import * as file_24 from "../content/docs/(sequencers)/euclid.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" -export const meta = [toRuntime("meta", file_0, {"path":"meta.json","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/meta.json"}),toRuntime("meta", file_1, {"path":"(effects)/meta.json","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(effects)/meta.json"}),toRuntime("meta", file_2, {"path":"(modifiers)/meta.json","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modifiers)/meta.json"}),toRuntime("meta", file_3, {"path":"(sequencers)/meta.json","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(sequencers)/meta.json"}),toRuntime("meta", file_4, {"path":"(sources)/meta.json","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(sources)/meta.json"}),toRuntime("meta", file_5, {"path":"(modulators)/meta.json","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modulators)/meta.json"})] -export const docs = [toRuntime("doc", file_6, {"path":"dsl.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/dsl.mdx"}),toRuntime("doc", file_7, {"path":"guide.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/guide.mdx"}),toRuntime("doc", file_8, {"path":"quick-start.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/quick-start.mdx"}),toRuntime("doc", file_9, {"path":"synths.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/synths.mdx"}),toRuntime("doc", file_10, {"path":"troubleshoo.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/troubleshoo.mdx"}),toRuntime("doc", file_11, {"path":"(effects)/chorus-t.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(effects)/chorus-t.mdx"}),toRuntime("doc", file_12, {"path":"(modifiers)/clip-amp.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modifiers)/clip-amp.mdx"}),toRuntime("doc", file_13, {"path":"(modifiers)/state-variable-filter.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modifiers)/state-variable-filter.mdx"}),toRuntime("doc", file_14, {"path":"(modifiers)/vca.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modifiers)/vca.mdx"}),toRuntime("doc", file_15, {"path":"(modulators)/ad.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modulators)/ad.mdx"}),toRuntime("doc", file_16, {"path":"(modulators)/adsr.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modulators)/adsr.mdx"}),toRuntime("doc", file_17, {"path":"(modulators)/lfo.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modulators)/lfo.mdx"}),toRuntime("doc", file_18, {"path":"(modulators)/param.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modulators)/param.mdx"}),toRuntime("doc", file_19, {"path":"(sources)/impulse.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(sources)/impulse.mdx"}),toRuntime("doc", file_20, {"path":"(sources)/noise.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(sources)/noise.mdx"}),toRuntime("doc", file_21, {"path":"(sources)/polyblep.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(sources)/polyblep.mdx"}),toRuntime("doc", file_22, {"path":"(sources)/wavetable.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(sources)/wavetable.mdx"}),toRuntime("doc", file_23, {"path":"(sequencers)/clock.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(sequencers)/clock.mdx"}),toRuntime("doc", file_24, {"path":"(sequencers)/euclid.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(sequencers)/euclid.mdx"})] \ No newline at end of file +import * as file_0 from "../content/docs/dsl.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_1 from "../content/docs/guide.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_2 from "../content/docs/quick-start.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_3 from "../content/docs/synths.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_4 from "../content/docs/troubleshoo.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_5 from "../content/docs/(effects)/chorus-t.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_6 from "../content/docs/(effects)/dattorro.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_7 from "../content/docs/(modifiers)/clip-amp.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_8 from "../content/docs/(modifiers)/state-variable-filter.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_9 from "../content/docs/(modifiers)/vca.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_10 from "../content/docs/(sequencers)/clock.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_11 from "../content/docs/(sequencers)/euclid.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_12 from "../content/docs/(sources)/impulse.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_13 from "../content/docs/(sources)/noise.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_14 from "../content/docs/(sources)/polyblep.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_15 from "../content/docs/(sources)/wavetable.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_16 from "../content/docs/(modulators)/ad.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_17 from "../content/docs/(modulators)/adsr.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_18 from "../content/docs/(modulators)/lfo.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_19 from "../content/docs/(modulators)/param.mdx?collection=docs&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_20 from "../content/docs/meta.json?collection=meta&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_21 from "../content/docs/(effects)/meta.json?collection=meta&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_22 from "../content/docs/(modifiers)/meta.json?collection=meta&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_23 from "../content/docs/(modulators)/meta.json?collection=meta&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_24 from "../content/docs/(sequencers)/meta.json?collection=meta&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +import * as file_25 from "../content/docs/(sources)/meta.json?collection=meta&hash=a0e5c83919940bc930420dd0f9f7d68e8c5dbe7f6983d8b3ed42ebccd021e4f6" +export const docs = [toRuntime("doc", file_0, {"path":"dsl.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/dsl.mdx"}),toRuntime("doc", file_1, {"path":"guide.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/guide.mdx"}),toRuntime("doc", file_2, {"path":"quick-start.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/quick-start.mdx"}),toRuntime("doc", file_3, {"path":"synths.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/synths.mdx"}),toRuntime("doc", file_4, {"path":"troubleshoo.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/troubleshoo.mdx"}),toRuntime("doc", file_5, {"path":"(effects)/chorus-t.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(effects)/chorus-t.mdx"}),toRuntime("doc", file_6, {"path":"(effects)/dattorro.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(effects)/dattorro.mdx"}),toRuntime("doc", file_7, {"path":"(modifiers)/clip-amp.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modifiers)/clip-amp.mdx"}),toRuntime("doc", file_8, {"path":"(modifiers)/state-variable-filter.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modifiers)/state-variable-filter.mdx"}),toRuntime("doc", file_9, {"path":"(modifiers)/vca.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modifiers)/vca.mdx"}),toRuntime("doc", file_10, {"path":"(sequencers)/clock.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(sequencers)/clock.mdx"}),toRuntime("doc", file_11, {"path":"(sequencers)/euclid.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(sequencers)/euclid.mdx"}),toRuntime("doc", file_12, {"path":"(sources)/impulse.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(sources)/impulse.mdx"}),toRuntime("doc", file_13, {"path":"(sources)/noise.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(sources)/noise.mdx"}),toRuntime("doc", file_14, {"path":"(sources)/polyblep.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(sources)/polyblep.mdx"}),toRuntime("doc", file_15, {"path":"(sources)/wavetable.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(sources)/wavetable.mdx"}),toRuntime("doc", file_16, {"path":"(modulators)/ad.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modulators)/ad.mdx"}),toRuntime("doc", file_17, {"path":"(modulators)/adsr.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modulators)/adsr.mdx"}),toRuntime("doc", file_18, {"path":"(modulators)/lfo.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modulators)/lfo.mdx"}),toRuntime("doc", file_19, {"path":"(modulators)/param.mdx","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modulators)/param.mdx"})] +export const meta = [toRuntime("meta", file_20, {"path":"meta.json","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/meta.json"}),toRuntime("meta", file_21, {"path":"(effects)/meta.json","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(effects)/meta.json"}),toRuntime("meta", file_22, {"path":"(modifiers)/meta.json","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modifiers)/meta.json"}),toRuntime("meta", file_23, {"path":"(modulators)/meta.json","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(modulators)/meta.json"}),toRuntime("meta", file_24, {"path":"(sequencers)/meta.json","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(sequencers)/meta.json"}),toRuntime("meta", file_25, {"path":"(sources)/meta.json","absolutePath":"/Users/danigb/Projects/Synthlet/site/content/docs/(sources)/meta.json"})] \ No newline at end of file diff --git a/site/content/docs/(effects)/dattorro.mdx b/site/content/docs/(effects)/dattorro.mdx new file mode 100644 index 0000000..aaace3c --- /dev/null +++ b/site/content/docs/(effects)/dattorro.mdx @@ -0,0 +1,27 @@ +--- +title: Dattorro Reverb +description: A Dattorro reverb effect from Faust +--- + +import DattorroExample from "../../../examples/DattorroExample"; + +This is a port of the Dattorro reverb from Faust to the Web Audio API. All credits to Jakob Zerbian. + +```ts +import { ClaveDrum, DattorroReverb, registerWorklets } from "synthlet"; + +const audioContext = await registerWorklets(new AudioContext()); +const reverb = DattorroReverb(audioContext, { + mix: 0.5, + time: 0.5, + decay: 0.5, + lowpass: 20000, + highpass: 20, +}); + +const clave = ClaveDrum(audioContext); +clave.connect(reverb).connect(audioContext.destination); +clave.trigger = 1; +``` + + diff --git a/site/examples/DattorroExample.tsx b/site/examples/DattorroExample.tsx new file mode 100644 index 0000000..70749b0 --- /dev/null +++ b/site/examples/DattorroExample.tsx @@ -0,0 +1,76 @@ +"use client"; + +import { ClaveDrum, DattorroReverb } from "synthlet"; +import { + ExamplePane, + ModulePane, + TriggerButton, +} from "./components/ExamplePane"; +import { Slider } from "./components/Slider"; +import { useSynth } from "./useSynth"; + +function DattorroSynth(context: AudioContext) { + const clave = ClaveDrum(context); + const reverb = DattorroReverb(context); + reverb.connect(context.destination); + clave.connect(reverb); + + return Object.assign(clave, { reverb }); +} + +function Example() { + const synth = useSynth(DattorroSynth); + if (!synth) return null; + + return ( + <> + + + + + + + + + + + + + + + ); +} + +export default () => ( + + + +); diff --git a/site/examples/components/ExamplePane.tsx b/site/examples/components/ExamplePane.tsx index 27ac1f8..f74a84a 100644 --- a/site/examples/components/ExamplePane.tsx +++ b/site/examples/components/ExamplePane.tsx @@ -70,9 +70,15 @@ export function ModulePane({ ); } -export function TriggerButton({ trigger }: { trigger: { value: number } }) { +export function TriggerButton({ + trigger, + className, +}: { + className?: string; + trigger: { value: number }; +}) { return ( -

+