UNPKG

mosfez-synth

Version:

A microtonal-aware synth engine library for web.

1 lines 23.6 kB
{"version":3,"file":"synth.mjs","sources":["../src/internal/param-utils.ts","../src/dsp-node.ts","../src/internal/faust-dsp-utils.ts","../src/internal/construct-node-faust.ts","../src/internal/construct-node-poly.ts","../src/internal/construct-node.ts","../src/synth.ts"],"sourcesContent":["import { ParamValueObject } from \"../params\";\nimport { ParamDefinitionObject, ParamDefinition } from \"../dsp-node\";\n\nexport function validateParamDefinition(\n name: string,\n paramDef: ParamDefinition\n): ParamDefinition {\n if (!isConstant(paramDef) && !isVariable(paramDef)) {\n throw new Error(\n `param \"${name}\" must be a constant number or a string referring to a param name, but got ${paramDef}`\n );\n }\n return paramDef;\n}\n\nexport function validateParamDefinitionObject(\n paramDefs: ParamDefinitionObject\n): ParamDefinitionObject {\n for (const name in paramDefs) {\n validateParamDefinition(name, paramDefs[name] as ParamDefinition);\n }\n return paramDefs;\n}\n\nexport function isConstant(paramDef: ParamDefinition): paramDef is number {\n return typeof paramDef === \"number\";\n}\n\nexport function isVariable(paramDef: ParamDefinition): paramDef is string {\n return typeof paramDef === \"string\";\n}\n\nexport function resolveParam(\n params: Partial<ParamValueObject>,\n paramDef: ParamDefinition\n): number | undefined {\n if (isConstant(paramDef)) {\n return paramDef;\n } else if (isVariable(paramDef)) {\n return params[paramDef] as number;\n }\n return undefined;\n}\n","import type { compile } from \"mosfez-faust/faust\";\nimport type { VoiceController } from \"./internal/voice-controller\";\nimport {\n validateParamDefinitionObject,\n validateParamDefinition,\n} from \"./internal/param-utils\";\n\nexport type ParamDefinition = number | string;\n\nexport type ParamDefinitionObject = Record<string, ParamDefinition>;\n\nexport type DspNodeType = \"faust\" | \"poly\";\n\nexport type DspNodeSerialized = DspNodeFaustSerialized | DspNodePolySerialized;\n\nexport type DspNodeConfig = {\n type: DspNodeType;\n};\n\nexport class DspNode {\n type: DspNodeType;\n\n constructor(config: DspNodeConfig) {\n this.type = config.type;\n }\n\n static isFaustDspNode(DspNode: DspNode): DspNode is DspNodeFaust {\n return DspNode.type === \"faust\";\n }\n\n static isPolyDspNode(DspNode: DspNode): DspNode is DspNodePoly {\n return DspNode.type === \"poly\";\n }\n\n static isFaustDspNodeSerialized(\n serialized: DspNodeSerialized\n ): serialized is DspNodeFaustSerialized {\n return serialized.type === \"faust\";\n }\n\n static isPolyDspNodeSerialized(\n serialized: DspNodeSerialized\n ): serialized is DspNodePolySerialized {\n return serialized.type === \"poly\";\n }\n\n serialize(): DspNodeSerialized {\n throw new Error(\".serialize() can only be called on subclasses\");\n }\n}\n\n//\n// faust\n//\n\nexport type DspNodeFaustDependencies = {\n compile: typeof compile;\n};\n\nexport type DspNodeFaustConfig = {\n dsp: string;\n inputs?: DspNode[];\n paramDefs: ParamDefinitionObject;\n dependencies: DspNodeFaustDependencies;\n};\n\nexport type DspNodeFaustSerialized = {\n type: \"faust\";\n dsp: string;\n inputs: DspNodeSerialized[];\n paramDefs: ParamDefinitionObject;\n};\n\nexport class DspNodeFaust extends DspNode {\n dsp: string;\n inputs: DspNode[];\n paramDefs: ParamDefinitionObject;\n dependencies: DspNodeFaustDependencies;\n\n constructor(config: DspNodeFaustConfig) {\n super({\n type: \"faust\",\n });\n\n this.dsp = config.dsp;\n this.inputs = config.inputs ?? [];\n this.paramDefs = validateParamDefinitionObject(config.paramDefs);\n this.dependencies = config.dependencies;\n }\n\n serialize(): DspNodeFaustSerialized {\n const { dsp, paramDefs } = this;\n const inputs = this.inputs.map((input) => input.serialize());\n\n return {\n type: \"faust\",\n dsp,\n inputs,\n paramDefs,\n };\n }\n}\n\n//\n// poly\n//\n\nexport type DspNodePolyDependencies = {\n VoiceController: typeof VoiceController;\n};\n\nexport type DspNodePolyConfig = {\n input: DspNode;\n polyphony: number;\n paramCacheSize?: number;\n release: ParamDefinition;\n gate: ParamDefinition;\n dependencies: DspNodePolyDependencies;\n};\n\nexport type DspNodePolySerialized = {\n type: \"poly\";\n input: DspNodeSerialized;\n polyphony: number;\n paramCacheSize?: number;\n release: ParamDefinition;\n gate: ParamDefinition;\n};\n\nexport class DspNodePoly extends DspNode {\n input: DspNode;\n polyphony: number;\n paramCacheSize?: number;\n release: ParamDefinition;\n gate: ParamDefinition;\n dependencies: DspNodePolyDependencies;\n\n constructor(config: DspNodePolyConfig) {\n super({\n type: \"poly\",\n });\n\n this.input = config.input;\n this.polyphony = config.polyphony;\n this.paramCacheSize = config.paramCacheSize;\n this.release = validateParamDefinition(\"release\", config.release);\n this.gate = validateParamDefinition(\"gate\", config.gate);\n this.dependencies = config.dependencies;\n }\n\n serialize(): DspNodePolySerialized {\n const { polyphony, paramCacheSize, release, gate } = this;\n const input = this.input.serialize();\n\n return {\n type: \"poly\",\n input,\n polyphony,\n paramCacheSize,\n release,\n gate,\n };\n }\n}\n","export function lines(lines: string[]): string {\n return lines.join(\"\\n\");\n}\n\nexport function series<T>(\n arr: T[],\n joiner: string,\n callback: (value: T, key: number) => string\n): string {\n return arr.map(callback).join(joiner);\n}\n\nexport function env(name: string, dsp: string): string {\n return `${name} = environment { \\n ${dsp.replace(/\\n/g, \"\\n \")} \\n};\\n`;\n}\n","import type { ParamValueObject } from \"../params\";\nimport type { DspNodeFaust } from \"../dsp-node\";\n\nimport type { ConstructNode, DspAudioNode } from \"./construct-node\";\n\nimport { series, env, lines } from \"./faust-dsp-utils\";\nimport { resolveParam } from \"./param-utils\";\n\nexport async function constructNodeFaust<P extends ParamValueObject>(\n audioContext: AudioContext | OfflineAudioContext,\n dspNode: DspNodeFaust,\n constructNode: ConstructNode<P>\n): Promise<DspAudioNode<P>> {\n const { inputs = [], paramDefs, dependencies } = dspNode;\n\n // build input nodes\n const inputNodes = await Promise.all(\n inputs.map((input) => constructNode(audioContext, input))\n );\n\n // build dsp\n const dspToCompile = lines([\n 'import(\"stdfaust.lib\");',\n constructFaustDsp(dspNode),\n ]);\n\n const faustNode = await dependencies.compile(audioContext, dspToCompile);\n const faustNodeDestroy = faustNode.destroy.bind(faustNode);\n const node = faustNode as unknown as DspAudioNode<P>;\n\n // execute and cascade any calls to destroy\n node.destroy = () => {\n faustNodeDestroy();\n inputNodes.forEach((node) => node?.destroy());\n };\n\n // precalculate params used in this node\n const paramsUsed = faustNode.getParams();\n\n // execute and cascade any calls to set\n node.set = (params: Partial<P>) => {\n paramsUsed.forEach((name) => {\n const paramKey = name.replace(/^\\/FaustDSP\\//g, \"\");\n const paramDef = paramDefs[paramKey];\n if (paramDef !== undefined) {\n const value = resolveParam(params, paramDef);\n if (typeof value === \"number\") {\n faustNode.setParamValue(name, value);\n }\n }\n });\n\n inputNodes.forEach((node) => node?.set(params));\n };\n\n // connect input nodes\n // todo - squash faust nodes together before compilation where possible\n // to reduce the amount of nodes and audio rate params being sent between nodes\n for (let i = 0; i < inputNodes.length; i++) {\n inputNodes[i].connect(node, 0, i);\n }\n\n return node;\n}\n\nfunction constructFaustDsp(dspNode: DspNodeFaust): string {\n const { paramDefs, dsp } = dspNode;\n\n // todo - use this when squashing faust nodes together\n // inputs\n // const inputDspVars = series(inputs, \",\", (_, key) => `input_${key}.process`);\n // const inputDsp = series(inputs, \",\", (dspNode, key) =>\n // env(`input_${key}`, constructFaustDsp(dspNode))\n // );\n // const bodyDsp =\n // inputDspVars.length === 0\n // ? dsp\n // : dsp.replace(\"process = \", `process = ${inputDspVars} : `);\n\n // params\n const paramsDsp = env(\n \"params\",\n lines([\n series(Object.entries(paramDefs), \"\\n\", ([name, value]) => {\n if (typeof value === \"number\") {\n return `${name} = ${value};\\n`;\n }\n return `${name} = hslider(\"${name}\",0.0,-9999999.0,9999999.0,0.0000001);`;\n }),\n // `changed(x) = x != x';`,\n // `reset = hslider(\"reset\",0.0,0.0,9999999.0,1.0) : changed;`,\n ])\n );\n\n return lines([paramsDsp, dsp]);\n}\n","import type { ParamValueObject } from \"../params\";\nimport type { DspNodePoly } from \"../dsp-node\";\n\nimport type { ConstructNode, DspAudioNode } from \"./construct-node\";\nimport { isVariable, resolveParam } from \"./param-utils\";\n\nexport async function constructNodePoly<P extends ParamValueObject>(\n audioContext: AudioContext | OfflineAudioContext,\n dspNode: DspNodePoly,\n constructNode: ConstructNode<P>\n): Promise<DspAudioNode<P>> {\n const {\n input,\n polyphony,\n paramCacheSize = 10000,\n release,\n gate,\n dependencies,\n } = dspNode;\n const releaseIsVariable = isVariable(release);\n\n // create a voice bank\n const { VoiceController } = dependencies;\n const controller = new VoiceController({\n polyphony,\n resolveGate: (params) => resolveParam(params, gate),\n paramCacheSize,\n });\n\n // set release if it's constant\n const setRelease = (r: number) => controller.setRelease(r * 1000);\n\n if (!releaseIsVariable) {\n setRelease(release);\n }\n\n // construct polyphony number of voices\n const voiceNodes = await Promise.all(\n Array(polyphony)\n .fill(0)\n .map(() => constructNode(audioContext, input))\n );\n\n // make a gain node and connect all voices to it\n const gainNode = new GainNode(audioContext) as unknown as DspAudioNode<P>;\n voiceNodes.forEach((node) => node.connect(gainNode));\n\n // cascade any calls to destroy\n gainNode.destroy = () => {\n voiceNodes.forEach((node) => node?.destroy());\n };\n\n // cascade any calls to set, filtered down to particular voices if required\n gainNode.set = (params: Partial<P>) => {\n // set release if it is passed through here\n if (releaseIsVariable) {\n const value = params[release];\n if (typeof value === \"number\") {\n setRelease(value);\n }\n }\n\n // pass params through the controller\n const paramsToSet = controller.set(params);\n\n // send the results to child nodes\n paramsToSet.forEach(({ index, params }) => {\n voiceNodes[index].set(params as Partial<P>);\n });\n };\n\n return gainNode;\n}\n","import { ParamValueObject } from \"../params\";\nimport { DspNode } from \"../dsp-node\";\nimport { constructNodeFaust } from \"./construct-node-faust\";\nimport { constructNodePoly } from \"./construct-node-poly\";\n\nexport type DspAudioNode<P extends ParamValueObject> = AudioNode & {\n set: (params: Partial<P>) => void;\n destroy: () => void;\n};\n\nexport type ConstructNode<P extends ParamValueObject> = (\n audioContext: AudioContext | OfflineAudioContext,\n dspNode: DspNode\n) => Promise<DspAudioNode<P>>;\n\nexport async function constructNode<P extends ParamValueObject>(\n audioContext: AudioContext | OfflineAudioContext,\n dspNode: DspNode\n): Promise<DspAudioNode<P>> {\n if (DspNode.isFaustDspNode(dspNode)) {\n return await constructNodeFaust<P>(audioContext, dspNode, constructNode);\n }\n if (DspNode.isPolyDspNode(dspNode)) {\n return await constructNodePoly<P>(audioContext, dspNode, constructNode);\n }\n throw new Error(`dspNode has invalid type \"${dspNode.type}\"`);\n}\n","import { constructNode, DspAudioNode } from \"./internal/construct-node\";\nimport type { DspNode } from \"./dsp-node\";\nimport type { ParamValueObject } from \"./params\";\n\nexport type InputSetEvent = {\n type: \"set\";\n time: number;\n params: Partial<ParamValueObject>;\n};\n\nexport type InputStopEvent = {\n type: \"stop\";\n time: number;\n};\n\nexport type InputEvent = InputSetEvent | InputStopEvent;\n\nexport function isInputSetEvent(e: InputEvent): e is InputSetEvent {\n return e.type === \"set\";\n}\n\nexport function isInputStopEvent(e: InputEvent): e is InputStopEvent {\n return e.type === \"stop\";\n}\n\nclass InputEventRecorder<P extends ParamValueObject> {\n public recording = false;\n private recordingStartTime = Date.now();\n private events: InputEvent[] = [];\n\n record() {\n this.recording = true;\n this.recordingStartTime = Date.now();\n }\n\n stop(): InputEvent[] {\n const time = (Date.now() - this.recordingStartTime) * 0.001;\n\n this.events.push({\n type: \"stop\",\n time,\n });\n\n const result = this.events;\n this.events = [];\n this.recording = false;\n return result;\n }\n\n addSetEvent(params: Partial<P>) {\n const time = (Date.now() - this.recordingStartTime) * 0.001;\n\n this.events.push({\n type: \"set\",\n time,\n params,\n });\n }\n}\n\nexport type SynthConfig<P> = {\n audioContext: AudioContext | OfflineAudioContext;\n params?: Partial<P>;\n};\n\nexport class Synth<P extends ParamValueObject> {\n private audioContext: AudioContext | OfflineAudioContext;\n private initialParams?: Partial<P>;\n\n private node?: DspAudioNode<P>;\n private connection?: [AudioNode, number?, number?];\n\n constructor(config: SynthConfig<P>) {\n this.audioContext = config.audioContext;\n this.initialParams = config.params;\n }\n\n async build(dspNode: DspNode) {\n const newNode = await constructNode<P>(this.audioContext, dspNode);\n this.node?.disconnect();\n this.node?.destroy();\n this.node = newNode;\n this.tryConnectNode();\n }\n\n connect(audio: AudioNode, output?: number, input?: number): AudioNode {\n this.connection = [audio, output, input];\n this.tryConnectNode();\n return audio;\n }\n\n private tryConnectNode() {\n if (this.node && this.connection) {\n this.node.disconnect();\n this.node.connect(...this.connection);\n if (this.initialParams) {\n this.set(this.initialParams);\n }\n }\n }\n\n disconnect(): void;\n disconnect(output: number): void;\n disconnect(destinationNode: AudioNode): void;\n disconnect(destinationNode: AudioNode, output: number): void;\n disconnect(destinationNode: AudioNode, output: number, input: number): void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n disconnect(outputOrDestinationNode?: any, output?: any, input?: any): void {\n if (this.node) {\n this.node.disconnect(outputOrDestinationNode, output, input);\n }\n }\n\n set(params: Partial<P>) {\n if (this.inputEvents.recording) {\n this.inputEvents.addSetEvent(params);\n }\n if (this.node) {\n this.node.set(params);\n }\n }\n\n destroy() {\n this.node?.destroy();\n this.node = undefined;\n }\n\n inputEvents = new InputEventRecorder<P>();\n}\n"],"names":[],"mappings":"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"}