@blibliki/engine 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +147 -129
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/Engine.ts +4 -0
- package/src/core/Note/index.ts +19 -4
- package/src/core/index.ts +7 -0
- package/src/core/midi/Message.ts +1 -0
- package/src/core/midi/MidiDeviceManager.ts +25 -0
- package/src/core/midi/deviceMatcher.ts +203 -0
- package/src/core/module/Module.ts +7 -1
- package/src/core/module/PolyModule.ts +6 -1
- package/src/core/module/VoiceScheduler.ts +9 -3
- package/src/core/module/index.ts +8 -0
- package/src/index.ts +1 -0
- package/src/modules/Inspector.ts +2 -1
- package/src/modules/MidiMapper.ts +3 -0
- package/src/modules/MidiSelector.ts +26 -5
- package/src/processors/filter-processor.ts +17 -7
- package/src/processors/scale-processor.ts +25 -7
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/Engine.ts","../src/core/module/Module.ts","../src/core/IO/Collection.ts","../src/core/module/PolyModule.ts","../src/core/IO/AudioIO.ts","../src/core/IO/Base.ts","../src/core/IO/PolyAudioIO.ts","../src/core/IO/MidiIO.ts","../src/core/Note/frequencyTable.ts","../src/core/Note/index.ts","../src/core/midi/Message.ts","../src/core/midi/MidiEvent.ts","../src/core/Route.ts","../src/core/midi/MidiDevice.ts","../src/core/midi/ComputerKeyboardDevice.ts","../src/core/midi/adapters/index.ts","../src/core/midi/adapters/NodeMidiAdapter.ts","../src/core/midi/adapters/WebMidiAdapter.ts","../src/core/midi/MidiDeviceManager.ts","../src/modules/index.ts","../src/core/module/VoiceScheduler.ts","../src/modules/Constant.ts","../src/modules/Envelope.ts","../src/modules/Filter.ts","../src/modules/Gain.ts","../src/modules/Inspector.ts","../src/modules/Master.ts","../src/modules/MidiMapper.ts","../src/modules/MidiSelector.ts","../src/modules/Oscillator.ts","../src/processors/index.ts","../src/processors/filter-processor.ts","../src/processors/scale-processor.ts","../src/modules/Scale.ts","../src/modules/StepSequencer.ts","../src/modules/StereoPanner.ts","../src/modules/VirtualMidi.ts","../src/index.ts"],"sourcesContent":["import {\n BPM,\n ContextTime,\n Ticks,\n TimeSignature,\n Transport,\n TransportEvent,\n} from \"@blibliki/transport\";\nimport {\n assertDefined,\n Context,\n Optional,\n pick,\n uuidv4,\n} from \"@blibliki/utils\";\nimport {\n IRoute,\n Routes,\n MidiDeviceManager,\n IModule,\n MidiEvent,\n IModuleSerialize,\n} from \"@/core\";\nimport {\n ICreateModule,\n ModuleParams,\n ModuleType,\n ModuleTypeToModuleMapping,\n createModule,\n} from \"@/modules\";\nimport {\n IPolyModule,\n IPolyModuleSerialize,\n PolyModule,\n} from \"./core/module/PolyModule\";\nimport { loadProcessors } from \"./processors\";\n\nexport type IUpdateModule<T extends ModuleType> = {\n id: string;\n moduleType: T;\n changes: Partial<Omit<ICreateModule<T>, \"id\" | \"moduleType\" | \"voice\">> & {\n voices?: number;\n };\n};\n\nexport type ICreateRoute = Optional<IRoute, \"id\">;\n\nexport interface IEngineSerialize {\n bpm: BPM;\n timeSignature: TimeSignature;\n modules: (IModuleSerialize<ModuleType> | IPolyModuleSerialize<ModuleType>)[];\n routes: IRoute[];\n}\n\nexport class Engine {\n private static _engines = new Map<string, Engine>();\n private static _currentId: string | undefined;\n private propsUpdateCallbacks: (<T extends ModuleType>(\n params: IModule<T> | IPolyModule<T>,\n ) => void)[] = [];\n\n readonly id: string;\n context: Context;\n isInitialized = false;\n routes: Routes;\n transport: Transport<TransportEvent>;\n modules: Map<\n string,\n ModuleTypeToModuleMapping[keyof ModuleTypeToModuleMapping]\n >;\n\n midiDeviceManager: MidiDeviceManager;\n\n static getById(id: string): Engine {\n const engine = Engine._engines.get(id);\n assertDefined(engine);\n\n return engine;\n }\n\n static get current(): Engine {\n assertDefined(this._currentId);\n\n return this.getById(this._currentId);\n }\n\n static async load(data: IEngineSerialize): Promise<Engine> {\n const { bpm, timeSignature, modules, routes } = data;\n const context = new Context();\n const engine = new Engine(context);\n await engine.initialize();\n\n engine.timeSignature = timeSignature;\n engine.bpm = bpm;\n modules.forEach((m) => {\n engine.addModule(m);\n });\n routes.forEach((r) => {\n engine.addRoute(r);\n });\n\n return engine;\n }\n\n constructor(context: Context) {\n this.id = uuidv4();\n\n this.context = context;\n this.transport = new Transport(this.context, {\n generator: (_start: Ticks, _end: Ticks) => {\n return [] as TransportEvent[];\n },\n consumer: (_event: TransportEvent) => {\n return;\n },\n onJump: (_ticks: Ticks) => {\n return;\n },\n onStart: this.onStart,\n onStop: this.onStop,\n silence: (_actionAt: ContextTime) => {\n return;\n },\n });\n this.routes = new Routes(this);\n this.modules = new Map();\n this.midiDeviceManager = new MidiDeviceManager(this.context);\n\n Engine._engines.set(this.id, this);\n Engine._currentId = this.id;\n }\n\n get state() {\n return this.transport.state;\n }\n\n async initialize() {\n if (this.isInitialized) return;\n\n await loadProcessors(this.context);\n await this.midiDeviceManager.initialize();\n this.isInitialized = true;\n }\n\n addModule<T extends ModuleType>(params: ICreateModule<T>) {\n const module = createModule(this.id, params as ModuleParams);\n this.modules.set(module.id, module);\n\n return module.serialize();\n }\n\n updateModule<T extends ModuleType>(params: IUpdateModule<T>) {\n const module = this.findModule(params.id);\n if (module.moduleType !== params.moduleType) {\n throw Error(\n `The module id ${params.id} isn't moduleType ${params.moduleType}`,\n );\n }\n\n const updates = pick(params.changes, [\"name\", \"props\"]);\n Object.assign(module, updates);\n\n if (module instanceof PolyModule && params.changes.voices !== undefined) {\n module.voices = params.changes.voices;\n }\n\n return module.serialize();\n }\n\n removeModule(id: string) {\n this.modules.delete(id);\n }\n\n addRoute(props: ICreateRoute): IRoute {\n return this.routes.addRoute(props);\n }\n\n removeRoute(id: string) {\n this.routes.removeRoute(id);\n }\n\n validRoute(props: Optional<IRoute, \"id\">): boolean {\n const { source, destination } = props;\n\n const output = this.findIO(source.moduleId, source.ioName, \"output\");\n const input = this.findIO(\n destination.moduleId,\n destination.ioName,\n \"input\",\n );\n\n return (\n (output.isMidi() && input.isMidi()) ||\n (output.isAudio() && input.isAudio())\n );\n }\n\n async start() {\n await this.resume();\n this.transport.start();\n }\n\n stop() {\n this.transport.stop();\n this.transport.reset();\n }\n\n pause() {\n this.transport.stop();\n }\n\n get bpm() {\n return this.transport.bpm;\n }\n\n set bpm(value: number) {\n this.transport.bpm = value;\n }\n\n get timeSignature() {\n return this.transport.timeSignature;\n }\n\n set timeSignature(value: TimeSignature) {\n this.transport.timeSignature = value;\n }\n\n async resume() {\n await this.context.resume();\n }\n\n dispose() {\n this.stop();\n this.routes.clear();\n this.modules.forEach((module) => {\n module.dispose();\n });\n this.modules.clear();\n }\n\n serialize(): IEngineSerialize {\n return {\n bpm: this.bpm,\n timeSignature: this.timeSignature,\n modules: Array.from(this.modules.values()).map((m) => m.serialize()),\n routes: this.routes.serialize(),\n };\n }\n\n findModule(\n id: string,\n ): ModuleTypeToModuleMapping[keyof ModuleTypeToModuleMapping] {\n const module = this.modules.get(id);\n if (!module) throw Error(`The module with id ${id} is not exists`);\n\n return module;\n }\n\n findIO(moduleId: string, ioName: string, type: \"input\" | \"output\") {\n const module = this.findModule(moduleId);\n return module[`${type}s`].findByName(ioName);\n }\n\n findMidiDevice(id: string) {\n return this.midiDeviceManager.find(id);\n }\n\n findMidiDeviceByName(name: string) {\n return this.midiDeviceManager.findByName(name);\n }\n\n onPropsUpdate(\n callback: <T extends ModuleType>(\n params: IModule<T> | IPolyModule<T>,\n ) => void,\n ) {\n this.propsUpdateCallbacks.push(callback);\n }\n\n _triggerPropsUpdate<T extends ModuleType>(\n params: IModule<T> | IPolyModule<T>,\n ) {\n this.propsUpdateCallbacks.forEach((callback) => {\n callback(params);\n });\n }\n\n // TODO: Find better way to support this\n triggerVirtualMidi(id: string, noteName: string, type: \"noteOn\" | \"noteOff\") {\n const virtualMidi = this.findModule(id);\n if (virtualMidi.moduleType !== ModuleType.VirtualMidi)\n throw Error(\"This is not a virtual mid\");\n\n virtualMidi.sendMidi(\n MidiEvent.fromNote(noteName, type === \"noteOn\", this.context.currentTime),\n );\n }\n\n // actionAt is context time\n private onStart = (actionAt: ContextTime) => {\n this.modules.forEach((module) => {\n module.start(actionAt);\n });\n };\n\n // actionAt is context time\n private onStop = (actionAt: ContextTime) => {\n this.modules.forEach((module) => {\n module.stop(actionAt);\n });\n };\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport { Context, Optional, upperFirst, uuidv4 } from \"@blibliki/utils\";\nimport { Engine } from \"@/Engine\";\nimport { AnyModule, ModuleType, ModuleTypeToPropsMapping } from \"@/modules\";\nimport {\n AudioInputProps,\n AudioOutputProps,\n IIOSerialize,\n IOType,\n InputCollection,\n OutputCollection,\n MidiInputProps,\n MidiOutputProps,\n} from \"../IO\";\nimport Note from \"../Note\";\nimport MidiEvent, { MidiEventType } from \"../midi/MidiEvent\";\n\nexport type IModule<T extends ModuleType> = {\n id: string;\n name: string;\n voiceNo: number;\n moduleType: T;\n props: ModuleTypeToPropsMapping[T];\n};\n\nexport type IModuleSerialize<T extends ModuleType> = IModule<T> & {\n inputs: IIOSerialize[];\n outputs: IIOSerialize[];\n};\n\nexport type IModuleConstructor<T extends ModuleType> = Optional<\n IModule<T>,\n \"id\" | \"voiceNo\"\n> & {\n audioNodeConstructor?: (context: Context) => AudioNode;\n};\n\nexport type SetterHooks<P> = {\n [K in keyof P as `onSet${Capitalize<string & K>}`]: (value: P[K]) => P[K];\n} & {\n [K in keyof P as `onAfterSet${Capitalize<string & K>}`]: (\n value: P[K],\n ) => void;\n};\n\nexport abstract class Module<T extends ModuleType> implements IModule<T> {\n id: string;\n engineId: string;\n name: string;\n moduleType: T;\n voiceNo: number;\n audioNode: AudioNode | undefined;\n inputs: InputCollection;\n outputs: OutputCollection;\n protected _props!: ModuleTypeToPropsMapping[T];\n protected activeNotes: Note[];\n private pendingUIUpdates = false;\n\n constructor(engineId: string, params: IModuleConstructor<T>) {\n const { id, name, moduleType, voiceNo, audioNodeConstructor, props } =\n params;\n\n this.id = id ?? uuidv4();\n this.engineId = engineId;\n this.name = name;\n this.moduleType = moduleType;\n this.voiceNo = voiceNo ?? 0;\n this.activeNotes = [];\n this.audioNode = audioNodeConstructor?.(this.context);\n this._props = props;\n\n this.inputs = new InputCollection(this);\n this.outputs = new OutputCollection(this);\n\n // Defer hook calls until after subclass is fully initialized\n queueMicrotask(() => {\n this.props = props;\n });\n }\n\n get props(): ModuleTypeToPropsMapping[T] {\n return this._props;\n }\n\n set props(value: Partial<ModuleTypeToPropsMapping[T]>) {\n const updatedValue = { ...value };\n\n (Object.keys(value) as (keyof ModuleTypeToPropsMapping[T])[]).forEach(\n (key) => {\n const propValue = value[key];\n if (propValue !== undefined) {\n const result = this.callPropHook(\"onSet\", key, propValue);\n if (result !== undefined) {\n updatedValue[key] = result;\n }\n }\n },\n );\n\n this._props = { ...this._props, ...updatedValue };\n\n (\n Object.keys(updatedValue) as (keyof ModuleTypeToPropsMapping[T])[]\n ).forEach((key) => {\n const propValue = updatedValue[key];\n if (propValue !== undefined) {\n this.callPropHook(\"onAfterSet\", key, propValue);\n }\n });\n }\n\n private callPropHook<K extends keyof ModuleTypeToPropsMapping[T]>(\n hookType: \"onSet\" | \"onAfterSet\",\n key: K,\n value: ModuleTypeToPropsMapping[T][K],\n ): ModuleTypeToPropsMapping[T][K] | undefined {\n const hookName = `${hookType}${upperFirst(key as string)}`;\n const hook = this[hookName as keyof this];\n\n if (typeof hook === \"function\") {\n const result = (\n hook as (\n value: ModuleTypeToPropsMapping[T][K],\n ) => ModuleTypeToPropsMapping[T][K] | undefined\n ).call(this, value);\n return result;\n }\n return undefined;\n }\n\n serialize(): IModuleSerialize<T> {\n return {\n id: this.id,\n name: this.name,\n moduleType: this.moduleType,\n voiceNo: this.voiceNo,\n props: this.props,\n inputs: this.inputs.serialize(),\n outputs: this.outputs.serialize(),\n };\n }\n\n plug({\n audioModule,\n from,\n to,\n }: {\n audioModule: AnyModule;\n from: string;\n to: string;\n }) {\n const output = this.outputs.findByName(from);\n const input = audioModule.inputs.findByName(to);\n\n output.plug(input);\n }\n\n protected rePlugAll(callback?: () => void) {\n this.inputs.rePlugAll(callback);\n this.outputs.rePlugAll(callback);\n }\n\n protected unPlugAll() {\n this.inputs.unPlugAll();\n this.outputs.unPlugAll();\n }\n\n start(_time: ContextTime): void {\n // Optional implementation in modules\n }\n\n stop(_time: ContextTime): void {\n // Optional implementation in modules\n }\n\n triggerAttack(note: Note, _triggeredAt: ContextTime): void {\n if (this.activeNotes.some((n) => n.fullName === note.fullName)) return;\n\n this.activeNotes.push(note);\n }\n\n triggerRelease(note: Note, _triggeredAt: ContextTime): void {\n this.activeNotes = this.activeNotes.filter(\n (n) => n.fullName !== note.fullName,\n );\n }\n\n handleCC(_event: MidiEvent, _triggeredAt: ContextTime): void {\n // Optional implementation in modules\n }\n\n onMidiEvent = (midiEvent: MidiEvent) => {\n const { note, triggeredAt } = midiEvent;\n\n switch (midiEvent.type) {\n case MidiEventType.noteOn: {\n this.triggerAttack(note!, triggeredAt);\n break;\n }\n case MidiEventType.noteOff:\n this.triggerRelease(note!, triggeredAt);\n break;\n case MidiEventType.cc:\n this.handleCC(midiEvent, triggeredAt);\n break;\n default:\n throw Error(\"This type is not a note\");\n }\n };\n\n triggerPropsUpdate = () => {\n if (this.pendingUIUpdates) return;\n\n this.pendingUIUpdates = true;\n this.sheduleTriggerUpdate();\n };\n\n private sheduleTriggerUpdate() {\n requestAnimationFrame(() => {\n this.engine._triggerPropsUpdate({\n id: this.id,\n moduleType: this.moduleType,\n voiceNo: this.voiceNo,\n name: this.name,\n props: this.props,\n });\n this.pendingUIUpdates = false;\n });\n }\n\n dispose() {\n this.inputs.unPlugAll();\n this.outputs.unPlugAll();\n }\n\n protected registerDefaultIOs(value: \"both\" | \"in\" | \"out\" = \"both\") {\n this.registerMidiInput({\n name: \"midi in\",\n onMidiEvent: this.onMidiEvent,\n });\n\n if (!this.audioNode) return;\n\n if (value === \"in\" || value === \"both\") {\n this.registerAudioInput({\n name: \"in\",\n getAudioNode: () => this.audioNode!,\n });\n }\n\n if (value === \"out\" || value === \"both\") {\n this.registerAudioOutput({\n name: \"out\",\n getAudioNode: () => this.audioNode!,\n });\n }\n }\n\n protected registerAudioInput(props: Omit<AudioInputProps, \"ioType\">) {\n return this.inputs.add({ ...props, ioType: IOType.AudioInput });\n }\n\n protected registerAudioOutput(props: Omit<AudioOutputProps, \"ioType\">) {\n return this.outputs.add({ ...props, ioType: IOType.AudioOutput });\n }\n\n protected registerMidiInput(props: Omit<MidiInputProps, \"ioType\">) {\n return this.inputs.add({ ...props, ioType: IOType.MidiInput });\n }\n\n protected registerMidiOutput(props: Omit<MidiOutputProps, \"ioType\">) {\n return this.outputs.add({\n ...props,\n ioType: IOType.MidiOutput,\n });\n }\n\n protected get engine() {\n return Engine.getById(this.engineId);\n }\n\n protected get context() {\n return this.engine.context;\n }\n}\n","import { assertNever } from \"@blibliki/utils\";\nimport { sortBy } from \"es-toolkit\";\nimport { ModuleType } from \"@/modules\";\nimport { Module } from \"../module\";\nimport { PolyModule } from \"../module/PolyModule\";\nimport {\n AudioInput,\n AudioInputProps,\n AudioOutput,\n AudioOutputProps,\n} from \"./AudioIO\";\nimport { Base, IOType } from \"./Base\";\nimport {\n MidiInput,\n MidiInputProps,\n MidiOutput,\n MidiOutputProps,\n} from \"./MidiIO\";\nimport {\n PolyAudioInput,\n PolyAudioInputProps,\n PolyAudioOutput,\n PolyAudioOutputProps,\n} from \"./PolyAudioIO\";\n\nexport enum CollectionType {\n Input = \"Input\",\n Output = \"Output\",\n}\n\ntype IMappedIOProps = {\n [CollectionType.Input]:\n | AudioInputProps\n | PolyAudioInputProps\n | MidiInputProps;\n [CollectionType.Output]:\n | AudioOutputProps\n | PolyAudioOutputProps\n | MidiOutputProps;\n};\n\ntype IIOTypeTOClass = {\n [IOType.AudioInput]: AudioInput;\n [IOType.AudioOutput]: AudioOutput;\n [IOType.PolyAudioInput]: PolyAudioInput;\n [IOType.PolyAudioOutput]: PolyAudioOutput;\n [IOType.MidiInput]: MidiInput;\n [IOType.MidiOutput]: MidiOutput;\n};\n\nexport default abstract class IOCollection<T extends CollectionType> {\n module: Module<ModuleType> | PolyModule<ModuleType>;\n collection: Base[] = [];\n collectionType: T;\n\n constructor(\n collectionType: T,\n module: Module<ModuleType> | PolyModule<ModuleType>,\n ) {\n this.collectionType = collectionType;\n this.module = module;\n }\n\n add<TT extends IMappedIOProps[T]>(props: TT): IIOTypeTOClass[TT[\"ioType\"]] {\n let io:\n | AudioInput\n | AudioOutput\n | PolyAudioInput\n | PolyAudioOutput\n | MidiInput\n | MidiOutput;\n this.validateUniqName(props.name);\n\n switch (props.ioType) {\n case IOType.AudioInput:\n if (this.module instanceof PolyModule) throw Error(\"Not compatible\");\n io = new AudioInput(this.module, props);\n break;\n case IOType.AudioOutput:\n if (this.module instanceof PolyModule) throw Error(\"Not compatible\");\n io = new AudioOutput(this.module, props);\n break;\n case IOType.PolyAudioInput:\n if (this.module instanceof Module) throw Error(\"Not compatible\");\n io = new PolyAudioInput(this.module, props);\n break;\n case IOType.PolyAudioOutput:\n if (this.module instanceof Module) throw Error(\"Not compatible\");\n io = new PolyAudioOutput(this.module, props);\n break;\n case IOType.MidiInput:\n io = new MidiInput(this.module, props);\n break;\n case IOType.MidiOutput:\n io = new MidiOutput(this.module, props);\n break;\n default:\n assertNever(props);\n }\n\n this.collection.push(io);\n\n return io as IIOTypeTOClass[TT[\"ioType\"]];\n }\n\n unPlugAll() {\n this.collection.forEach((io) => {\n io.unPlugAll();\n });\n }\n\n rePlugAll(callback?: () => void) {\n this.collection.forEach((io) => {\n io.rePlugAll(callback);\n });\n }\n\n find(id: string) {\n const io = this.collection.find((io) => io.id === id);\n if (!io) throw Error(`The io with id ${id} is not exists`);\n\n return io;\n }\n\n findByName(name: string) {\n const io = this.collection.find((io) => io.name === name);\n if (!io) throw Error(`The io with name ${name} is not exists`);\n\n return io;\n }\n\n serialize() {\n return sortBy(this.collection, [(io) => (io.isMidi() ? -1 : 1)]).map((io) =>\n io.serialize(),\n );\n }\n\n private validateUniqName(name: string) {\n if (this.collection.some((io) => io.name === name)) {\n throw Error(`An io with name ${name} is already exists`);\n }\n }\n}\n\nexport class InputCollection extends IOCollection<CollectionType.Input> {\n constructor(module: Module<ModuleType> | PolyModule<ModuleType>) {\n super(CollectionType.Input, module);\n }\n}\n\nexport class OutputCollection extends IOCollection<CollectionType.Output> {\n constructor(module: Module<ModuleType> | PolyModule<ModuleType>) {\n super(CollectionType.Output, module);\n }\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport { deterministicId, Optional, uuidv4 } from \"@blibliki/utils\";\nimport { Engine } from \"@/Engine\";\nimport { ModuleType, ModuleTypeToPropsMapping } from \"@/modules\";\nimport {\n IIOSerialize,\n InputCollection,\n IOType,\n MidiInputProps,\n MidiOutputProps,\n OutputCollection,\n} from \"../IO\";\nimport { PolyAudioInputProps, PolyAudioOutputProps } from \"../IO/PolyAudioIO\";\nimport MidiEvent from \"../midi/MidiEvent\";\nimport { IModule, IModuleConstructor, Module } from \"./Module\";\n\nexport type IPolyModule<T extends ModuleType> = Omit<IModule<T>, \"voiceNo\"> & {\n voices: number;\n};\n\nexport type IPolyModuleSerialize<T extends ModuleType> = IPolyModule<T> & {\n inputs: IIOSerialize[];\n outputs: IIOSerialize[];\n};\n\nexport type IPolyModuleConstructor<T extends ModuleType> = Optional<\n IPolyModule<T>,\n \"id\"\n> & {\n monoModuleConstructor: (\n engineId: string,\n params: IModuleConstructor<T>,\n ) => Module<T>;\n};\n\nexport abstract class PolyModule<\n T extends ModuleType,\n> implements IPolyModule<T> {\n id: string;\n engineId: string;\n moduleType: T;\n audioModules!: Module<T>[];\n inputs: InputCollection;\n outputs: OutputCollection;\n protected monoModuleConstructor: IPolyModuleConstructor<T>[\"monoModuleConstructor\"];\n protected _props!: ModuleTypeToPropsMapping[T];\n private _voices!: number;\n private _name!: string;\n private pendingUIUpdates = false;\n\n constructor(engineId: string, params: IPolyModuleConstructor<T>) {\n const { id, name, moduleType, voices, monoModuleConstructor, props } =\n params;\n\n this.audioModules = [];\n\n this.monoModuleConstructor = monoModuleConstructor;\n this.id = id ?? uuidv4();\n this.engineId = engineId;\n this.name = name;\n this.moduleType = moduleType;\n this._props = props;\n\n this.inputs = new InputCollection(\n this as unknown as PolyModule<ModuleType>,\n );\n this.outputs = new OutputCollection(\n this as unknown as PolyModule<ModuleType>,\n );\n\n // Defer hook calls until after subclass is fully initialized\n queueMicrotask(() => {\n this.voices = voices || 1;\n this.props = props;\n this.triggerPropsUpdate();\n });\n }\n\n get name() {\n return this._name;\n }\n\n set name(value: string) {\n this._name = value;\n this.audioModules.forEach((m) => (m.name = value));\n }\n\n get props(): ModuleTypeToPropsMapping[T] {\n return this._props;\n }\n\n set props(value: Partial<ModuleTypeToPropsMapping[T]>) {\n this._props = { ...this._props, ...value };\n this.audioModules.forEach((m) => (m.props = value));\n }\n\n get voices() {\n return this._voices;\n }\n\n set voices(value: number) {\n this._voices = value;\n this.adjustNumberOfModules();\n this.rePlugAll();\n }\n\n start(time: ContextTime): void {\n this.audioModules.forEach((m) => {\n m.start(time);\n });\n }\n\n stop(time: ContextTime): void {\n this.audioModules.forEach((m) => {\n m.stop(time);\n });\n }\n\n serialize(): IPolyModuleSerialize<T> {\n return {\n id: this.id,\n name: this.name,\n moduleType: this.moduleType,\n voices: this.voices,\n props: this.props,\n inputs: this.inputs.serialize(),\n outputs: this.outputs.serialize(),\n };\n }\n\n plug({\n audioModule,\n from,\n to,\n }: {\n audioModule: Module<ModuleType> | PolyModule<ModuleType>;\n from: string;\n to: string;\n }) {\n const output = this.outputs.findByName(from);\n const input = audioModule.inputs.findByName(to);\n\n output.plug(input);\n }\n\n rePlugAll(callback?: () => void) {\n this.inputs.rePlugAll(callback);\n this.outputs.rePlugAll(callback);\n }\n\n protected unPlugAll() {\n this.inputs.unPlugAll();\n this.outputs.unPlugAll();\n }\n\n dispose() {\n this.inputs.unPlugAll();\n this.outputs.unPlugAll();\n this.audioModules.forEach((m) => {\n m.dispose();\n });\n }\n\n onMidiEvent = (midiEvent: MidiEvent) => {\n const voiceNo = midiEvent.voiceNo ?? 0;\n const audioModule = this.findVoice(voiceNo);\n audioModule.onMidiEvent(midiEvent);\n };\n\n triggerPropsUpdate = () => {\n if (this.pendingUIUpdates) return;\n\n this.pendingUIUpdates = true;\n this.sheduleTriggerUpdate();\n };\n\n private sheduleTriggerUpdate() {\n requestAnimationFrame(() => {\n this.engine._triggerPropsUpdate({\n id: this.id,\n moduleType: this.moduleType,\n voices: this.voices,\n name: this.name,\n props: this.props,\n });\n this.pendingUIUpdates = false;\n });\n }\n\n findVoice(voiceNo: number) {\n const moduleByVoice = this.audioModules.find((m) => m.voiceNo === voiceNo);\n if (!moduleByVoice)\n throw Error(`Voice ${voiceNo} on module ${this.name} not found`);\n\n return moduleByVoice;\n }\n\n protected registerDefaultIOs(value: \"both\" | \"in\" | \"out\" = \"both\") {\n this.registerMidiInput({\n name: \"midi in\",\n onMidiEvent: this.onMidiEvent,\n });\n\n if (value === \"in\" || value === \"both\") {\n this.registerAudioInput({\n name: \"in\",\n });\n }\n\n if (value === \"out\" || value === \"both\") {\n this.registerAudioOutput({\n name: \"out\",\n });\n }\n }\n\n protected registerAudioInput(props: Omit<PolyAudioInputProps, \"ioType\">) {\n return this.inputs.add({ ...props, ioType: IOType.PolyAudioInput });\n }\n\n protected registerAudioOutput(props: Omit<PolyAudioOutputProps, \"ioType\">) {\n return this.outputs.add({ ...props, ioType: IOType.PolyAudioOutput });\n }\n\n protected registerMidiInput(props: Omit<MidiInputProps, \"ioType\">) {\n return this.inputs.add({ ...props, ioType: IOType.MidiInput });\n }\n\n protected registerMidiOutput(props: Omit<MidiOutputProps, \"ioType\">) {\n return this.outputs.add({\n ...props,\n ioType: IOType.MidiOutput,\n });\n }\n\n private adjustNumberOfModules() {\n if (this.audioModules.length === this.voices) return;\n\n if (this.audioModules.length > this.voices) {\n const audioModule = this.audioModules.pop();\n audioModule?.dispose();\n } else {\n const voiceNo = this.audioModules.length;\n const id = deterministicId(this.id, voiceNo.toString());\n\n const audioModule = this.monoModuleConstructor(this.engineId, {\n id,\n name: this.name,\n moduleType: this.moduleType,\n voiceNo,\n props: { ...this.props },\n });\n\n this.audioModules.push(audioModule);\n }\n\n this.adjustNumberOfModules();\n }\n\n protected get engine() {\n return Engine.getById(this.engineId);\n }\n\n protected get context() {\n return this.engine.context;\n }\n}\n","import { AudioParam } from \"@blibliki/utils/web-audio-api\";\nimport { ModuleType } from \"@/modules\";\nimport { Module } from \"../module\";\nimport IO, { IOProps, IOType } from \"./Base\";\nimport { PolyAudioInput, PolyAudioOutput } from \"./PolyAudioIO\";\n\nexport type AudioIO = AudioInput | AudioOutput;\n\nexport type AudioInputProps = IOProps & {\n ioType: IOType.AudioInput;\n getAudioNode: () => AudioNode | AudioParam | AudioDestinationNode;\n};\n\nexport type AudioOutputProps = IOProps & {\n ioType: IOType.AudioOutput;\n getAudioNode: () => AudioNode;\n};\n\nexport class AudioInput\n extends IO<AudioOutput | PolyAudioOutput>\n implements AudioInputProps\n{\n declare ioType: IOType.AudioInput;\n getAudioNode: AudioInputProps[\"getAudioNode\"];\n\n constructor(module: Module<ModuleType>, props: AudioInputProps) {\n super(module, props);\n this.getAudioNode = props.getAudioNode;\n }\n}\n\nexport class AudioOutput\n extends IO<AudioInput | PolyAudioInput>\n implements AudioOutputProps\n{\n declare ioType: IOType.AudioOutput;\n getAudioNode!: AudioOutputProps[\"getAudioNode\"];\n\n constructor(module: Module<ModuleType>, props: AudioOutputProps) {\n super(module, props);\n this.getAudioNode = props.getAudioNode;\n }\n\n plug(io: AudioInput | PolyAudioInput, plugOther = true) {\n super.plug(io, plugOther);\n if (io instanceof PolyAudioInput) return;\n\n const input = io.getAudioNode();\n\n if (input instanceof AudioParam) {\n this.getAudioNode().connect(input);\n } else {\n this.getAudioNode().connect(input);\n }\n }\n\n unPlug(io: AudioInput | PolyAudioInput, plugOther = true) {\n super.unPlug(io, plugOther);\n if (io instanceof PolyAudioInput) return;\n\n const input = io.getAudioNode();\n\n try {\n if (input instanceof AudioParam) {\n this.getAudioNode().disconnect(input);\n } else {\n this.getAudioNode().disconnect(input);\n }\n } catch {\n // Ignore disconnect errors\n }\n }\n}\n","import { deterministicId } from \"@blibliki/utils\";\nimport { ModuleType } from \"@/modules\";\nimport { Module } from \"../module\";\nimport { PolyModule } from \"../module/PolyModule\";\nimport { AudioInput, AudioOutput } from \"./AudioIO\";\nimport { MidiInput, MidiOutput } from \"./MidiIO\";\nimport { PolyAudioInput, PolyAudioOutput } from \"./PolyAudioIO\";\n\nexport type IOProps = {\n name: string;\n ioType: IOType;\n};\n\nexport type IIOSerialize = IOProps & {\n id: string;\n moduleId: string;\n};\n\nexport enum IOType {\n AudioInput = \"audioInput\",\n AudioOutput = \"audioOutput\",\n PolyAudioInput = \"polyAudioInput\",\n PolyAudioOutput = \"polyAudioOutput\",\n MidiOutput = \"midiOutput\",\n MidiInput = \"midiInput\",\n}\n\nexport type IIO = {\n id: string;\n module: Module<ModuleType> | PolyModule<ModuleType>;\n} & IOProps;\n\nexport abstract class Base implements IIO {\n id: string;\n ioType: IOType;\n name: string;\n module: Module<ModuleType> | PolyModule<ModuleType>;\n connections: Base[];\n\n constructor(\n module: Module<ModuleType> | PolyModule<ModuleType>,\n props: IOProps,\n ) {\n this.module = module;\n this.name = props.name;\n this.ioType = props.ioType;\n this.id = deterministicId(this.module.id, this.name);\n this.connections = [];\n }\n\n plug(io: Base, plugOther = true) {\n this.connections.push(io);\n if (plugOther) io.plug(this, false);\n }\n\n unPlug(io: Base, plugOther = true) {\n this.connections = this.connections.filter(\n (currentIO) => currentIO.id !== io.id,\n );\n if (plugOther) io.unPlug(this, false);\n }\n\n rePlugAll(callback?: () => void) {\n const connections = this.connections;\n this.unPlugAll();\n if (callback) callback();\n\n connections.forEach((otherIO) => {\n this.plug(otherIO);\n });\n }\n\n unPlugAll() {\n this.connections.forEach((otherIO) => {\n this.unPlug(otherIO);\n });\n }\n\n isAudio(): this is\n | AudioInput\n | AudioOutput\n | PolyAudioInput\n | PolyAudioOutput {\n return (\n this.ioType === IOType.AudioInput ||\n this.ioType === IOType.AudioOutput ||\n this.ioType === IOType.PolyAudioInput ||\n this.ioType === IOType.PolyAudioOutput\n );\n }\n\n isMidi(): this is MidiInput | MidiOutput {\n return (\n this.ioType === IOType.MidiInput || this.ioType === IOType.MidiOutput\n );\n }\n\n serialize(): IIOSerialize {\n return {\n id: this.id,\n name: this.name,\n ioType: this.ioType,\n moduleId: this.module.id,\n };\n }\n}\n\nexport default abstract class IO<Connection extends Base> extends Base {\n declare connections: Connection[];\n\n plug(io: Connection, plugOther?: boolean): void {\n super.plug(io, plugOther);\n }\n\n unPlug(io: Connection, plugOther?: boolean): void {\n super.unPlug(io, plugOther);\n }\n}\n","import { ModuleType } from \"@/modules\";\nimport { PolyModule } from \"../module/PolyModule\";\nimport { AudioInput, AudioOutput } from \"./AudioIO\";\nimport IO, { IOProps, IOType } from \"./Base\";\n\nexport type PolyAudioIO = PolyAudioInput | PolyAudioOutput;\n\nexport type PolyAudioInputProps = IOProps & {\n ioType: IOType.PolyAudioInput;\n};\n\nexport type PolyAudioOutputProps = IOProps & {\n ioType: IOType.PolyAudioOutput;\n};\n\nexport class PolyAudioInput\n extends IO<PolyAudioOutput | AudioOutput>\n implements PolyAudioInputProps\n{\n declare ioType: IOType.PolyAudioInput;\n declare module: PolyModule<ModuleType>;\n\n plug(io: PolyAudioOutput | AudioOutput, plugOther = true) {\n super.plug(io, plugOther);\n if (!plugOther && io instanceof PolyAudioOutput) return;\n\n plugOrUnplug(this, io, true);\n }\n\n unPlug(io: PolyAudioOutput | AudioOutput, plugOther = true) {\n super.unPlug(io, plugOther);\n if (!plugOther && io instanceof PolyAudioOutput) return;\n\n plugOrUnplug(this, io, false);\n }\n\n findIOByVoice(voice: number): AudioInput {\n return this.module\n .findVoice(voice)\n .inputs.findByName(this.name) as AudioInput;\n }\n}\n\nexport class PolyAudioOutput\n extends IO<PolyAudioInput | AudioInput>\n implements PolyAudioOutputProps\n{\n declare ioType: IOType.PolyAudioOutput;\n declare module: PolyModule<ModuleType>;\n\n plug(io: PolyAudioInput | AudioInput, plugOther = true) {\n super.plug(io, plugOther);\n if (!plugOther && io instanceof PolyAudioInput) return;\n\n plugOrUnplug(this, io, true);\n }\n\n unPlug(io: PolyAudioInput | AudioInput, plugOther = true) {\n super.unPlug(io, plugOther);\n if (!plugOther && io instanceof PolyAudioInput) return;\n\n plugOrUnplug(this, io, false);\n }\n\n findIOByVoice(voice: number): AudioOutput {\n return this.module\n .findVoice(voice)\n .outputs.findByName(this.name) as AudioOutput;\n }\n}\n\nfunction plugOrUnplug(\n thisIO: PolyAudioInput,\n otherIO: PolyAudioOutput | AudioOutput,\n isPlug: boolean,\n): void;\nfunction plugOrUnplug(\n thisIO: PolyAudioOutput,\n otherIO: PolyAudioInput | AudioInput,\n isPlug: boolean,\n): void;\nfunction plugOrUnplug(\n thisIO: PolyAudioInput | PolyAudioOutput,\n otherIO: PolyAudioOutput | AudioOutput | PolyAudioInput | AudioInput,\n isPlug: boolean,\n) {\n if (otherIO instanceof PolyAudioInput || otherIO instanceof PolyAudioOutput) {\n const maxVoices = Math.max(thisIO.module.voices, otherIO.module.voices);\n\n for (let voice = 0; voice < maxVoices; voice++) {\n const thisMonoIO = thisIO.findIOByVoice(voice % thisIO.module.voices);\n const otherMonoIO = otherIO.findIOByVoice(voice % otherIO.module.voices);\n\n if (isPlug) {\n // @ts-expect-error: temp solution until guard this input plug to output\n thisMonoIO.plug(otherMonoIO);\n } else {\n // @ts-expect-error: temp solution until guard this input plug to output\n thisMonoIO.unPlug(otherMonoIO);\n }\n }\n } else {\n for (let voice = 0; voice < thisIO.module.voices; voice++) {\n const thisMonoIO = thisIO.findIOByVoice(voice);\n\n if (isPlug) {\n // @ts-expect-error: temp solution until guard this input plug to output\n thisMonoIO.plug(otherIO);\n } else {\n // @ts-expect-error: temp solution until guard this input plug to output\n thisMonoIO.unPlug(otherIO);\n }\n }\n }\n}\n","import { ModuleType } from \"@/modules\";\nimport MidiEvent from \"../midi/MidiEvent\";\nimport { Module } from \"../module\";\nimport { PolyModule } from \"../module/PolyModule\";\nimport IO, { IOProps, IOType } from \"./Base\";\n\nexport type MidiIO = MidiInput | MidiOutput;\n\nexport type MidiInputProps = IOProps & {\n ioType: IOType.MidiInput;\n onMidiEvent: (event: MidiEvent) => void;\n};\n\nexport type MidiOutputProps = IOProps & {\n ioType: IOType.MidiOutput;\n};\n\nexport class MidiInput extends IO<MidiOutput> implements MidiInputProps {\n declare ioType: IOType.MidiInput;\n onMidiEvent: MidiInputProps[\"onMidiEvent\"];\n\n constructor(\n module: Module<ModuleType> | PolyModule<ModuleType>,\n props: MidiInputProps,\n ) {\n super(module, props);\n this.onMidiEvent = props.onMidiEvent;\n }\n}\n\nexport class MidiOutput extends IO<MidiInput> implements MidiOutputProps {\n declare ioType: IOType.MidiOutput;\n\n onMidiEvent = (event: MidiEvent) => {\n this.midiConnections.forEach((input) => {\n input.onMidiEvent(event);\n });\n };\n\n private get midiConnections() {\n return this.connections.filter((input) => input instanceof MidiInput);\n }\n}\n","const frequencyTable = new Map<string, number>([\n [\"C0\", 16.35],\n [\"C#0\", 17.32],\n [\"Db0\", 17.32],\n [\"D0\", 18.35],\n [\"D#0\", 19.45],\n [\"Eb0\", 19.45],\n [\"E0\", 20.6],\n [\"F0\", 21.83],\n [\"F#0\", 23.12],\n [\"Gb0\", 23.12],\n [\"G0\", 24.5],\n [\"G#0\", 25.96],\n [\"Ab0\", 25.96],\n [\"A0\", 27.5],\n [\"A#0\", 29.14],\n [\"Bb0\", 29.14],\n [\"B0\", 30.87],\n [\"C1\", 32.7],\n [\"C#1\", 34.65],\n [\"Db1\", 34.65],\n [\"D1\", 36.71],\n [\"D#1\", 38.89],\n [\"Eb1\", 38.89],\n [\"E1\", 41.2],\n [\"F1\", 43.65],\n [\"F#1\", 46.25],\n [\"Gb1\", 46.25],\n [\"G1\", 49.0],\n [\"G#1\", 51.91],\n [\"Ab1\", 51.91],\n [\"A1\", 55.0],\n [\"A#1\", 58.27],\n [\"Bb1\", 58.27],\n [\"B1\", 61.74],\n [\"C2\", 65.41],\n [\"C#2\", 69.3],\n [\"Db2\", 69.3],\n [\"D2\", 73.42],\n [\"D#2\", 77.78],\n [\"Eb2\", 77.78],\n [\"E2\", 82.41],\n [\"F2\", 87.31],\n [\"F#2\", 92.5],\n [\"Gb2\", 92.5],\n [\"G2\", 98.0],\n [\"G#2\", 103.83],\n [\"Ab2\", 103.83],\n [\"A2\", 110.0],\n [\"A#2\", 116.54],\n [\"Bb2\", 116.54],\n [\"B2\", 123.47],\n [\"C3\", 130.81],\n [\"C#3\", 138.59],\n [\"Db3\", 138.59],\n [\"D3\", 146.83],\n [\"D#3\", 155.56],\n [\"Eb3\", 155.56],\n [\"E3\", 164.81],\n [\"F3\", 174.61],\n [\"F#3\", 185.0],\n [\"Gb3\", 185.0],\n [\"G3\", 196.0],\n [\"G#3\", 207.65],\n [\"Ab3\", 207.65],\n [\"A3\", 220.0],\n [\"A#3\", 233.08],\n [\"Bb3\", 233.08],\n [\"B3\", 246.94],\n [\"C4\", 261.63],\n [\"C#4\", 277.18],\n [\"Db4\", 277.18],\n [\"D4\", 293.66],\n [\"D#4\", 311.13],\n [\"Eb4\", 311.13],\n [\"E4\", 329.63],\n [\"F4\", 349.23],\n [\"F#4\", 369.99],\n [\"Gb4\", 369.99],\n [\"G4\", 392.0],\n [\"G#4\", 415.3],\n [\"Ab4\", 415.3],\n [\"A4\", 440.0],\n [\"A#4\", 466.16],\n [\"Bb4\", 466.16],\n [\"B4\", 493.88],\n [\"C5\", 523.25],\n [\"C#5\", 554.37],\n [\"Db5\", 554.37],\n [\"D5\", 587.33],\n [\"D#5\", 622.25],\n [\"Eb5\", 622.25],\n [\"E5\", 659.26],\n [\"F5\", 698.46],\n [\"F#5\", 739.99],\n [\"Gb5\", 739.99],\n [\"G5\", 783.99],\n [\"G#5\", 830.61],\n [\"Ab5\", 830.61],\n [\"A5\", 880.0],\n [\"A#5\", 932.33],\n [\"Bb5\", 932.33],\n [\"B5\", 987.77],\n [\"C6\", 1046.5],\n [\"C#6\", 1108.73],\n [\"Db6\", 1108.73],\n [\"D6\", 1174.66],\n [\"D#6\", 1244.51],\n [\"Eb6\", 1244.51],\n [\"E6\", 1318.51],\n [\"F6\", 1396.91],\n [\"F#6\", 1479.98],\n [\"Gb6\", 1479.98],\n [\"G6\", 1567.98],\n [\"G#6\", 1661.22],\n [\"Ab6\", 1661.22],\n [\"A6\", 1760.0],\n [\"A#6\", 1864.66],\n [\"Bb6\", 1864.66],\n [\"B6\", 1975.53],\n [\"C7\", 2093.0],\n [\"C#7\", 2217.46],\n [\"Db7\", 2217.46],\n [\"D7\", 2349.32],\n [\"D#7\", 2489.02],\n [\"Eb7\", 2489.02],\n [\"E7\", 2637.02],\n [\"F7\", 2793.83],\n [\"F#7\", 2959.96],\n [\"Gb7\", 2959.96],\n [\"G7\", 3135.96],\n [\"G#7\", 3322.44],\n [\"Ab7\", 3322.44],\n [\"A7\", 3520.0],\n [\"A#7\", 3729.31],\n [\"Bb7\", 3729.31],\n [\"B7\", 3951.07],\n [\"C8\", 4186.01],\n [\"C#8\", 4434.92],\n [\"Db8\", 4434.92],\n [\"D8\", 4698.64],\n [\"D#8\", 4978.03],\n [\"Eb8\", 4978.03],\n]);\n\nexport default frequencyTable;\n","import { Seconds } from \"@blibliki/transport\";\nimport Message from \"../midi/Message\";\nimport frequencyTable from \"./frequencyTable\";\n\nconst Notes = [\"C\", \"C#\", \"D\", \"D#\", \"E\", \"F\", \"F#\", \"G\", \"G#\", \"A\", \"A#\", \"B\"];\n\nconst MIDI_OCTAVE_SYTSTEM = 2;\n\nexport type INote = {\n name: string;\n octave: number;\n frequency: number;\n duration?: Seconds;\n velocity?: number;\n};\n\nexport default class Note implements INote {\n static _notes: Note[];\n name!: string;\n octave!: number;\n velocity = 1;\n duration?: Seconds;\n\n static fromFrequency(frequency: number) {\n let noteName: string | undefined;\n\n for (const [note, freq] of frequencyTable) {\n if (freq !== frequency) continue;\n\n noteName = note;\n break;\n }\n\n if (!noteName) throw Error(\"Not matching frequency with a note\");\n\n return new Note(noteName);\n }\n\n static fromEvent(message: Message) {\n const name = Notes[message.data[1] % 12];\n const octave = Math.floor(message.data[1] / 12) - 2;\n\n return new Note(`${name}${octave}`);\n }\n\n static notes(octave = 3) {\n return Notes.map((note: string) => new Note(`${note}${octave}`));\n }\n\n constructor(note: Omit<INote, \"frequency\"> | string) {\n if (typeof note === \"string\") {\n this.fromString(note);\n } else {\n this.fromProps(note);\n }\n }\n\n get isSemi() {\n return this.name.endsWith(\"#\");\n }\n\n get fullName() {\n return `${this.name}${this.octave}`;\n }\n\n get frequency(): number {\n return frequencyTable.get(`${this.name}${this.octave}`)!;\n }\n\n midiData(noteOn = true): Uint8Array {\n const statusByte = noteOn ? 0x90 : 0x80;\n return new Uint8Array([statusByte, this.midiNumber, this.velocity * 100]);\n }\n\n get midiNumber(): number {\n return (this.octave + MIDI_OCTAVE_SYTSTEM) * 12 + this.noteIndex;\n }\n\n get noteIndex(): number {\n return Notes.indexOf(this.name);\n }\n\n valueOf() {\n return this.fullName;\n }\n\n serialize(): INote {\n return {\n name: this.name,\n octave: this.octave,\n frequency: this.frequency,\n velocity: this.velocity,\n duration: this.duration,\n };\n }\n\n private fromString(string: string) {\n const matches = /(\\w#?)(\\d)?/.exec(string) ?? [];\n\n this.name = matches[1];\n this.octave = matches[2] ? parseInt(matches[2]) : 1;\n }\n\n private fromProps(props: Omit<INote, \"frequency\">) {\n Object.assign(this, props);\n }\n}\n","/**\n * Simple wrapper around MIDI message data (Uint8Array)\n * Replaces the webmidi Message class with native Web MIDI API data\n */\nexport default class Message {\n public readonly data: Uint8Array;\n\n constructor(data: Uint8Array) {\n this.data = data;\n }\n\n /**\n * Returns the data bytes (excluding the status byte)\n */\n get dataBytes(): number[] {\n return Array.from(this.data.slice(1));\n }\n\n /**\n * Returns the MIDI message type based on the status byte\n */\n get type(): string {\n const statusByte = this.data[0];\n const messageType = statusByte & 0xf0;\n\n switch (messageType) {\n case 0x90: // Note On\n // Check if velocity is 0 (which is actually Note Off)\n return this.data[2] === 0 ? \"noteoff\" : \"noteon\";\n case 0x80: // Note Off\n return \"noteoff\";\n case 0xb0: // Control Change\n return \"controlchange\";\n case 0xe0: // Pitch Bend\n return \"pitchbend\";\n case 0xd0: // Channel Pressure (Aftertouch)\n return \"channelaftertouch\";\n case 0xa0: // Polyphonic Key Pressure\n return \"keyaftertouch\";\n case 0xc0: // Program Change\n return \"programchange\";\n default:\n return \"unknown\";\n }\n }\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport Note, { INote } from \"../Note\";\nimport Message from \"./Message\";\n\nexport enum MidiEventType {\n noteOn = \"noteon\",\n noteOff = \"noteoff\",\n cc = \"controlchange\",\n}\n\nexport default class MidiEvent {\n note?: Note;\n voiceNo?: number;\n readonly triggeredAt: ContextTime;\n private message: Message;\n\n static fromNote(\n noteName: string | Note | Omit<INote, \"frequency\">,\n noteOn = true,\n triggeredAt: ContextTime,\n ): MidiEvent {\n const note = noteName instanceof Note ? noteName : new Note(noteName);\n\n return new MidiEvent(new Message(note.midiData(noteOn)), triggeredAt);\n }\n\n static fromCC(\n cc: number,\n value: number,\n triggeredAt: ContextTime,\n ): MidiEvent {\n return new MidiEvent(\n new Message(new Uint8Array([0xb0, cc, value])),\n triggeredAt,\n );\n }\n\n constructor(message: Message, triggeredAt: ContextTime) {\n this.message = message;\n this.triggeredAt = triggeredAt;\n this.defineNotes();\n }\n\n get type() {\n return this.message.type as MidiEventType;\n }\n\n get isNote() {\n return (\n this.type === MidiEventType.noteOn || this.type === MidiEventType.noteOff\n );\n }\n\n get isCC() {\n return this.type === MidiEventType.cc;\n }\n\n get cc(): number | undefined {\n if (!this.isCC) return;\n\n return this.message.dataBytes[0];\n }\n\n get ccValue(): number | undefined {\n if (!this.isCC) return;\n\n return this.message.dataBytes[1];\n }\n\n defineNotes() {\n if (!this.isNote) return;\n if (this.note) return;\n\n this.note = Note.fromEvent(this.message);\n }\n\n get rawMessage() {\n return this.message;\n }\n\n clone(voiceNo?: number) {\n const newEvent = new MidiEvent(this.message, this.triggeredAt);\n newEvent.voiceNo = voiceNo;\n\n return newEvent;\n }\n}\n","import { Optional, uuidv4 } from \"@blibliki/utils\";\nimport { Engine } from \"@/Engine\";\n\ntype IPlug = {\n moduleId: string;\n ioName: string;\n};\n\nexport type IRoute = {\n id: string;\n source: IPlug;\n destination: IPlug;\n};\n\nexport class Routes {\n engine: Engine;\n routes: Map<string, IRoute>;\n\n constructor(engine: Engine) {\n this.engine = engine;\n this.routes = new Map();\n }\n\n addRoute(props: Optional<IRoute, \"id\">): IRoute {\n const id = props.id ?? uuidv4();\n const route = { ...props, id };\n this.routes.set(id, route);\n\n this.plug(id);\n\n return route;\n }\n\n removeRoute(id: string) {\n this.unPlug(id);\n this.routes.delete(id);\n }\n\n clear() {\n this.routes.forEach((_, id) => {\n this.removeRoute(id);\n });\n }\n\n replug() {\n this.routes.forEach((_, id) => {\n const { sourceIO, destinationIO } = this.getIOs(id);\n sourceIO.rePlugAll();\n destinationIO.rePlugAll();\n });\n }\n\n serialize(): IRoute[] {\n return Array.from(this.routes.values());\n }\n\n private plug(id: string) {\n const { sourceIO, destinationIO } = this.getIOs(id);\n sourceIO.plug(destinationIO);\n }\n\n private unPlug(id: string) {\n const { sourceIO, destinationIO } = this.getIOs(id);\n sourceIO.unPlug(destinationIO);\n }\n\n private find(id: string): IRoute {\n const route = this.routes.get(id);\n if (!route) throw Error(`Route with id ${id} not found`);\n\n return route;\n }\n\n private getIOs(id: string) {\n const route = this.find(id);\n const { source, destination } = route;\n\n const sourceIO = this.engine.findIO(\n source.moduleId,\n source.ioName,\n \"output\",\n );\n const destinationIO = this.engine.findIO(\n destination.moduleId,\n destination.ioName,\n \"input\",\n );\n\n return { sourceIO, destinationIO };\n }\n}\n","import { Context } from \"@blibliki/utils\";\nimport Message from \"./Message\";\nimport MidiEvent, { MidiEventType } from \"./MidiEvent\";\nimport type { IMidiInputPort, IMidiMessageEvent } from \"./adapters\";\n\nexport enum MidiPortState {\n connected = \"connected\",\n disconnected = \"disconnected\",\n}\n\nexport type IMidiDevice = {\n id: string;\n name: string;\n state: MidiPortState;\n};\n\nexport type IMidiInput = IMidiDevice & {\n eventListerCallbacks: EventListerCallback[];\n};\n\nexport type EventListerCallback = (event: MidiEvent) => void;\n\nexport default class MidiDevice implements IMidiDevice {\n id: string;\n name: string;\n eventListerCallbacks: EventListerCallback[] = [];\n\n private context: Readonly<Context>;\n private input: IMidiInputPort;\n private messageHandler: ((event: IMidiMessageEvent) => void) | null = null;\n\n constructor(input: IMidiInputPort, context: Context) {\n this.id = input.id;\n this.name = input.name;\n this.input = input;\n this.context = context;\n\n this.connect();\n }\n\n get state() {\n return this.input.state as MidiPortState;\n }\n\n connect() {\n this.messageHandler = (e: IMidiMessageEvent) => {\n this.processEvent(e);\n };\n this.input.addEventListener(this.messageHandler);\n }\n\n disconnect() {\n if (this.messageHandler) {\n this.input.removeEventListener(this.messageHandler);\n this.messageHandler = null;\n }\n }\n\n serialize() {\n const { id, name, state } = this;\n\n return { id, name, state };\n }\n\n addEventListener(callback: EventListerCallback) {\n this.eventListerCallbacks.push(callback);\n }\n\n removeEventListener(callback: EventListerCallback) {\n this.eventListerCallbacks = this.eventListerCallbacks.filter(\n (c) => c !== callback,\n );\n }\n\n private processEvent(event: IMidiMessageEvent) {\n const message = new Message(event.data);\n const midiEvent = new MidiEvent(\n message,\n this.context.browserToContextTime(event.timeStamp),\n );\n\n switch (midiEvent.type) {\n case MidiEventType.noteOn:\n case MidiEventType.noteOff:\n case MidiEventType.cc:\n this.eventListerCallbacks.forEach((callback) => {\n callback(midiEvent);\n });\n }\n }\n}\n","import { Context } from \"@blibliki/utils\";\nimport Note from \"../Note\";\nimport { EventListerCallback, IMidiInput, MidiPortState } from \"./MidiDevice\";\nimport MidiEvent from \"./MidiEvent\";\n\nconst MAP_KEYS: Record<string, Note> = {\n a: new Note(\"C3\"),\n s: new Note(\"D3\"),\n d: new Note(\"E3\"),\n f: new Note(\"F3\"),\n g: new Note(\"G3\"),\n h: new Note(\"A3\"),\n j: new Note(\"B3\"),\n k: new Note(\"C4\"),\n l: new Note(\"D4\"),\n w: new Note(\"C#3\"),\n e: new Note(\"D#3\"),\n t: new Note(\"F#3\"),\n y: new Note(\"G#3\"),\n u: new Note(\"A#3\"),\n o: new Note(\"C#4\"),\n p: new Note(\"D#4\"),\n};\n\nconst computerKeyboardData = () => ({\n id: \"computer_keyboard\",\n name: \"Computer Keyboard\",\n state: MidiPortState.connected,\n});\n\nexport default class ComputerKeyboardInput implements IMidiInput {\n id: string;\n name: string;\n state: MidiPortState;\n eventListerCallbacks: EventListerCallback[] = [];\n private context: Readonly<Context>;\n\n constructor(context: Context) {\n const { id, name, state } = computerKeyboardData();\n this.id = id;\n this.name = name;\n this.state = state;\n this.context = context;\n\n document.addEventListener(\"keydown\", this.onKeyTrigger(true));\n document.addEventListener(\"keyup\", this.onKeyTrigger(false));\n }\n\n addEventListener(callback: EventListerCallback) {\n this.eventListerCallbacks.push(callback);\n }\n\n removeEventListener(callback: EventListerCallback) {\n this.eventListerCallbacks = this.eventListerCallbacks.filter(\n (c) => c !== callback,\n );\n }\n\n serialize() {\n const { id, name, state } = this;\n\n return { id, name, state };\n }\n\n onKeyTrigger = (noteOn: boolean) => (event: KeyboardEvent) => {\n const note = this.extractNote(event);\n if (!note) return;\n\n const midiEvent = MidiEvent.fromNote(\n note,\n noteOn,\n this.context.browserToContextTime(event.timeStamp),\n );\n this.eventListerCallbacks.forEach((callback) => {\n callback(midiEvent);\n });\n };\n\n private extractNote(event: KeyboardEvent): Note | undefined {\n if (event.repeat) return;\n\n return MAP_KEYS[event.key];\n }\n}\n","/**\n * MIDI adapter factory\n * Automatically selects the correct MIDI implementation based on the platform\n */\nimport { isNode } from \"es-toolkit\";\nimport NodeMidiAdapter from \"./NodeMidiAdapter\";\nimport WebMidiAdapter from \"./WebMidiAdapter\";\nimport type { IMidiAdapter } from \"./types\";\n\nexport * from \"./types\";\n\n/**\n * Creates the appropriate MIDI adapter for the current platform\n * @returns The MIDI adapter (Web MIDI API for browsers, node-midi for Node.js)\n */\nexport function createMidiAdapter(): IMidiAdapter {\n if (isNode()) {\n return new NodeMidiAdapter();\n }\n\n // Default to Web MIDI API for browsers\n return new WebMidiAdapter();\n}\n","/**\n * node-midi adapter for Node.js\n */\nimport { isNode } from \"es-toolkit\";\nimport type {\n IMidiAccess,\n IMidiAdapter,\n IMidiInputPort,\n MidiMessageCallback,\n} from \"./types\";\n\n// Dynamic import type for node-midi\ntype NodeMidiInput = {\n getPortCount(): number;\n getPortName(port: number): string;\n openPort(port: number): void;\n closePort(): void;\n on(\n event: \"message\",\n callback: (deltaTime: number, message: number[]) => void,\n ): void;\n off(\n event: \"message\",\n callback: (deltaTime: number, message: number[]) => void,\n ): void;\n isPortOpen(): boolean;\n};\n\ntype NodeMidiModule = {\n Input: new () => NodeMidiInput;\n};\n\nclass NodeMidiInputPort implements IMidiInputPort {\n readonly id: string;\n readonly name: string;\n private portIndex: number;\n private input: NodeMidiInput;\n private callbacks = new Set<MidiMessageCallback>();\n private handler: ((deltaTime: number, message: number[]) => void) | null =\n null;\n private _state: \"connected\" | \"disconnected\" = \"disconnected\";\n\n constructor(portIndex: number, name: string, input: NodeMidiInput) {\n this.portIndex = portIndex;\n this.id = `node-midi-${portIndex}`;\n this.name = name;\n this.input = input;\n }\n\n get state(): \"connected\" | \"disconnected\" {\n return this._state;\n }\n\n setState(state: \"connected\" | \"disconnected\"): void {\n this._state = state;\n }\n\n addEventListener(callback: MidiMessageCallback): void {\n if (this.callbacks.size === 0) {\n this.handler = (_deltaTime: number, message: number[]) => {\n const event = {\n data: new Uint8Array(message),\n timeStamp: performance.now(),\n };\n\n this.callbacks.forEach((cb) => {\n cb(event);\n });\n };\n\n try {\n if (!this.input.isPortOpen()) {\n this.input.openPort(this.portIndex);\n this._state = \"connected\";\n }\n this.input.on(\"message\", this.handler);\n } catch (err) {\n console.error(`Error opening MIDI port ${this.portIndex}:`, err);\n }\n }\n this.callbacks.add(callback);\n }\n\n removeEventListener(callback: MidiMessageCallback): void {\n this.callbacks.delete(callback);\n\n if (this.callbacks.size === 0 && this.handler) {\n try {\n this.input.off(\"message\", this.handler);\n if (this.input.isPortOpen()) {\n this.input.closePort();\n this._state = \"disconnected\";\n }\n } catch (err) {\n console.error(`Error closing MIDI port ${this.portIndex}:`, err);\n }\n this.handler = null;\n }\n }\n}\n\nclass NodeMidiAccess implements IMidiAccess {\n private ports = new Map<string, NodeMidiInputPort>();\n private MidiModule: NodeMidiModule;\n\n constructor(MidiModule: NodeMidiModule) {\n this.MidiModule = MidiModule;\n this.scanPorts();\n }\n\n private scanPorts(): void {\n try {\n const input = new this.MidiModule.Input();\n const portCount = input.getPortCount();\n\n for (let i = 0; i < portCount; i++) {\n const portName = input.getPortName(i);\n const id = `node-midi-${i}`;\n\n if (!this.ports.has(id)) {\n // Create a new input instance for each port\n const portInput = new this.MidiModule.Input();\n const port = new NodeMidiInputPort(i, portName, portInput);\n this.ports.set(id, port);\n }\n }\n\n // Clean up the scanning input\n if (input.isPortOpen()) {\n input.closePort();\n }\n } catch (err) {\n console.error(\"Error scanning MIDI ports:\", err);\n }\n }\n\n *inputs(): IterableIterator<IMidiInputPort> {\n for (const [, port] of this.ports) {\n yield port;\n }\n }\n\n addEventListener(\n _event: \"statechange\",\n _callback: (port: IMidiInputPort) => void,\n ): void {\n // node-midi doesn't support hot-plugging detection\n // This could be implemented with polling if needed\n console.warn(\n \"Hot-plug detection not supported with node-midi adapter. Restart required for new devices.\",\n );\n }\n}\n\nexport default class NodeMidiAdapter implements IMidiAdapter {\n async requestMIDIAccess(): Promise<IMidiAccess | null> {\n try {\n // Dynamic import to avoid bundling in browser builds\n const midi = (await import(\"@julusian/midi\")) as\n | NodeMidiModule\n | { default: NodeMidiModule };\n const midiModule = \"default\" in midi ? midi.default : midi;\n return new NodeMidiAccess(midiModule);\n } catch (err) {\n console.error(\"Error loading node-midi:\", err);\n return null;\n }\n }\n\n isSupported(): boolean {\n // Check if we're in Node.js environment\n return isNode();\n }\n}\n","/**\n * Web MIDI API adapter for browsers\n */\nimport type {\n IMidiAccess,\n IMidiAdapter,\n IMidiInputPort,\n MidiMessageCallback,\n} from \"./types\";\n\nclass WebMidiInputPort implements IMidiInputPort {\n private input: MIDIInput;\n private callbacks = new Set<MidiMessageCallback>();\n private handler: ((e: MIDIMessageEvent) => void) | null = null;\n\n constructor(input: MIDIInput) {\n this.input = input;\n }\n\n get id(): string {\n return this.input.id;\n }\n\n get name(): string {\n return this.input.name ?? `Device ${this.input.id}`;\n }\n\n get state(): \"connected\" | \"disconnected\" {\n return this.input.state as \"connected\" | \"disconnected\";\n }\n\n addEventListener(callback: MidiMessageCallback): void {\n if (this.callbacks.size === 0) {\n this.handler = (e: MIDIMessageEvent) => {\n if (!e.data) return;\n\n const event = {\n data: e.data,\n timeStamp: e.timeStamp,\n };\n\n this.callbacks.forEach((cb) => {\n cb(event);\n });\n };\n this.input.addEventListener(\"midimessage\", this.handler);\n }\n this.callbacks.add(callback);\n }\n\n removeEventListener(callback: MidiMessageCallback): void {\n this.callbacks.delete(callback);\n\n if (this.callbacks.size === 0 && this.handler) {\n this.input.removeEventListener(\"midimessage\", this.handler);\n this.handler = null;\n }\n }\n}\n\nclass WebMidiAccess implements IMidiAccess {\n private midiAccess: MIDIAccess;\n private portCache = new Map<string, WebMidiInputPort>();\n\n constructor(midiAccess: MIDIAccess) {\n this.midiAccess = midiAccess;\n }\n\n *inputs(): IterableIterator<IMidiInputPort> {\n for (const [, input] of this.midiAccess.inputs) {\n if (!this.portCache.has(input.id)) {\n this.portCache.set(input.id, new WebMidiInputPort(input));\n }\n yield this.portCache.get(input.id)!;\n }\n }\n\n addEventListener(\n event: \"statechange\",\n callback: (port: IMidiInputPort) => void,\n ): void {\n this.midiAccess.addEventListener(event, (e) => {\n const port = e.port;\n if (port?.type !== \"input\") return;\n\n const input = port as MIDIInput;\n if (!this.portCache.has(input.id)) {\n this.portCache.set(input.id, new WebMidiInputPort(input));\n }\n\n callback(this.portCache.get(input.id)!);\n });\n }\n}\n\nexport default class WebMidiAdapter implements IMidiAdapter {\n async requestMIDIAccess(): Promise<IMidiAccess | null> {\n try {\n if (\n typeof navigator === \"undefined\" ||\n typeof navigator.requestMIDIAccess !== \"function\"\n ) {\n return null;\n }\n\n const midiAccess = await navigator.requestMIDIAccess();\n return new WebMidiAccess(midiAccess);\n } catch (err) {\n console.error(\"Error enabling Web MIDI API:\", err);\n return null;\n }\n }\n\n isSupported(): boolean {\n return (\n typeof navigator !== \"undefined\" &&\n typeof navigator.requestMIDIAccess === \"function\"\n );\n }\n}\n","import { Context } from \"@blibliki/utils\";\nimport ComputerKeyboardDevice from \"./ComputerKeyboardDevice\";\nimport MidiDevice from \"./MidiDevice\";\nimport { createMidiAdapter, type IMidiAccess } from \"./adapters\";\n\ntype ListenerCallback = (device: MidiDevice) => void;\n\nexport default class MidiDeviceManager {\n devices = new Map<string, MidiDevice | ComputerKeyboardDevice>();\n private initialized = false;\n private listeners: ListenerCallback[] = [];\n private context: Readonly<Context>;\n private midiAccess: IMidiAccess | null = null;\n private adapter = createMidiAdapter();\n\n constructor(context: Context) {\n this.context = context;\n this.addComputerKeyboard();\n }\n\n async initialize() {\n await this.initializeDevices();\n\n this.listenChanges();\n this.initialized = true;\n }\n\n find(id: string): MidiDevice | ComputerKeyboardDevice | undefined {\n return this.devices.get(id);\n }\n\n findByName(name: string): MidiDevice | ComputerKeyboardDevice | undefined {\n return Array.from(this.devices.values()).find((d) => d.name === name);\n }\n\n addListener(callback: ListenerCallback) {\n this.listeners.push(callback);\n }\n\n private async initializeDevices() {\n if (this.initialized) return;\n\n try {\n if (!this.adapter.isSupported()) {\n console.warn(\"MIDI is not supported on this platform\");\n return;\n }\n\n this.midiAccess = await this.adapter.requestMIDIAccess();\n\n if (!this.midiAccess) {\n console.error(\"Failed to get MIDI access\");\n return;\n }\n\n for (const input of this.midiAccess.inputs()) {\n if (!this.devices.has(input.id)) {\n this.devices.set(input.id, new MidiDevice(input, this.context));\n }\n }\n } catch (err) {\n console.error(\"Error enabling MIDI:\", err);\n }\n }\n\n private addComputerKeyboard() {\n if (typeof document === \"undefined\") return;\n\n const computerKeyboardDevice = new ComputerKeyboardDevice(this.context);\n this.devices.set(computerKeyboardDevice.id, computerKeyboardDevice);\n }\n\n private listenChanges() {\n if (!this.midiAccess) return;\n\n this.midiAccess.addEventListener(\"statechange\", (port) => {\n if (port.state === \"connected\") {\n // Device connected\n if (this.devices.has(port.id)) return;\n\n const device = new MidiDevice(port, this.context);\n this.devices.set(device.id, device);\n\n this.listeners.forEach((listener) => {\n listener(device);\n });\n } else {\n // Device disconnected\n const device = this.devices.get(port.id);\n if (!device) return;\n if (device instanceof ComputerKeyboardDevice) return;\n\n device.disconnect();\n this.devices.delete(device.id);\n\n this.listeners.forEach((listener) => {\n listener(device);\n });\n }\n });\n }\n}\n","import { assertNever } from \"@blibliki/utils\";\nimport { IModule, Module } from \"@/core\";\nimport { IPolyModuleConstructor } from \"@/core/module/PolyModule\";\nimport VoiceScheduler, {\n IVoiceSchedulerProps,\n voiceSchedulerPropSchema,\n} from \"@/core/module/VoiceScheduler\";\nimport Constant, { constantPropSchema, IConstantProps } from \"./Constant\";\nimport Envelope, { envelopePropSchema, IEnvelopeProps } from \"./Envelope\";\nimport Filter, { filterPropSchema, IFilterProps } from \"./Filter\";\nimport Gain, { gainPropSchema, IGainProps } from \"./Gain\";\nimport Inspector, { IInspectorProps, inspectorPropSchema } from \"./Inspector\";\nimport Master, { IMasterProps, masterPropSchema } from \"./Master\";\nimport MidiMapper, {\n IMidiMapperProps,\n midiMapperPropSchema,\n} from \"./MidiMapper\";\nimport MidiSelector, {\n IMidiSelectorProps,\n midiSelectorPropSchema,\n} from \"./MidiSelector\";\nimport Oscillator, {\n IOscillatorProps,\n oscillatorPropSchema,\n} from \"./Oscillator\";\nimport Scale, { IScaleProps, scalePropSchema } from \"./Scale\";\nimport StepSequencer, {\n IStepSequencerProps,\n stepSequencerPropSchema,\n} from \"./StepSequencer\";\nimport StereoPanner, {\n IStereoPannerProps,\n stereoPannerPropSchema,\n} from \"./StereoPanner\";\nimport VirtualMidi, {\n IVirtualMidiProps,\n virtualMidiPropSchema,\n} from \"./VirtualMidi\";\n\nexport enum ModuleType {\n Master = \"Master\",\n Oscillator = \"Oscillator\",\n Gain = \"Gain\",\n MidiSelector = \"MidiSelector\",\n Envelope = \"Envelope\",\n Filter = \"Filter\",\n Scale = \"Scale\",\n StereoPanner = \"StereoPanner\",\n Inspector = \"Inspector\",\n Constant = \"Constant\",\n MidiMapper = \"MidiMapper\",\n VirtualMidi = \"VirtualMidi\",\n StepSequencer = \"StepSequencer\",\n VoiceScheduler = \"VoiceScheduler\",\n}\n\nexport type ModuleTypeToPropsMapping = {\n [ModuleType.Oscillator]: IOscillatorProps;\n [ModuleType.Gain]: IGainProps;\n [ModuleType.Master]: IMasterProps;\n [ModuleType.MidiSelector]: IMidiSelectorProps;\n [ModuleType.Envelope]: IEnvelopeProps;\n [ModuleType.Filter]: IFilterProps;\n [ModuleType.Scale]: IScaleProps;\n [ModuleType.StereoPanner]: IStereoPannerProps;\n [ModuleType.Inspector]: IInspectorProps;\n [ModuleType.Constant]: IConstantProps;\n [ModuleType.MidiMapper]: IMidiMapperProps;\n [ModuleType.VirtualMidi]: IVirtualMidiProps;\n [ModuleType.StepSequencer]: IStepSequencerProps;\n [ModuleType.VoiceScheduler]: IVoiceSchedulerProps;\n};\n\nexport type ModuleTypeToModuleMapping = {\n [ModuleType.Oscillator]: Oscillator;\n [ModuleType.Gain]: Gain;\n [ModuleType.Master]: Master;\n [ModuleType.MidiSelector]: MidiSelector;\n [ModuleType.Envelope]: Envelope;\n [ModuleType.Filter]: Filter;\n [ModuleType.Scale]: Scale;\n [ModuleType.StereoPanner]: StereoPanner;\n [ModuleType.Inspector]: Inspector;\n [ModuleType.Constant]: Constant;\n [ModuleType.MidiMapper]: MidiMapper;\n [ModuleType.VirtualMidi]: VirtualMidi;\n [ModuleType.StepSequencer]: StepSequencer;\n [ModuleType.VoiceScheduler]: VoiceScheduler;\n};\n\nexport const moduleSchemas = {\n [ModuleType.Oscillator]: oscillatorPropSchema,\n [ModuleType.Gain]: gainPropSchema,\n [ModuleType.Master]: masterPropSchema,\n [ModuleType.MidiSelector]: midiSelectorPropSchema,\n [ModuleType.Envelope]: envelopePropSchema,\n [ModuleType.Filter]: filterPropSchema,\n [ModuleType.Scale]: scalePropSchema,\n [ModuleType.StereoPanner]: stereoPannerPropSchema,\n [ModuleType.Inspector]: inspectorPropSchema,\n [ModuleType.Constant]: constantPropSchema,\n [ModuleType.MidiMapper]: midiMapperPropSchema,\n [ModuleType.VirtualMidi]: virtualMidiPropSchema,\n [ModuleType.StepSequencer]: stepSequencerPropSchema,\n [ModuleType.VoiceScheduler]: voiceSchedulerPropSchema,\n};\n\nexport type { IOscillator } from \"./Oscillator\";\nexport { OscillatorWave } from \"./Oscillator\";\nexport type { IGain } from \"./Gain\";\nexport type { IMaster } from \"./Master\";\nexport type { IMidiSelector } from \"./MidiSelector\";\nexport type { IStereoPanner } from \"./StereoPanner\";\nexport type {\n IStepSequencer,\n IStepSequencerProps,\n ISequence,\n} from \"./StepSequencer\";\nexport type { IMidiMapper, IMidiMapperProps, MidiMapping } from \"./MidiMapper\";\nexport { MidiMappingMode } from \"./MidiMapper\";\n\nexport type AnyModule = Module<ModuleType>;\nexport type IAnyModule = IModule<ModuleType>;\n\nexport type ICreateModule<T extends ModuleType> = {\n id?: string;\n name: string;\n moduleType: T;\n props: Partial<ModuleTypeToPropsMapping[T]>;\n};\n\nexport type ModuleParams = {\n [K in ModuleType]: K extends\n | ModuleType.Oscillator\n | ModuleType.Gain\n | ModuleType.Envelope\n | ModuleType.Filter\n | ModuleType.StereoPanner\n | ModuleType.VoiceScheduler\n ? IPolyModuleConstructor<K>\n : ICreateModule<K>;\n}[ModuleType];\n\nexport function createModule(\n engineId: string,\n params: ModuleParams,\n): ModuleTypeToModuleMapping[keyof ModuleTypeToModuleMapping] {\n switch (params.moduleType) {\n case ModuleType.Oscillator:\n return new Oscillator(engineId, params);\n case ModuleType.Gain:\n return new Gain(engineId, params);\n case ModuleType.Master:\n return new Master(engineId, params);\n case ModuleType.MidiSelector:\n return new MidiSelector(engineId, params);\n case ModuleType.Envelope:\n return new Envelope(engineId, params);\n case ModuleType.Filter:\n return new Filter(engineId, params);\n case ModuleType.Scale:\n return new Scale(engineId, params);\n case ModuleType.StereoPanner:\n return new StereoPanner(engineId, params);\n case ModuleType.Inspector:\n return new Inspector(engineId, params);\n case ModuleType.Constant:\n return new Constant(engineId, params);\n case ModuleType.MidiMapper:\n return new MidiMapper(engineId, params);\n case ModuleType.VirtualMidi:\n return new VirtualMidi(engineId, params);\n case ModuleType.StepSequencer:\n return new StepSequencer(engineId, params);\n case ModuleType.VoiceScheduler:\n return new VoiceScheduler(engineId, params);\n default:\n assertNever(params);\n }\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport { EmptyObject } from \"@blibliki/utils\";\nimport { ICreateModule, ModuleType } from \"@/modules\";\nimport { MidiOutput } from \"../IO\";\nimport MidiEvent, { MidiEventType } from \"../midi/MidiEvent\";\nimport { ModulePropSchema } from \"../schema\";\nimport { IModuleConstructor, Module } from \"./Module\";\nimport { IPolyModuleConstructor, PolyModule } from \"./PolyModule\";\n\nexport type IVoiceSchedulerProps = EmptyObject;\nexport const voiceSchedulerPropSchema: ModulePropSchema<IVoiceSchedulerProps> =\n {};\nconst DEFAULT_PROPS = {};\n\nclass Voice extends Module<ModuleType.VoiceScheduler> {\n declare audioNode: undefined;\n activeNote: string | null = null;\n triggeredAt: ContextTime = 0;\n\n constructor(\n engineId: string,\n params: ICreateModule<ModuleType.VoiceScheduler>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n\n super(engineId, {\n ...params,\n props,\n });\n }\n\n midiTriggered = (midiEvent: MidiEvent) => {\n const { triggeredAt, note, type } = midiEvent;\n\n if (!note) return;\n const noteName = note.fullName;\n\n switch (type) {\n case MidiEventType.noteOn:\n this.activeNote = noteName;\n this.triggeredAt = triggeredAt;\n\n break;\n case MidiEventType.noteOff:\n this.activeNote = null;\n break;\n default:\n throw Error(\"This type is not a note\");\n }\n };\n}\n\nexport default class VoiceScheduler extends PolyModule<ModuleType.VoiceScheduler> {\n declare audioModules: Voice[];\n midiOutput!: MidiOutput;\n\n constructor(\n engineId: string,\n params: IPolyModuleConstructor<ModuleType.VoiceScheduler>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const monoModuleConstructor = (\n engineId: string,\n params: IModuleConstructor<ModuleType.VoiceScheduler>,\n ) => new Voice(engineId, params);\n\n super(engineId, {\n ...params,\n props,\n monoModuleConstructor,\n });\n\n this.registerInputs();\n this.registerOutputs();\n }\n\n onMidiEvent = (midiEvent: MidiEvent) => {\n let voice: Voice | undefined;\n\n switch (midiEvent.type) {\n case MidiEventType.noteOn:\n voice = this.findFreeVoice();\n\n break;\n case MidiEventType.noteOff:\n voice = this.audioModules.find(\n (v) => v.activeNote === midiEvent.note!.fullName,\n );\n break;\n default:\n throw Error(\"This type is not a note\");\n }\n\n if (!voice) return;\n\n voice.midiTriggered(midiEvent);\n midiEvent.voiceNo = voice.voiceNo;\n this.midiOutput.onMidiEvent(midiEvent);\n };\n\n private findFreeVoice(): Voice {\n let voice = this.audioModules.find((v) => !v.activeNote);\n\n // If no available voice, get the one with the lowest triggeredAt\n voice ??= this.audioModules.sort((a, b) => {\n return a.triggeredAt - b.triggeredAt;\n })[0];\n\n return voice;\n }\n\n private registerInputs() {\n this.registerMidiInput({\n name: \"midi in\",\n onMidiEvent: this.onMidiEvent,\n });\n }\n\n private registerOutputs() {\n this.midiOutput = this.registerMidiOutput({ name: \"midi out\" });\n }\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport { Context } from \"@blibliki/utils\";\nimport { ConstantSourceNode } from \"@blibliki/utils/web-audio-api\";\nimport { IModule, Module, ModulePropSchema, SetterHooks } from \"@/core\";\nimport Note from \"@/core/Note\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IConstant = IModule<ModuleType.Constant>;\nexport type IConstantProps = {\n value: number;\n};\n\nexport const constantPropSchema: ModulePropSchema<IConstantProps> = {\n value: {\n kind: \"number\",\n min: -Infinity,\n max: Infinity,\n step: 0.01,\n label: \"Value\",\n },\n};\n\nconst DEFAULT_PROPS: IConstantProps = { value: 1 };\n\nexport default class Constant\n extends Module<ModuleType.Constant>\n implements Pick<SetterHooks<IConstantProps>, \"onAfterSetValue\">\n{\n declare audioNode: ConstantSourceNode;\n isStated = false;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.Constant>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const audioNodeConstructor = (context: Context) =>\n new ConstantSourceNode(context.audioContext);\n\n super(engineId, {\n ...params,\n props,\n audioNodeConstructor,\n });\n\n this.registerDefaultIOs(\"out\");\n }\n\n onAfterSetValue: SetterHooks<IConstantProps>[\"onAfterSetValue\"] = (value) => {\n this.audioNode.offset.value = value;\n };\n\n start(time: ContextTime) {\n if (this.isStated) return;\n\n this.isStated = true;\n this.audioNode.start(time);\n }\n\n stop(time: ContextTime) {\n if (!this.isStated) return;\n\n this.audioNode.stop(time);\n this.rePlugAll(() => {\n this.audioNode = new ConstantSourceNode(this.context.audioContext, {\n offset: this.props.value,\n });\n });\n\n this.isStated = false;\n }\n\n triggerAttack = (note: Note, triggeredAt: ContextTime) => {\n this.audioNode.offset.setValueAtTime(note.frequency, triggeredAt);\n this.start(triggeredAt);\n };\n\n triggerRelease = () => {\n // Do nothing\n };\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport { Context, cancelAndHoldAtTime } from \"@blibliki/utils\";\nimport { GainNode } from \"@blibliki/utils/web-audio-api\";\nimport { Module } from \"@/core\";\nimport Note from \"@/core/Note\";\nimport { IModuleConstructor } from \"@/core/module/Module\";\nimport { IPolyModuleConstructor, PolyModule } from \"@/core/module/PolyModule\";\nimport { ModulePropSchema } from \"@/core/schema\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IEnvelopeProps = {\n attack: number;\n decay: number;\n sustain: number;\n release: number;\n};\n\nconst DEFAULT_PROPS: IEnvelopeProps = {\n attack: 0.01,\n decay: 0,\n sustain: 1,\n release: 0,\n};\n\nexport const envelopePropSchema: ModulePropSchema<IEnvelopeProps> = {\n attack: {\n kind: \"number\",\n min: 0.0001,\n max: 20,\n step: 0.01,\n exp: 3,\n label: \"Attack\",\n },\n decay: {\n kind: \"number\",\n min: 0,\n max: 20,\n step: 0.01,\n exp: 3,\n label: \"Decay\",\n },\n sustain: {\n kind: \"number\",\n min: 0,\n max: 1,\n step: 0.01,\n label: \"Sustain\",\n },\n release: {\n kind: \"number\",\n min: 0,\n max: 20,\n step: 0.01,\n exp: 3,\n label: \"Release\",\n },\n};\n\nclass MonoEnvelope extends Module<ModuleType.Envelope> {\n declare audioNode: GainNode;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.Envelope>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const audioNodeConstructor = (context: Context) => {\n const audioNode = new GainNode(context.audioContext);\n audioNode.gain.value = 0;\n return audioNode;\n };\n\n super(engineId, {\n ...params,\n props,\n audioNodeConstructor,\n });\n\n this.registerDefaultIOs();\n }\n\n triggerAttack(note: Note, triggeredAt: ContextTime) {\n super.triggerAttack(note, triggeredAt);\n\n const attack = this.props.attack;\n const decay = this.props.decay;\n const sustain = this.props.sustain;\n\n cancelAndHoldAtTime(this.audioNode.gain, triggeredAt);\n\n // Always start from a tiny value, can't ramp from 0\n if (this.audioNode.gain.value === 0) {\n this.audioNode.gain.setValueAtTime(0.001, triggeredAt);\n }\n\n // Attack\n this.audioNode.gain.exponentialRampToValueAtTime(1.0, triggeredAt + attack);\n\n // Decay\n if (sustain > 0) {\n this.audioNode.gain.exponentialRampToValueAtTime(\n sustain,\n triggeredAt + attack + decay,\n );\n // Do not set to zero or anything else!\n } else {\n this.audioNode.gain.exponentialRampToValueAtTime(\n 0.001,\n triggeredAt + attack + decay,\n );\n }\n }\n\n triggerRelease(note: Note, triggeredAt: ContextTime) {\n super.triggerRelease(note, triggeredAt);\n if (this.activeNotes.length > 0) return;\n\n const release = this.props.release;\n\n // Cancel scheduled automations and set gain to the ACTUAL value at this moment\n const currentGainValue = cancelAndHoldAtTime(\n this.audioNode.gain,\n triggeredAt,\n );\n\n if (currentGainValue >= 0.0001) {\n // Always set the value at the release time to ensure a smooth ramp from here\n this.audioNode.gain.setValueAtTime(currentGainValue, triggeredAt);\n // Exponential ramp to a tiny value\n this.audioNode.gain.exponentialRampToValueAtTime(\n 0.0001,\n triggeredAt + release - 0.0001,\n );\n }\n\n // Set to zero at the very end\n this.audioNode.gain.setValueAtTime(0, triggeredAt + release);\n }\n}\n\nexport default class Envelope extends PolyModule<ModuleType.Envelope> {\n constructor(\n engineId: string,\n params: IPolyModuleConstructor<ModuleType.Envelope>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const monoModuleConstructor = (\n engineId: string,\n params: IModuleConstructor<ModuleType.Envelope>,\n ) => new MonoEnvelope(engineId, params);\n\n super(engineId, {\n ...params,\n props,\n monoModuleConstructor,\n });\n\n this.registerDefaultIOs();\n }\n}\n","import { Context } from \"@blibliki/utils\";\nimport { BiquadFilterNode } from \"@blibliki/utils/web-audio-api\";\nimport { EnumProp, ModulePropSchema } from \"@/core\";\nimport { IModuleConstructor, Module, SetterHooks } from \"@/core/module/Module\";\nimport { IPolyModuleConstructor, PolyModule } from \"@/core/module/PolyModule\";\nimport { createModule, ICreateModule, ModuleType } from \".\";\nimport { MonoGain } from \"./Gain\";\nimport Scale from \"./Scale\";\n\nexport type IFilterProps = {\n cutoff: number;\n envelopeAmount: number;\n type: BiquadFilterType;\n Q: number;\n};\n\nconst MIN_FREQ = 20;\nconst MAX_FREQ = 20000;\n\nconst DEFAULT_PROPS: IFilterProps = {\n cutoff: MAX_FREQ,\n envelopeAmount: 0,\n type: \"lowpass\",\n Q: 1,\n};\n\nexport const filterPropSchema: ModulePropSchema<\n IFilterProps,\n {\n type: EnumProp<BiquadFilterType>;\n }\n> = {\n cutoff: {\n kind: \"number\",\n min: MIN_FREQ,\n max: MAX_FREQ,\n step: 1,\n exp: 5,\n label: \"Cutoff\",\n },\n envelopeAmount: {\n kind: \"number\",\n min: -1,\n max: 1,\n step: 0.01,\n label: \"Envelope Amount\",\n },\n type: {\n kind: \"enum\",\n options: [\"lowpass\", \"highpass\", \"bandpass\"] satisfies BiquadFilterType[],\n label: \"Type\",\n },\n Q: {\n kind: \"number\",\n min: 0.0001,\n max: 1000,\n step: 0.1,\n exp: 5,\n label: \"Q\",\n },\n};\n\nclass MonoFilter\n extends Module<ModuleType.Filter>\n implements\n Pick<\n SetterHooks<IFilterProps>,\n | \"onAfterSetType\"\n | \"onAfterSetCutoff\"\n | \"onAfterSetQ\"\n | \"onAfterSetEnvelopeAmount\"\n >\n{\n declare audioNode: BiquadFilterNode;\n private scale: Scale;\n private amount: MonoGain;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.Filter>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n\n const audioNodeConstructor = (context: Context) =>\n new BiquadFilterNode(context.audioContext, {\n type: props.type,\n frequency: 0,\n Q: props.Q,\n });\n\n super(engineId, {\n ...params,\n props,\n audioNodeConstructor,\n });\n\n this.amount = new MonoGain(engineId, {\n name: \"amount\",\n moduleType: ModuleType.Gain,\n props: { gain: props.envelopeAmount },\n });\n\n this.scale = createModule(engineId, {\n name: \"scale\",\n moduleType: ModuleType.Scale,\n props: { min: MIN_FREQ, max: MAX_FREQ, current: this.props.cutoff },\n }) as Scale;\n\n this.amount.plug({ audioModule: this.scale, from: \"out\", to: \"in\" });\n this.scale.audioNode.connect(this.audioNode.frequency);\n\n this.registerDefaultIOs();\n this.registerInputs();\n }\n\n onAfterSetType: SetterHooks<IFilterProps>[\"onAfterSetType\"] = (value) => {\n this.audioNode.type = value;\n };\n\n onAfterSetCutoff: SetterHooks<IFilterProps>[\"onAfterSetCutoff\"] = (value) => {\n this.scale.props = { current: value };\n };\n\n onAfterSetQ: SetterHooks<IFilterProps>[\"onAfterSetQ\"] = (value) => {\n this.audioNode.Q.value = value;\n };\n\n onAfterSetEnvelopeAmount: SetterHooks<IFilterProps>[\"onAfterSetEnvelopeAmount\"] =\n (value) => {\n this.amount.props = { gain: value };\n };\n\n private registerInputs() {\n this.registerAudioInput({\n name: \"cutoff\",\n getAudioNode: () => this.audioNode.frequency,\n });\n\n this.registerAudioInput({\n name: \"cutoffMod\",\n getAudioNode: () => this.amount.audioNode,\n });\n\n this.registerAudioInput({\n name: \"Q\",\n getAudioNode: () => this.audioNode.Q,\n });\n }\n}\n\nexport default class Filter extends PolyModule<ModuleType.Filter> {\n constructor(\n engineId: string,\n params: IPolyModuleConstructor<ModuleType.Filter>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const monoModuleConstructor = (\n engineId: string,\n params: IModuleConstructor<ModuleType.Filter>,\n ) => new MonoFilter(engineId, params);\n\n super(engineId, {\n ...params,\n props,\n monoModuleConstructor,\n });\n\n this.registerInputs();\n this.registerDefaultIOs();\n }\n\n private registerInputs() {\n this.registerAudioInput({ name: \"cutoff\" });\n this.registerAudioInput({ name: \"cutoffMod\" });\n this.registerAudioInput({ name: \"Q\" });\n }\n}\n","import { Context } from \"@blibliki/utils\";\nimport { GainNode } from \"@blibliki/utils/web-audio-api\";\nimport { IModule, Module, ModulePropSchema, SetterHooks } from \"@/core\";\nimport { IModuleConstructor } from \"@/core/module/Module\";\nimport { IPolyModuleConstructor, PolyModule } from \"@/core/module/PolyModule\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IGain = IModule<ModuleType.Gain>;\nexport type IGainProps = {\n gain: number;\n};\n\nexport const gainPropSchema: ModulePropSchema<IGainProps> = {\n gain: {\n kind: \"number\",\n min: 0,\n max: Infinity,\n step: 0.01,\n label: \"Gain\",\n },\n};\n\nconst DEFAULT_PROPS: IGainProps = { gain: 1 };\n\nexport class MonoGain\n extends Module<ModuleType.Gain>\n implements Pick<SetterHooks<IGainProps>, \"onAfterSetGain\">\n{\n declare audioNode: GainNode;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.Gain>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const audioNodeConstructor = (context: Context) =>\n new GainNode(context.audioContext);\n\n super(engineId, {\n ...params,\n audioNodeConstructor,\n props,\n });\n\n this.registerDefaultIOs();\n this.registerAdditionalInputs();\n }\n\n onAfterSetGain: SetterHooks<IGainProps>[\"onAfterSetGain\"] = (value) => {\n this.audioNode.gain.value = value;\n };\n\n private registerAdditionalInputs() {\n this.registerAudioInput({\n name: \"gain\",\n getAudioNode: () => this.audioNode.gain,\n });\n }\n}\n\nexport default class Gain extends PolyModule<ModuleType.Gain> {\n constructor(\n engineId: string,\n params: IPolyModuleConstructor<ModuleType.Gain>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const monoModuleConstructor = (\n engineId: string,\n params: IModuleConstructor<ModuleType.Gain>,\n ) => new MonoGain(engineId, params);\n\n super(engineId, {\n ...params,\n props,\n monoModuleConstructor,\n });\n\n this.registerAdditionalInputs();\n this.registerDefaultIOs();\n }\n\n private registerAdditionalInputs() {\n this.registerAudioInput({ name: \"gain\" });\n }\n}\n","import { Context } from \"@blibliki/utils\";\nimport { AnalyserNode } from \"@blibliki/utils/web-audio-api\";\nimport { IModule, Module, SetterHooks } from \"@/core\";\nimport { EnumProp, ModulePropSchema } from \"@/core/schema\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IInspector = IModule<ModuleType.Inspector>;\nexport type IInspectorProps = {\n fftSize: number;\n};\n\nexport const inspectorPropSchema: ModulePropSchema<\n IInspectorProps,\n {\n fftSize: EnumProp<number>;\n }\n> = {\n fftSize: {\n kind: \"enum\",\n options: [32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768],\n label: \"FFT size\",\n },\n};\n\nconst DEFAULT_PROPS: IInspectorProps = { fftSize: 512 };\n\nexport default class Inspector\n extends Module<ModuleType.Inspector>\n implements Pick<SetterHooks<IInspectorProps>, \"onAfterSetFftSize\">\n{\n declare audioNode: AnalyserNode;\n private _buffer?: Float32Array<ArrayBuffer>;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.Inspector>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const audioNodeConstructor = (context: Context) =>\n new AnalyserNode(context.audioContext);\n\n super(engineId, {\n ...params,\n props,\n audioNodeConstructor,\n });\n\n this.registerDefaultIOs(\"in\");\n }\n\n onAfterSetFftSize: SetterHooks<IInspectorProps>[\"onAfterSetFftSize\"] = (\n value,\n ) => {\n this._buffer = new Float32Array(value);\n };\n\n get buffer() {\n if (this._buffer) return this._buffer;\n\n this._buffer = new Float32Array(this.props.fftSize);\n\n return this._buffer;\n }\n\n getValue(): number {\n return this.getValues()[0];\n }\n\n getValues(): Float32Array {\n this.audioNode.getFloatTimeDomainData(this.buffer);\n\n return this.buffer;\n }\n}\n","import { Context, EmptyObject } from \"@blibliki/utils\";\nimport { IModule, Module, ModulePropSchema } from \"@/core\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IMaster = IModule<ModuleType.Master>;\nexport type IMasterProps = EmptyObject;\n\nconst DEFAULT_PROPS: IMasterProps = {};\n\nexport const masterPropSchema: ModulePropSchema<IMasterProps> = {};\n\nexport default class Master extends Module<ModuleType.Master> {\n declare audioNode: AudioDestinationNode;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.Master>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const audioNodeConstructor = (context: Context) => context.destination;\n\n super(engineId, { ...params, audioNodeConstructor, props });\n\n this.registerDefaultIOs(\"in\");\n }\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport { IModule, MidiEvent, Module, SetterHooks } from \"@/core\";\nimport { ModulePropSchema, NumberProp, PropSchema } from \"@/core/schema\";\nimport { ICreateModule, moduleSchemas, ModuleType } from \".\";\n\nexport type IMidiMapper = IModule<ModuleType.MidiMapper>;\nexport type IMidiMapperProps = {\n pages: MidiMappingPage[];\n activePage: number;\n globalMappings: MidiMapping<ModuleType>[];\n};\n\nexport type MidiMappingPage = {\n name?: string;\n mappings: MidiMapping<ModuleType>[];\n};\n\nexport enum MidiMappingMode {\n direct = \"direct\",\n directRev = \"directRev\",\n toggleInc = \"toggleInc\",\n toggleDec = \"toggleDec\",\n incDec = \"incDec\",\n incDecRev = \"incDecRev\",\n}\n\nexport type MidiMapping<T extends ModuleType> = {\n cc?: number;\n moduleId?: string;\n moduleType?: T;\n propName?: string;\n autoAssign?: boolean;\n mode?: MidiMappingMode;\n threshold?: number; // For incDec mode (default: 64)\n step?: number;\n};\n\nexport const midiMapperPropSchema: ModulePropSchema<IMidiMapperProps> = {\n pages: {\n kind: \"array\",\n label: \"Midi mapping pages\",\n },\n activePage: {\n kind: \"number\",\n label: \"Active page\",\n min: 0,\n max: 100,\n step: 1,\n },\n globalMappings: {\n kind: \"array\",\n label: \"Global midi mappings\",\n },\n};\n\nconst DEFAULT_PROPS: IMidiMapperProps = {\n pages: [{ name: \"Page 1\", mappings: [{}] }],\n activePage: 0,\n globalMappings: [{}],\n};\n\nfunction getMidiFromMappedValue({\n value,\n midiValue,\n propSchema,\n mapping,\n}: {\n value: number;\n propSchema: NumberProp;\n midiValue: number;\n mapping: MidiMapping<ModuleType>;\n}): number {\n const min = propSchema.min ?? 0;\n const max = propSchema.max ?? 1;\n const exp = propSchema.exp ?? 1;\n\n const { threshold = 64, mode } = mapping;\n\n // Reverse the range mapping: get curvedValue\n const curvedValue = (value - min) / (max - min);\n\n // Reverse the exponential curve: get normalizedMidi\n const normalizedMidi = Math.pow(curvedValue, 1 / exp);\n\n // Reverse the MIDI normalization: get midiValue\n let newMidiValue = normalizedMidi * 127;\n newMidiValue =\n (midiValue >= threshold && mode === MidiMappingMode.incDec) ||\n (midiValue <= threshold && mode === MidiMappingMode.incDecRev)\n ? newMidiValue + 1\n : newMidiValue - 1;\n return Math.round(Math.max(0, Math.min(127, newMidiValue))); // Valid MIDI range\n}\n\ntype MidiMapperSetterHooks = Pick<\n SetterHooks<IMidiMapperProps>,\n \"onSetActivePage\"\n>;\n\nexport default class MidiMapper\n extends Module<ModuleType.MidiMapper>\n implements MidiMapperSetterHooks\n{\n declare audioNode: undefined;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.MidiMapper>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n\n super(engineId, {\n ...params,\n props,\n });\n\n this.registerMidiInput({\n name: \"midi in\",\n onMidiEvent: this.onMidiEvent,\n });\n }\n\n onSetActivePage: MidiMapperSetterHooks[\"onSetActivePage\"] = (value) => {\n return Math.max(Math.min(value, this.props.pages.length - 1), 0);\n };\n\n handleCC = (event: MidiEvent, triggeredAt: ContextTime) => {\n this.checkAutoAssign(event);\n\n const activePage = this.props.pages[this.props.activePage];\n\n [\n ...this.props.globalMappings.filter((m) => m.cc === event.cc),\n ...activePage.mappings.filter((m) => m.cc === event.cc),\n ].forEach((mapping) => {\n this.forwardMapping(event, mapping, triggeredAt);\n });\n };\n\n forwardMapping = (\n event: MidiEvent,\n mapping: MidiMapping<ModuleType>,\n _triggeredAt: ContextTime,\n ) => {\n if (\n mapping.moduleId === undefined ||\n mapping.moduleType === undefined ||\n mapping.propName === undefined\n )\n return;\n\n const propName = mapping.propName;\n let midiValue = event.ccValue;\n if (midiValue === undefined) return;\n\n const mode = mapping.mode ?? \"direct\";\n\n // Toggle mode: only respond to 127 (button press), ignore 0\n if (\n (mode === MidiMappingMode.toggleInc ||\n mode === MidiMappingMode.toggleDec) &&\n midiValue !== 127\n ) {\n return;\n }\n\n const mappedModule = this.engine.findModule(mapping.moduleId);\n // @ts-expect-error TS7053 ignore this error\n const propSchema = moduleSchemas[mappedModule.moduleType][\n propName\n ] as PropSchema;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let mappedValue: any;\n\n // Direct mode (default) or Toggle mode: map value directly\n switch (propSchema.kind) {\n case \"number\": {\n // @ts-expect-error TS7053 ignore this error\n const currentValue = mappedModule.props[propName] as number;\n\n if (\n mode === MidiMappingMode.incDec ||\n mode === MidiMappingMode.incDecRev\n ) {\n midiValue = getMidiFromMappedValue({\n value: currentValue,\n propSchema,\n mapping,\n midiValue,\n });\n } else if (mode === MidiMappingMode.directRev) {\n midiValue = 127 - midiValue;\n }\n\n if (mode === MidiMappingMode.toggleInc) {\n mappedValue = currentValue + (propSchema.step ?? 1);\n } else if (mode === MidiMappingMode.toggleDec) {\n mappedValue = currentValue - (propSchema.step ?? 1);\n } else {\n const min = propSchema.min ?? 0;\n const max = propSchema.max ?? 1;\n const normalizedMidi = midiValue / 127;\n const curvedValue = Math.pow(normalizedMidi, propSchema.exp ?? 1);\n mappedValue = min + curvedValue * (max - min);\n\n // Round to step if defined\n if (\n propSchema.step !== undefined &&\n (!propSchema.exp || propSchema.exp === 1)\n ) {\n const steps = Math.round((mappedValue - min) / propSchema.step);\n mappedValue = min + steps * propSchema.step;\n }\n }\n\n break;\n }\n case \"enum\": {\n const optionIndex = Math.floor(\n (midiValue / 127) * propSchema.options.length,\n );\n const clampedIndex = Math.min(\n optionIndex,\n propSchema.options.length - 1,\n );\n mappedValue = propSchema.options[clampedIndex];\n break;\n }\n case \"boolean\":\n mappedValue = midiValue >= 64;\n break;\n case \"string\":\n throw Error(\"MidiMapper not support string type of values\");\n case \"array\":\n throw Error(\"MidiMapper not support array type of values\");\n\n default:\n throw Error(\"MidiMapper unknown type\");\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n mappedModule.props = { [propName]: mappedValue };\n mappedModule.triggerPropsUpdate();\n };\n\n private checkAutoAssign(event: MidiEvent) {\n if (event.cc === undefined) return;\n\n const activePage = this.props.pages[this.props.activePage];\n const hasGlobalAutoAssign = this.props.globalMappings.some(\n ({ autoAssign }) => autoAssign,\n );\n const hasPageAutoAssign = activePage.mappings.some(\n ({ autoAssign }) => autoAssign,\n );\n\n if (!hasGlobalAutoAssign && !hasPageAutoAssign) return;\n\n // Update global mappings if needed\n const updatedGlobalMappings = hasGlobalAutoAssign\n ? this.props.globalMappings.map((mapping) => {\n if (!mapping.autoAssign) return mapping;\n\n return {\n ...mapping,\n cc: event.cc,\n autoAssign: false,\n };\n })\n : this.props.globalMappings;\n\n // Update page mappings if needed\n const updatedPageMappings = hasPageAutoAssign\n ? activePage.mappings.map((mapping) => {\n if (!mapping.autoAssign) return mapping;\n\n return {\n ...mapping,\n cc: event.cc,\n autoAssign: false,\n };\n })\n : activePage.mappings;\n\n const updatedPages = this.props.pages.map((page, index) =>\n index === this.props.activePage\n ? { ...page, mappings: updatedPageMappings }\n : page,\n );\n\n this.props = { pages: updatedPages, globalMappings: updatedGlobalMappings };\n this.triggerPropsUpdate();\n }\n}\n","import { IModule, Module, MidiOutput, SetterHooks, MidiDevice } from \"@/core\";\nimport ComputerKeyboardInput from \"@/core/midi/ComputerKeyboardDevice\";\nimport MidiEvent from \"@/core/midi/MidiEvent\";\nimport { ModulePropSchema } from \"@/core/schema\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IMidiSelector = IModule<ModuleType.MidiSelector>;\nexport type IMidiSelectorProps = {\n selectedId: string | undefined | null;\n selectedName: string | undefined | null;\n};\n\nexport const midiSelectorPropSchema: ModulePropSchema<IMidiSelectorProps> = {\n selectedId: {\n kind: \"string\",\n label: \"Midi device ID\",\n },\n selectedName: {\n kind: \"string\",\n label: \"Midi device name\",\n },\n};\n\nconst DEFAULT_PROPS: IMidiSelectorProps = {\n selectedId: undefined,\n selectedName: undefined,\n};\n\nexport default class MidiSelector\n extends Module<ModuleType.MidiSelector>\n implements Pick<SetterHooks<IMidiSelectorProps>, \"onSetSelectedId\">\n{\n declare audioNode: undefined;\n midiOutput!: MidiOutput;\n _forwardMidiEvent?: (midiEvent: MidiEvent) => void;\n\n constructor(\n engineId: string,\n params: ICreateModule<ModuleType.MidiSelector>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n\n super(engineId, {\n ...params,\n props,\n });\n\n const midiDevice =\n (this.props.selectedId &&\n this.engine.findMidiDevice(this.props.selectedId)) ??\n (this.props.selectedName &&\n this.engine.findMidiDeviceByName(this.props.selectedName));\n\n if (midiDevice) {\n this.addEventListener(midiDevice);\n }\n\n this.registerOutputs();\n }\n\n onSetSelectedId: SetterHooks<IMidiSelectorProps>[\"onSetSelectedId\"] = (\n value,\n ) => {\n this.removeEventListener();\n if (!value) return value;\n\n const midiDevice = this.engine.findMidiDevice(value);\n if (!midiDevice) return value;\n\n if (this.props.selectedName !== midiDevice.name) {\n this.props = { selectedName: midiDevice.name };\n this.triggerPropsUpdate();\n }\n this.addEventListener(midiDevice);\n\n return value;\n };\n\n private get forwardMidiEvent() {\n if (this._forwardMidiEvent) return this._forwardMidiEvent;\n\n this._forwardMidiEvent = (midiEvent: MidiEvent) => {\n this.midiOutput.onMidiEvent(midiEvent);\n };\n\n return this._forwardMidiEvent;\n }\n\n private addEventListener(midiDevice: MidiDevice | ComputerKeyboardInput) {\n midiDevice.addEventListener(this.forwardMidiEvent);\n }\n\n private removeEventListener() {\n if (!this.props.selectedId) return;\n\n const midiDevice = this.engine.findMidiDevice(this.props.selectedId);\n midiDevice?.removeEventListener(this.forwardMidiEvent);\n }\n\n private registerOutputs() {\n this.midiOutput = this.registerMidiOutput({ name: \"midi out\" });\n }\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport { Context, dbToGain } from \"@blibliki/utils\";\nimport { GainNode, OscillatorNode } from \"@blibliki/utils/web-audio-api\";\nimport { IModule, Module } from \"@/core\";\nimport Note from \"@/core/Note\";\nimport { IModuleConstructor, SetterHooks } from \"@/core/module/Module\";\nimport { IPolyModuleConstructor, PolyModule } from \"@/core/module/PolyModule\";\nimport { EnumProp, ModulePropSchema } from \"@/core/schema\";\nimport { ICreateModule, ModuleType } from \".\";\n\nconst LOW_GAIN = -18;\n\nexport type IOscillator = IModule<ModuleType.Oscillator>;\n\nexport enum OscillatorWave {\n sine = \"sine\",\n triangle = \"triangle\",\n square = \"square\",\n sawtooth = \"sawtooth\",\n}\n\n/**\n * Props for the Oscillator module.\n *\n * @property wave - Waveform shape of the oscillator.\n * One of: \"sine\", \"square\", \"sawtooth\", \"triangle\", or \"custom\".\n * @property frequency - Base frequency in Hz (e.g. 440 for A4).\n * @property fine - Fine tuning factor in the range [-1, 1], where ±1 represents ±1 semitone.\n * @property coarse - Coarse tuning factor in the range [-1, 1], scaled to ±12 semitones.\n * @property octave - Octave transposition value (e.g. +1 for one octave up, -2 for two octaves down).\n * @property lowGain - Whether to gain reduction (-18dB). When false, oscillator runs at full gain.\n */\nexport type IOscillatorProps = {\n wave: OscillatorWave;\n frequency: number;\n fine: number;\n coarse: number;\n octave: number;\n lowGain: boolean;\n};\n\nexport const oscillatorPropSchema: ModulePropSchema<\n IOscillatorProps,\n {\n wave: EnumProp<OscillatorWave>;\n }\n> = {\n wave: {\n kind: \"enum\",\n options: Object.values(OscillatorWave),\n label: \"Waveform\",\n },\n frequency: {\n kind: \"number\",\n min: 0,\n max: 25000,\n step: 1,\n label: \"Frequency\",\n },\n fine: {\n kind: \"number\",\n min: -1,\n max: 1,\n step: 0.01,\n label: \"Fine\",\n },\n coarse: {\n kind: \"number\",\n min: -12,\n max: 12,\n step: 1,\n label: \"Coarse\",\n },\n octave: {\n kind: \"number\",\n min: -1,\n max: 2,\n step: 1,\n label: \"Octave\",\n },\n lowGain: {\n kind: \"boolean\",\n label: `Use ${LOW_GAIN}db Gain`,\n },\n};\n\nconst DEFAULT_PROPS: IOscillatorProps = {\n wave: OscillatorWave.sine,\n frequency: 440,\n fine: 0,\n coarse: 0,\n octave: 0,\n lowGain: false,\n};\n\ntype OscillatorSetterHooks = Pick<\n SetterHooks<IOscillatorProps>,\n | \"onAfterSetWave\"\n | \"onAfterSetFrequency\"\n | \"onAfterSetFine\"\n | \"onAfterSetCoarse\"\n | \"onAfterSetOctave\"\n | \"onAfterSetLowGain\"\n>;\n\nexport class MonoOscillator\n extends Module<ModuleType.Oscillator>\n implements OscillatorSetterHooks\n{\n declare audioNode: OscillatorNode;\n isStated = false;\n outputGain: GainNode;\n detuneGain!: GainNode;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.Oscillator>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const audioNodeConstructor = (context: Context) =>\n new OscillatorNode(context.audioContext);\n\n super(engineId, {\n ...params,\n props,\n audioNodeConstructor,\n });\n\n this.outputGain = new GainNode(this.context.audioContext, {\n gain: dbToGain(LOW_GAIN),\n });\n\n this.applyOutputGain();\n this.initializeGainDetune();\n this.registerInputs();\n this.registerOutputs();\n }\n\n onAfterSetWave: OscillatorSetterHooks[\"onAfterSetWave\"] = (value) => {\n this.audioNode.type = value;\n };\n\n onAfterSetFrequency: OscillatorSetterHooks[\"onAfterSetFrequency\"] = () => {\n this.updateFrequency();\n };\n\n onAfterSetFine: OscillatorSetterHooks[\"onAfterSetFine\"] = () => {\n this.updateFrequency();\n };\n\n onAfterSetCoarse: OscillatorSetterHooks[\"onAfterSetCoarse\"] = () => {\n this.updateFrequency();\n };\n\n onAfterSetOctave: OscillatorSetterHooks[\"onAfterSetOctave\"] = () => {\n this.updateFrequency();\n };\n\n onAfterSetLowGain: OscillatorSetterHooks[\"onAfterSetLowGain\"] = (lowGain) => {\n this.outputGain.gain.value = lowGain ? dbToGain(LOW_GAIN) : 1;\n };\n\n start(time: ContextTime) {\n if (this.isStated) return;\n\n this.isStated = true;\n this.audioNode.start(time);\n }\n\n stop(time: ContextTime) {\n if (!this.isStated) return;\n\n this.audioNode.stop(time);\n this.rePlugAll(() => {\n this.audioNode = new OscillatorNode(this.context.audioContext, {\n type: this.props.wave,\n frequency: this.finalFrequency,\n });\n this.applyOutputGain();\n this.detuneGain.connect(this.audioNode.detune);\n });\n\n this.isStated = false;\n }\n\n triggerAttack = (note: Note, triggeredAt: ContextTime) => {\n super.triggerAttack(note, triggeredAt);\n\n this.props = { frequency: note.frequency };\n this.updateFrequency(triggeredAt);\n this.start(triggeredAt);\n };\n\n triggerRelease(note: Note, triggeredAt: ContextTime) {\n super.triggerRelease(note, triggeredAt);\n\n const lastNote = this.activeNotes.length\n ? this.activeNotes[this.activeNotes.length - 1]\n : null;\n if (!lastNote) return;\n\n this.props = { frequency: lastNote.frequency };\n this.updateFrequency(triggeredAt);\n }\n\n private get finalFrequency(): number | undefined {\n const { frequency, coarse, octave, fine } = this.props;\n\n const transposed =\n frequency * Math.pow(2, coarse / 12 + octave + fine / 12);\n return transposed;\n }\n\n private updateFrequency(actionAt?: ContextTime) {\n if (this.finalFrequency === undefined) return;\n\n if (actionAt) {\n this.audioNode.frequency.setValueAtTime(this.finalFrequency, actionAt);\n } else {\n this.audioNode.frequency.value = this.finalFrequency;\n }\n }\n\n private applyOutputGain() {\n this.audioNode.connect(this.outputGain);\n }\n\n private initializeGainDetune() {\n this.detuneGain = new GainNode(this.context.audioContext, { gain: 100 });\n this.detuneGain.connect(this.audioNode.detune);\n }\n\n private registerInputs() {\n this.registerAudioInput({\n name: \"detune\",\n getAudioNode: () => this.detuneGain,\n });\n }\n\n private registerOutputs() {\n this.registerAudioOutput({\n name: \"out\",\n getAudioNode: () => this.outputGain,\n });\n }\n}\n\nexport default class Oscillator extends PolyModule<ModuleType.Oscillator> {\n constructor(\n engineId: string,\n params: IPolyModuleConstructor<ModuleType.Oscillator>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const monoModuleConstructor = (\n engineId: string,\n params: IModuleConstructor<ModuleType.Oscillator>,\n ) => new MonoOscillator(engineId, params);\n\n super(engineId, {\n ...params,\n props,\n monoModuleConstructor,\n });\n\n this.registerInputs();\n this.registerDefaultIOs(\"out\");\n }\n\n start(time: ContextTime) {\n this.audioModules.forEach((audioModule) => {\n audioModule.start(time);\n });\n }\n\n stop(time: ContextTime) {\n this.audioModules.forEach((audioModule) => {\n audioModule.stop(time);\n });\n }\n\n private registerInputs() {\n this.registerAudioInput({ name: \"detune\" });\n }\n}\n","import { assertNever, Context } from \"@blibliki/utils\";\nimport { filterProcessorURL } from \"./filter-processor\";\nimport { scaleProcessorURL } from \"./scale-processor\";\n\nexport enum CustomWorklet {\n ScaleProcessor = \"ScaleProcessor\",\n FilterProcessor = \"FilterProcessor\",\n}\n\nexport async function loadProcessors(context: Context) {\n await context.addModule(scaleProcessorURL);\n await context.addModule(filterProcessorURL);\n}\n\nexport function newAudioWorklet(context: Context, worklet: CustomWorklet) {\n switch (worklet) {\n case CustomWorklet.ScaleProcessor:\n return context.newAudioWorklet(\"scale-processor\");\n case CustomWorklet.FilterProcessor:\n return context.newAudioWorklet(\"filter-processor\");\n default:\n assertNever(worklet);\n }\n}\n","export const filterProcessorURL = URL.createObjectURL(\n new Blob(\n [\n \"(\",\n (() => {\n class FilterProcessor extends AudioWorkletProcessor {\n s0: number;\n s1: number;\n\n constructor() {\n super();\n this.s0 = 0;\n this.s1 = 0;\n }\n\n static get parameterDescriptors() {\n return [\n {\n name: \"cutoff\",\n defaultValue: 1000,\n minValue: 20,\n maxValue: 20000,\n },\n {\n name: \"resonance\",\n defaultValue: 0.0,\n minValue: 0.0,\n maxValue: 4.0,\n },\n ];\n }\n\n process(\n inputs: Float32Array[][],\n outputs: Float32Array[][],\n parameters: Record<string, Float32Array>,\n ): boolean {\n const input = inputs[0];\n const output = outputs[0];\n\n const cutoff = parameters.cutoff;\n const resonance = parameters.resonance;\n\n for (let channelNum = 0; channelNum < input.length; channelNum++) {\n const inputChannel = input[channelNum];\n const outputChannel = output[channelNum];\n\n for (let i = 0; i < inputChannel.length; i++) {\n const s = inputChannel[i];\n // Convert Hz to normalized frequency using logarithmic scale\n // This better matches human hearing perception\n const cutoffHz = cutoff.length > 1 ? cutoff[i] : cutoff[0];\n const clampedHz = Math.max(20, Math.min(20000, cutoffHz));\n const normalizedCutoff =\n Math.log(clampedHz / 20) / Math.log(20000 / 20);\n const c = Math.pow(0.5, (1 - normalizedCutoff) / 0.125);\n const r = Math.pow(\n 0.5,\n ((resonance.length > 1 ? resonance[i] : resonance[0]) +\n 0.125) /\n 0.125,\n );\n const mrc = 1 - r * c;\n\n this.s0 = mrc * this.s0 - c * this.s1 + c * s;\n this.s1 = mrc * this.s1 + c * this.s0;\n\n outputChannel[i] = this.s1;\n }\n }\n\n return true;\n }\n }\n\n registerProcessor(\"filter-processor\", FilterProcessor);\n }).toString(),\n \")()\",\n ],\n { type: \"application/javascript\" },\n ),\n);\n","export const scaleProcessorURL = URL.createObjectURL(\n new Blob(\n [\n \"(\",\n (() => {\n class ScaleProcessor extends AudioWorkletProcessor {\n static get parameterDescriptors() {\n return [\n {\n name: \"min\",\n defaultValue: 1e-10,\n },\n {\n name: \"max\",\n defaultValue: 1,\n },\n {\n name: \"current\",\n defaultValue: 0.5,\n },\n ];\n }\n\n process(\n inputs: Float32Array[][],\n outputs: Float32Array[][],\n parameters: Record<string, Float32Array>,\n ) {\n const input = inputs[0];\n const output = outputs[0];\n\n const minValues = parameters.min;\n const maxValues = parameters.max;\n const currentValues = parameters.current;\n\n if (!input.length || input[0].length === 0) {\n for (const outputChannel of output) {\n const current =\n parameters.current.length > 1\n ? parameters.current[0]\n : parameters.current[0];\n\n outputChannel.fill(current);\n }\n\n return true;\n }\n\n for (let channel = 0; channel < input.length; channel++) {\n const inputChannel = input[channel];\n const outputChannel = output[channel];\n\n for (let i = 0; i < inputChannel.length; i++) {\n const x = inputChannel[i];\n\n const min = minValues.length > 1 ? minValues[i] : minValues[0];\n const max = maxValues.length > 1 ? maxValues[i] : maxValues[0];\n const current =\n currentValues.length > 1\n ? currentValues[i]\n : currentValues[0];\n\n if (x < 0) {\n outputChannel[i] = current * Math.pow(min / current, -x);\n } else {\n outputChannel[i] = current * Math.pow(max / current, x);\n }\n }\n }\n\n return true;\n }\n }\n\n registerProcessor(\"scale-processor\", ScaleProcessor);\n }).toString(),\n \")()\",\n ],\n { type: \"application/javascript\" },\n ),\n);\n","import { Context } from \"@blibliki/utils\";\nimport { IModule, Module, SetterHooks } from \"@/core\";\nimport { ModulePropSchema } from \"@/core/schema\";\nimport { CustomWorklet, newAudioWorklet } from \"@/processors\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IScale = IModule<ModuleType.Scale>;\nexport type IScaleProps = {\n min: number;\n max: number;\n current: number;\n};\n\nexport const scalePropSchema: ModulePropSchema<IScaleProps> = {\n min: {\n kind: \"number\",\n min: -Infinity,\n max: Infinity,\n step: 0.01,\n label: \"Min\",\n },\n max: {\n kind: \"number\",\n min: -Infinity,\n max: Infinity,\n step: 0.01,\n label: \"Max\",\n },\n current: {\n kind: \"number\",\n min: -Infinity,\n max: Infinity,\n step: 0.01,\n label: \"Current\",\n },\n};\n\nconst DEFAULT_PROPS: IScaleProps = { min: 0, max: 1, current: 0.5 };\n\nexport default class Scale\n extends Module<ModuleType.Scale>\n implements\n Pick<\n SetterHooks<IScaleProps>,\n \"onAfterSetMin\" | \"onAfterSetMax\" | \"onAfterSetCurrent\"\n >\n{\n declare audioNode: AudioWorkletNode;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.Scale>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const audioNodeConstructor = (context: Context) =>\n newAudioWorklet(context, CustomWorklet.ScaleProcessor);\n\n super(engineId, {\n ...params,\n props,\n audioNodeConstructor,\n });\n\n this.registerDefaultIOs();\n }\n\n get current() {\n return this.audioNode.parameters.get(\"current\")!;\n }\n\n get min() {\n return this.audioNode.parameters.get(\"min\")!;\n }\n\n get max() {\n return this.audioNode.parameters.get(\"max\")!;\n }\n\n onAfterSetMin: SetterHooks<IScaleProps>[\"onAfterSetMin\"] = (value) => {\n this.min.value = value;\n };\n\n onAfterSetMax: SetterHooks<IScaleProps>[\"onAfterSetMax\"] = (value) => {\n this.max.value = value;\n };\n\n onAfterSetCurrent: SetterHooks<IScaleProps>[\"onAfterSetCurrent\"] = (\n value,\n ) => {\n this.current.value = value;\n };\n}\n","import { INote, Module, IModule, MidiOutput, ModulePropSchema } from \"@/core\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IStepSequencer = IModule<ModuleType.StepSequencer>;\n\nexport type ISequence = {\n active: boolean;\n // time: BarsBeatsSixteenths;\n duration: string;\n notes: INote[];\n};\n\nexport type IStepSequencerProps = {\n bars: number;\n steps: number;\n sequences: ISequence[][];\n};\n\nexport const stepSequencerPropSchema: ModulePropSchema<\n Omit<IStepSequencerProps, \"sequences\">\n> = {\n steps: {\n kind: \"number\",\n min: 1,\n max: 16,\n step: 1,\n label: \"Steps\",\n },\n bars: {\n kind: \"number\",\n min: 1,\n max: 16,\n step: 1,\n label: \"Steps\",\n },\n};\n\nconst DEFAULT_PROPS: IStepSequencerProps = {\n sequences: [],\n steps: 16,\n bars: 1,\n};\n\n// Not implemented yet, just the data modeling\nexport default class StepSequencer extends Module<ModuleType.StepSequencer> {\n declare audioNode: undefined;\n midiOutput!: MidiOutput;\n\n constructor(\n engineId: string,\n params: ICreateModule<ModuleType.StepSequencer>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n\n super(engineId, {\n ...params,\n props,\n });\n }\n}\n","import { Context } from \"@blibliki/utils\";\nimport { StereoPannerNode } from \"@blibliki/utils/web-audio-api\";\nimport { IModule, Module, ModulePropSchema } from \"@/core\";\nimport { IModuleConstructor, SetterHooks } from \"@/core/module/Module\";\nimport { IPolyModuleConstructor, PolyModule } from \"@/core/module/PolyModule\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IStereoPanner = IModule<ModuleType.StereoPanner>;\nexport type IStereoPannerProps = {\n pan: number;\n};\n\nexport const stereoPannerPropSchema: ModulePropSchema<IStereoPannerProps> = {\n pan: {\n kind: \"number\",\n min: -1,\n max: 1,\n step: 0.01,\n label: \"Pan\",\n },\n};\n\nconst DEFAULT_PROPS: IStereoPannerProps = {\n pan: 0,\n};\n\nexport class MonoStereoPanner\n extends Module<ModuleType.StereoPanner>\n implements Pick<SetterHooks<IStereoPannerProps>, \"onAfterSetPan\">\n{\n declare audioNode: StereoPannerNode;\n\n constructor(\n engineId: string,\n params: ICreateModule<ModuleType.StereoPanner>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const audioNodeConstructor = (context: Context) =>\n new StereoPannerNode(context.audioContext);\n\n super(engineId, {\n ...params,\n audioNodeConstructor,\n props,\n });\n\n this.registerDefaultIOs();\n this.registerAdditionalInputs();\n }\n\n onAfterSetPan: SetterHooks<IStereoPannerProps>[\"onAfterSetPan\"] = (value) => {\n this.audioNode.pan.value = value;\n };\n\n private registerAdditionalInputs() {\n this.registerAudioInput({\n name: \"pan\",\n getAudioNode: () => this.audioNode.pan,\n });\n }\n}\n\nexport default class StereoPanner extends PolyModule<ModuleType.StereoPanner> {\n constructor(\n engineId: string,\n params: IPolyModuleConstructor<ModuleType.StereoPanner>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const monoModuleConstructor = (\n engineId: string,\n params: IModuleConstructor<ModuleType.StereoPanner>,\n ) => new MonoStereoPanner(engineId, params);\n\n super(engineId, {\n ...params,\n props,\n monoModuleConstructor,\n });\n\n this.registerAdditionalInputs();\n this.registerDefaultIOs();\n }\n\n private registerAdditionalInputs() {\n this.registerAudioInput({ name: \"pan\" });\n }\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport { Module, IModule, MidiOutput, Note, ModulePropSchema } from \"@/core\";\nimport MidiEvent from \"@/core/midi/MidiEvent\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IVirtualMidi = IModule<ModuleType.VirtualMidi>;\nexport type IVirtualMidiProps = {\n activeNotes: string[];\n};\n\nexport const virtualMidiPropSchema: ModulePropSchema<IVirtualMidiProps> = {\n activeNotes: {\n kind: \"array\",\n label: \"Active notes\",\n },\n};\n\nconst DEFAULT_PROPS: IVirtualMidiProps = { activeNotes: [] };\n\nexport default class VirtualMidi extends Module<ModuleType.VirtualMidi> {\n declare audioNode: undefined;\n midiOutput!: MidiOutput;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.VirtualMidi>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n\n super(engineId, {\n ...params,\n props,\n });\n\n this.registerInputs();\n this.registerOutputs();\n }\n\n sendMidi(midiEvent: MidiEvent) {\n this.midiOutput.onMidiEvent(midiEvent);\n }\n\n triggerAttack = (note: Note, triggerAttack: ContextTime) => {\n this.props = { activeNotes: [...this.props.activeNotes, note.fullName] };\n this.triggerPropsUpdate();\n this.sendMidi(MidiEvent.fromNote(note, true, triggerAttack));\n };\n\n triggerRelease = (note: Note, triggerAttack: ContextTime) => {\n this.props = {\n activeNotes: this.props.activeNotes.filter(\n (name) => name !== note.fullName,\n ),\n };\n this.triggerPropsUpdate();\n this.sendMidi(MidiEvent.fromNote(note, false, triggerAttack));\n };\n\n private registerInputs() {\n this.registerMidiInput({\n name: \"midi in\",\n onMidiEvent: this.onMidiEvent,\n });\n }\n\n private registerOutputs() {\n this.midiOutput = this.registerMidiOutput({ name: \"midi out\" });\n }\n}\n","export { Engine } from \"./Engine\";\nexport type { ICreateRoute, IUpdateModule, IEngineSerialize } from \"./Engine\";\n\nexport type {\n IRoute,\n IIOSerialize,\n IModule,\n IModuleSerialize,\n IPolyModuleSerialize,\n IMidiDevice,\n ModulePropSchema,\n PropSchema,\n StringProp,\n NumberProp,\n EnumProp,\n BooleanProp,\n ArrayProp,\n INote,\n} from \"./core\";\nexport { MidiDevice, MidiPortState, Note } from \"./core\";\n\nexport { TransportState } from \"@blibliki/transport\";\nexport type { TimeSignature, Position } from \"@blibliki/transport\";\n\nexport { Context } from \"@blibliki/utils\";\n\nexport {\n ModuleType,\n moduleSchemas,\n OscillatorWave,\n MidiMappingMode,\n} from \"./modules\";\nexport type {\n IOscillator,\n IGain,\n IMaster,\n ISequence,\n IStepSequencerProps,\n IStepSequencer,\n ModuleTypeToPropsMapping,\n ICreateModule,\n ModuleParams,\n IMidiMapper,\n IMidiMapperProps,\n MidiMapping,\n} from \"./modules\";\n"],"mappings":"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","names":["Transport","assertDefined","Context","pick","uuidv4","upperFirst","uuidv4","assertNever","sortBy","deterministicId","uuidv4","PolyModule","engineId","params","id","name","moduleType","voices","monoModuleConstructor","props","uuidv4","InputCollection","OutputCollection","value","m","time","audioModule","from","to","output","input","callback","midiEvent","voiceNo","moduleByVoice","deterministicId","Engine","AudioParam","deterministicId","Base","module","props","deterministicId","io","plugOther","currentIO","callback","connections","otherIO","IO","PolyAudioInput","IO","io","plugOther","PolyAudioOutput","plugOrUnplug","voice","thisIO","otherIO","isPlug","maxVoices","thisMonoIO","otherMonoIO","AudioInput","IO","module","props","AudioOutput","io","plugOther","PolyAudioInput","input","AudioParam","MidiInput","IO","module","props","MidiOutput","event","input","IOCollection","collectionType","module","props","io","PolyModule","AudioInput","AudioOutput","Module","PolyAudioInput","PolyAudioOutput","MidiInput","MidiOutput","assertNever","callback","id","name","sortBy","InputCollection","OutputCollection","frequencyTable","frequencyTable_default","Notes","MIDI_OCTAVE_SYTSTEM","Note","_Note","frequency","noteName","note","freq","frequencyTable_default","message","name","octave","noteOn","statusByte","string","matches","props","Message","data","MidiEvent","_MidiEvent","noteName","noteOn","triggeredAt","note","Note","Message","cc","value","message","voiceNo","newEvent","Module","engineId","params","id","name","moduleType","voiceNo","audioNodeConstructor","props","uuidv4","InputCollection","OutputCollection","value","updatedValue","key","propValue","result","hookType","hookName","upperFirst","hook","audioModule","from","to","output","input","callback","_time","note","_triggeredAt","n","_event","midiEvent","triggeredAt","Engine","uuidv4","Routes","engine","props","id","route","_","sourceIO","destinationIO","source","destination","MidiPortState","MidiDevice","input","context","id","name","state","callback","c","event","message","Message","midiEvent","MidiEvent","MAP_KEYS","Note","computerKeyboardData","ComputerKeyboardInput","context","id","name","state","callback","c","noteOn","event","note","midiEvent","MidiEvent","isNode","isNode","NodeMidiInputPort","portIndex","name","input","state","callback","_deltaTime","message","event","cb","err","NodeMidiAccess","MidiModule","portCount","i","portName","id","portInput","port","_event","_callback","NodeMidiAdapter","midi","midiModule","WebMidiInputPort","input","callback","e","event","cb","WebMidiAccess","midiAccess","port","WebMidiAdapter","err","createMidiAdapter","isNode","NodeMidiAdapter","WebMidiAdapter","MidiDeviceManager","createMidiAdapter","context","id","name","d","callback","input","MidiDevice","err","computerKeyboardDevice","ComputerKeyboardInput","port","device","listener","assertNever","voiceSchedulerPropSchema","DEFAULT_PROPS","Voice","Module","engineId","params","props","midiEvent","triggeredAt","note","type","noteName","VoiceScheduler","PolyModule","monoModuleConstructor","voice","v","a","b","ConstantSourceNode","constantPropSchema","DEFAULT_PROPS","Constant","Module","engineId","params","props","audioNodeConstructor","context","ConstantSourceNode","value","time","note","triggeredAt","cancelAndHoldAtTime","GainNode","DEFAULT_PROPS","envelopePropSchema","MonoEnvelope","Module","engineId","params","props","audioNodeConstructor","context","audioNode","GainNode","note","triggeredAt","attack","decay","sustain","cancelAndHoldAtTime","release","currentGainValue","Envelope","PolyModule","monoModuleConstructor","BiquadFilterNode","GainNode","gainPropSchema","DEFAULT_PROPS","MonoGain","Module","engineId","params","props","audioNodeConstructor","context","GainNode","value","Gain","PolyModule","monoModuleConstructor","MIN_FREQ","MAX_FREQ","DEFAULT_PROPS","filterPropSchema","MonoFilter","Module","engineId","params","props","audioNodeConstructor","context","BiquadFilterNode","MonoGain","createModule","value","Filter","PolyModule","monoModuleConstructor","AnalyserNode","inspectorPropSchema","DEFAULT_PROPS","Inspector","Module","engineId","params","props","audioNodeConstructor","context","AnalyserNode","value","DEFAULT_PROPS","masterPropSchema","Master","Module","engineId","params","props","audioNodeConstructor","context","MidiMappingMode","midiMapperPropSchema","DEFAULT_PROPS","getMidiFromMappedValue","value","midiValue","propSchema","mapping","min","max","exp","threshold","mode","curvedValue","newMidiValue","MidiMapper","Module","engineId","params","props","event","triggeredAt","activePage","m","_triggeredAt","propName","mappedModule","moduleSchemas","mappedValue","currentValue","normalizedMidi","steps","optionIndex","clampedIndex","hasGlobalAutoAssign","autoAssign","hasPageAutoAssign","updatedGlobalMappings","updatedPageMappings","updatedPages","page","index","midiSelectorPropSchema","DEFAULT_PROPS","MidiSelector","Module","engineId","params","props","midiDevice","value","midiEvent","dbToGain","GainNode","OscillatorNode","LOW_GAIN","OscillatorWave","oscillatorPropSchema","DEFAULT_PROPS","MonoOscillator","Module","engineId","params","props","audioNodeConstructor","context","OscillatorNode","GainNode","dbToGain","value","lowGain","time","note","triggeredAt","lastNote","frequency","coarse","octave","fine","actionAt","Oscillator","PolyModule","monoModuleConstructor","audioModule","assertNever","filterProcessorURL","FilterProcessor","inputs","outputs","parameters","input","output","cutoff","resonance","channelNum","inputChannel","outputChannel","i","s","cutoffHz","clampedHz","normalizedCutoff","c","mrc","scaleProcessorURL","ScaleProcessor","inputs","outputs","parameters","input","output","minValues","maxValues","currentValues","outputChannel","current","channel","inputChannel","i","x","min","max","loadProcessors","context","scaleProcessorURL","filterProcessorURL","newAudioWorklet","worklet","assertNever","scalePropSchema","DEFAULT_PROPS","Scale","Module","engineId","params","props","audioNodeConstructor","context","newAudioWorklet","value","stepSequencerPropSchema","DEFAULT_PROPS","StepSequencer","Module","engineId","params","props","StereoPannerNode","stereoPannerPropSchema","DEFAULT_PROPS","MonoStereoPanner","Module","engineId","params","props","audioNodeConstructor","context","StereoPannerNode","value","StereoPanner","PolyModule","monoModuleConstructor","virtualMidiPropSchema","DEFAULT_PROPS","VirtualMidi","Module","engineId","params","props","midiEvent","note","triggerAttack","MidiEvent","name","ModuleType","moduleSchemas","oscillatorPropSchema","gainPropSchema","masterPropSchema","midiSelectorPropSchema","envelopePropSchema","filterPropSchema","scalePropSchema","stereoPannerPropSchema","inspectorPropSchema","constantPropSchema","midiMapperPropSchema","virtualMidiPropSchema","stepSequencerPropSchema","voiceSchedulerPropSchema","createModule","engineId","params","Oscillator","Gain","Master","MidiSelector","Envelope","Filter","Scale","StereoPanner","Inspector","Constant","MidiMapper","VirtualMidi","StepSequencer","VoiceScheduler","assertNever","Engine","_Engine","id","engine","assertDefined","data","bpm","timeSignature","modules","routes","context","Context","m","r","uuidv4","Transport","_start","_end","_event","_ticks","_actionAt","Routes","MidiDeviceManager","loadProcessors","params","module","createModule","updates","pick","PolyModule","props","source","destination","output","input","value","moduleId","ioName","type","name","callback","noteName","virtualMidi","MidiEvent","actionAt","TransportState","Context"]}
|
|
1
|
+
{"version":3,"sources":["../src/Engine.ts","../src/core/module/Module.ts","../src/core/IO/Collection.ts","../src/core/module/PolyModule.ts","../src/core/IO/AudioIO.ts","../src/core/IO/Base.ts","../src/core/IO/PolyAudioIO.ts","../src/core/IO/MidiIO.ts","../src/core/Note/frequencyTable.ts","../src/core/Note/index.ts","../src/core/midi/Message.ts","../src/core/midi/MidiEvent.ts","../src/core/Route.ts","../src/core/midi/MidiDevice.ts","../src/core/midi/ComputerKeyboardDevice.ts","../src/core/midi/adapters/index.ts","../src/core/midi/adapters/NodeMidiAdapter.ts","../src/core/midi/adapters/WebMidiAdapter.ts","../src/core/midi/deviceMatcher.ts","../src/core/midi/MidiDeviceManager.ts","../src/modules/index.ts","../src/core/module/VoiceScheduler.ts","../src/modules/Constant.ts","../src/modules/Envelope.ts","../src/modules/Filter.ts","../src/modules/Gain.ts","../src/modules/Inspector.ts","../src/modules/Master.ts","../src/modules/MidiMapper.ts","../src/modules/MidiSelector.ts","../src/modules/Oscillator.ts","../src/processors/index.ts","../src/processors/filter-processor.ts","../src/processors/scale-processor.ts","../src/modules/Scale.ts","../src/modules/StepSequencer.ts","../src/modules/StereoPanner.ts","../src/modules/VirtualMidi.ts","../src/index.ts"],"sourcesContent":["import {\n BPM,\n ContextTime,\n Ticks,\n TimeSignature,\n Transport,\n TransportEvent,\n} from \"@blibliki/transport\";\nimport {\n assertDefined,\n Context,\n Optional,\n pick,\n uuidv4,\n} from \"@blibliki/utils\";\nimport {\n IRoute,\n Routes,\n MidiDeviceManager,\n IModule,\n MidiEvent,\n IModuleSerialize,\n} from \"@/core\";\nimport {\n ICreateModule,\n ModuleParams,\n ModuleType,\n ModuleTypeToModuleMapping,\n createModule,\n} from \"@/modules\";\nimport {\n IPolyModule,\n IPolyModuleSerialize,\n PolyModule,\n} from \"./core/module/PolyModule\";\nimport { loadProcessors } from \"./processors\";\n\nexport type IUpdateModule<T extends ModuleType> = {\n id: string;\n moduleType: T;\n changes: Partial<Omit<ICreateModule<T>, \"id\" | \"moduleType\" | \"voice\">> & {\n voices?: number;\n };\n};\n\nexport type ICreateRoute = Optional<IRoute, \"id\">;\n\nexport interface IEngineSerialize {\n bpm: BPM;\n timeSignature: TimeSignature;\n modules: (IModuleSerialize<ModuleType> | IPolyModuleSerialize<ModuleType>)[];\n routes: IRoute[];\n}\n\nexport class Engine {\n private static _engines = new Map<string, Engine>();\n private static _currentId: string | undefined;\n private propsUpdateCallbacks: (<T extends ModuleType>(\n params: IModule<T> | IPolyModule<T>,\n ) => void)[] = [];\n\n readonly id: string;\n context: Context;\n isInitialized = false;\n routes: Routes;\n transport: Transport<TransportEvent>;\n modules: Map<\n string,\n ModuleTypeToModuleMapping[keyof ModuleTypeToModuleMapping]\n >;\n\n midiDeviceManager: MidiDeviceManager;\n\n static getById(id: string): Engine {\n const engine = Engine._engines.get(id);\n assertDefined(engine);\n\n return engine;\n }\n\n static get current(): Engine {\n assertDefined(this._currentId);\n\n return this.getById(this._currentId);\n }\n\n static async load(data: IEngineSerialize): Promise<Engine> {\n const { bpm, timeSignature, modules, routes } = data;\n const context = new Context();\n const engine = new Engine(context);\n await engine.initialize();\n\n engine.timeSignature = timeSignature;\n engine.bpm = bpm;\n modules.forEach((m) => {\n engine.addModule(m);\n });\n routes.forEach((r) => {\n engine.addRoute(r);\n });\n\n return engine;\n }\n\n constructor(context: Context) {\n this.id = uuidv4();\n\n this.context = context;\n this.transport = new Transport(this.context, {\n generator: (_start: Ticks, _end: Ticks) => {\n return [] as TransportEvent[];\n },\n consumer: (_event: TransportEvent) => {\n return;\n },\n onJump: (_ticks: Ticks) => {\n return;\n },\n onStart: this.onStart,\n onStop: this.onStop,\n silence: (_actionAt: ContextTime) => {\n return;\n },\n });\n this.routes = new Routes(this);\n this.modules = new Map();\n this.midiDeviceManager = new MidiDeviceManager(this.context);\n\n Engine._engines.set(this.id, this);\n Engine._currentId = this.id;\n }\n\n get state() {\n return this.transport.state;\n }\n\n async initialize() {\n if (this.isInitialized) return;\n\n await loadProcessors(this.context);\n await this.midiDeviceManager.initialize();\n this.isInitialized = true;\n }\n\n addModule<T extends ModuleType>(params: ICreateModule<T>) {\n const module = createModule(this.id, params as ModuleParams);\n this.modules.set(module.id, module);\n\n return module.serialize();\n }\n\n updateModule<T extends ModuleType>(params: IUpdateModule<T>) {\n const module = this.findModule(params.id);\n if (module.moduleType !== params.moduleType) {\n throw Error(\n `The module id ${params.id} isn't moduleType ${params.moduleType}`,\n );\n }\n\n const updates = pick(params.changes, [\"name\", \"props\"]);\n Object.assign(module, updates);\n\n if (module instanceof PolyModule && params.changes.voices !== undefined) {\n module.voices = params.changes.voices;\n }\n\n return module.serialize();\n }\n\n removeModule(id: string) {\n this.modules.delete(id);\n }\n\n addRoute(props: ICreateRoute): IRoute {\n return this.routes.addRoute(props);\n }\n\n removeRoute(id: string) {\n this.routes.removeRoute(id);\n }\n\n validRoute(props: Optional<IRoute, \"id\">): boolean {\n const { source, destination } = props;\n\n const output = this.findIO(source.moduleId, source.ioName, \"output\");\n const input = this.findIO(\n destination.moduleId,\n destination.ioName,\n \"input\",\n );\n\n return (\n (output.isMidi() && input.isMidi()) ||\n (output.isAudio() && input.isAudio())\n );\n }\n\n async start() {\n await this.resume();\n this.transport.start();\n }\n\n stop() {\n this.transport.stop();\n this.transport.reset();\n }\n\n pause() {\n this.transport.stop();\n }\n\n get bpm() {\n return this.transport.bpm;\n }\n\n set bpm(value: number) {\n this.transport.bpm = value;\n }\n\n get timeSignature() {\n return this.transport.timeSignature;\n }\n\n set timeSignature(value: TimeSignature) {\n this.transport.timeSignature = value;\n }\n\n async resume() {\n await this.context.resume();\n }\n\n dispose() {\n this.stop();\n this.routes.clear();\n this.modules.forEach((module) => {\n module.dispose();\n });\n this.modules.clear();\n }\n\n serialize(): IEngineSerialize {\n return {\n bpm: this.bpm,\n timeSignature: this.timeSignature,\n modules: Array.from(this.modules.values()).map((m) => m.serialize()),\n routes: this.routes.serialize(),\n };\n }\n\n findModule(\n id: string,\n ): ModuleTypeToModuleMapping[keyof ModuleTypeToModuleMapping] {\n const module = this.modules.get(id);\n if (!module) throw Error(`The module with id ${id} is not exists`);\n\n return module;\n }\n\n findIO(moduleId: string, ioName: string, type: \"input\" | \"output\") {\n const module = this.findModule(moduleId);\n return module[`${type}s`].findByName(ioName);\n }\n\n findMidiDevice(id: string) {\n return this.midiDeviceManager.find(id);\n }\n\n findMidiDeviceByName(name: string) {\n return this.midiDeviceManager.findByName(name);\n }\n\n findMidiDeviceByFuzzyName(name: string, threshold?: number) {\n return this.midiDeviceManager.findByFuzzyName(name, threshold);\n }\n\n onPropsUpdate(\n callback: <T extends ModuleType>(\n params: IModule<T> | IPolyModule<T>,\n ) => void,\n ) {\n this.propsUpdateCallbacks.push(callback);\n }\n\n _triggerPropsUpdate<T extends ModuleType>(\n params: IModule<T> | IPolyModule<T>,\n ) {\n this.propsUpdateCallbacks.forEach((callback) => {\n callback(params);\n });\n }\n\n // TODO: Find better way to support this\n triggerVirtualMidi(id: string, noteName: string, type: \"noteOn\" | \"noteOff\") {\n const virtualMidi = this.findModule(id);\n if (virtualMidi.moduleType !== ModuleType.VirtualMidi)\n throw Error(\"This is not a virtual mid\");\n\n virtualMidi.sendMidi(\n MidiEvent.fromNote(noteName, type === \"noteOn\", this.context.currentTime),\n );\n }\n\n // actionAt is context time\n private onStart = (actionAt: ContextTime) => {\n this.modules.forEach((module) => {\n module.start(actionAt);\n });\n };\n\n // actionAt is context time\n private onStop = (actionAt: ContextTime) => {\n this.modules.forEach((module) => {\n module.stop(actionAt);\n });\n };\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport {\n Context,\n Optional,\n upperFirst,\n uuidv4,\n requestAnimationFrame,\n} from \"@blibliki/utils\";\nimport { Engine } from \"@/Engine\";\nimport { AnyModule, ModuleType, ModuleTypeToPropsMapping } from \"@/modules\";\nimport {\n AudioInputProps,\n AudioOutputProps,\n IIOSerialize,\n IOType,\n InputCollection,\n OutputCollection,\n MidiInputProps,\n MidiOutputProps,\n} from \"../IO\";\nimport Note from \"../Note\";\nimport MidiEvent, { MidiEventType } from \"../midi/MidiEvent\";\n\nexport type IModule<T extends ModuleType> = {\n id: string;\n name: string;\n voiceNo: number;\n moduleType: T;\n props: ModuleTypeToPropsMapping[T];\n};\n\nexport type IModuleSerialize<T extends ModuleType> = IModule<T> & {\n inputs: IIOSerialize[];\n outputs: IIOSerialize[];\n};\n\nexport type IModuleConstructor<T extends ModuleType> = Optional<\n IModule<T>,\n \"id\" | \"voiceNo\"\n> & {\n audioNodeConstructor?: (context: Context) => AudioNode;\n};\n\nexport type SetterHooks<P> = {\n [K in keyof P as `onSet${Capitalize<string & K>}`]: (value: P[K]) => P[K];\n} & {\n [K in keyof P as `onAfterSet${Capitalize<string & K>}`]: (\n value: P[K],\n ) => void;\n};\n\nexport abstract class Module<T extends ModuleType> implements IModule<T> {\n id: string;\n engineId: string;\n name: string;\n moduleType: T;\n voiceNo: number;\n audioNode: AudioNode | undefined;\n inputs: InputCollection;\n outputs: OutputCollection;\n protected _props!: ModuleTypeToPropsMapping[T];\n protected activeNotes: Note[];\n private pendingUIUpdates = false;\n\n constructor(engineId: string, params: IModuleConstructor<T>) {\n const { id, name, moduleType, voiceNo, audioNodeConstructor, props } =\n params;\n\n this.id = id ?? uuidv4();\n this.engineId = engineId;\n this.name = name;\n this.moduleType = moduleType;\n this.voiceNo = voiceNo ?? 0;\n this.activeNotes = [];\n this.audioNode = audioNodeConstructor?.(this.context);\n this._props = props;\n\n this.inputs = new InputCollection(this);\n this.outputs = new OutputCollection(this);\n\n // Defer hook calls until after subclass is fully initialized\n queueMicrotask(() => {\n this.props = props;\n });\n }\n\n get props(): ModuleTypeToPropsMapping[T] {\n return this._props;\n }\n\n set props(value: Partial<ModuleTypeToPropsMapping[T]>) {\n const updatedValue = { ...value };\n\n (Object.keys(value) as (keyof ModuleTypeToPropsMapping[T])[]).forEach(\n (key) => {\n const propValue = value[key];\n if (propValue !== undefined) {\n const result = this.callPropHook(\"onSet\", key, propValue);\n if (result !== undefined) {\n updatedValue[key] = result;\n }\n }\n },\n );\n\n this._props = { ...this._props, ...updatedValue };\n\n (\n Object.keys(updatedValue) as (keyof ModuleTypeToPropsMapping[T])[]\n ).forEach((key) => {\n const propValue = updatedValue[key];\n if (propValue !== undefined) {\n this.callPropHook(\"onAfterSet\", key, propValue);\n }\n });\n }\n\n private callPropHook<K extends keyof ModuleTypeToPropsMapping[T]>(\n hookType: \"onSet\" | \"onAfterSet\",\n key: K,\n value: ModuleTypeToPropsMapping[T][K],\n ): ModuleTypeToPropsMapping[T][K] | undefined {\n const hookName = `${hookType}${upperFirst(key as string)}`;\n const hook = this[hookName as keyof this];\n\n if (typeof hook === \"function\") {\n const result = (\n hook as (\n value: ModuleTypeToPropsMapping[T][K],\n ) => ModuleTypeToPropsMapping[T][K] | undefined\n ).call(this, value);\n return result;\n }\n return undefined;\n }\n\n serialize(): IModuleSerialize<T> {\n return {\n id: this.id,\n name: this.name,\n moduleType: this.moduleType,\n voiceNo: this.voiceNo,\n props: this.props,\n inputs: this.inputs.serialize(),\n outputs: this.outputs.serialize(),\n };\n }\n\n plug({\n audioModule,\n from,\n to,\n }: {\n audioModule: AnyModule;\n from: string;\n to: string;\n }) {\n const output = this.outputs.findByName(from);\n const input = audioModule.inputs.findByName(to);\n\n output.plug(input);\n }\n\n protected rePlugAll(callback?: () => void) {\n this.inputs.rePlugAll(callback);\n this.outputs.rePlugAll(callback);\n }\n\n protected unPlugAll() {\n this.inputs.unPlugAll();\n this.outputs.unPlugAll();\n }\n\n start(_time: ContextTime): void {\n // Optional implementation in modules\n }\n\n stop(_time: ContextTime): void {\n // Optional implementation in modules\n }\n\n triggerAttack(note: Note, _triggeredAt: ContextTime): void {\n if (this.activeNotes.some((n) => n.fullName === note.fullName)) return;\n\n this.activeNotes.push(note);\n }\n\n triggerRelease(note: Note, _triggeredAt: ContextTime): void {\n this.activeNotes = this.activeNotes.filter(\n (n) => n.fullName !== note.fullName,\n );\n }\n\n handleCC(_event: MidiEvent, _triggeredAt: ContextTime): void {\n // Optional implementation in modules\n }\n\n onMidiEvent = (midiEvent: MidiEvent) => {\n const { note, triggeredAt } = midiEvent;\n\n switch (midiEvent.type) {\n case MidiEventType.noteOn: {\n this.triggerAttack(note!, triggeredAt);\n break;\n }\n case MidiEventType.noteOff:\n this.triggerRelease(note!, triggeredAt);\n break;\n case MidiEventType.cc:\n this.handleCC(midiEvent, triggeredAt);\n break;\n default:\n throw Error(\"This type is not a note\");\n }\n };\n\n triggerPropsUpdate = () => {\n if (this.pendingUIUpdates) return;\n\n this.pendingUIUpdates = true;\n this.sheduleTriggerUpdate();\n };\n\n private sheduleTriggerUpdate() {\n requestAnimationFrame(() => {\n this.engine._triggerPropsUpdate({\n id: this.id,\n moduleType: this.moduleType,\n voiceNo: this.voiceNo,\n name: this.name,\n props: this.props,\n });\n this.pendingUIUpdates = false;\n });\n }\n\n dispose() {\n this.inputs.unPlugAll();\n this.outputs.unPlugAll();\n }\n\n protected registerDefaultIOs(value: \"both\" | \"in\" | \"out\" = \"both\") {\n this.registerMidiInput({\n name: \"midi in\",\n onMidiEvent: this.onMidiEvent,\n });\n\n if (!this.audioNode) return;\n\n if (value === \"in\" || value === \"both\") {\n this.registerAudioInput({\n name: \"in\",\n getAudioNode: () => this.audioNode!,\n });\n }\n\n if (value === \"out\" || value === \"both\") {\n this.registerAudioOutput({\n name: \"out\",\n getAudioNode: () => this.audioNode!,\n });\n }\n }\n\n protected registerAudioInput(props: Omit<AudioInputProps, \"ioType\">) {\n return this.inputs.add({ ...props, ioType: IOType.AudioInput });\n }\n\n protected registerAudioOutput(props: Omit<AudioOutputProps, \"ioType\">) {\n return this.outputs.add({ ...props, ioType: IOType.AudioOutput });\n }\n\n protected registerMidiInput(props: Omit<MidiInputProps, \"ioType\">) {\n return this.inputs.add({ ...props, ioType: IOType.MidiInput });\n }\n\n protected registerMidiOutput(props: Omit<MidiOutputProps, \"ioType\">) {\n return this.outputs.add({\n ...props,\n ioType: IOType.MidiOutput,\n });\n }\n\n protected get engine() {\n return Engine.getById(this.engineId);\n }\n\n protected get context() {\n return this.engine.context;\n }\n}\n","import { assertNever } from \"@blibliki/utils\";\nimport { sortBy } from \"es-toolkit\";\nimport { ModuleType } from \"@/modules\";\nimport { Module } from \"../module\";\nimport { PolyModule } from \"../module/PolyModule\";\nimport {\n AudioInput,\n AudioInputProps,\n AudioOutput,\n AudioOutputProps,\n} from \"./AudioIO\";\nimport { Base, IOType } from \"./Base\";\nimport {\n MidiInput,\n MidiInputProps,\n MidiOutput,\n MidiOutputProps,\n} from \"./MidiIO\";\nimport {\n PolyAudioInput,\n PolyAudioInputProps,\n PolyAudioOutput,\n PolyAudioOutputProps,\n} from \"./PolyAudioIO\";\n\nexport enum CollectionType {\n Input = \"Input\",\n Output = \"Output\",\n}\n\ntype IMappedIOProps = {\n [CollectionType.Input]:\n | AudioInputProps\n | PolyAudioInputProps\n | MidiInputProps;\n [CollectionType.Output]:\n | AudioOutputProps\n | PolyAudioOutputProps\n | MidiOutputProps;\n};\n\ntype IIOTypeTOClass = {\n [IOType.AudioInput]: AudioInput;\n [IOType.AudioOutput]: AudioOutput;\n [IOType.PolyAudioInput]: PolyAudioInput;\n [IOType.PolyAudioOutput]: PolyAudioOutput;\n [IOType.MidiInput]: MidiInput;\n [IOType.MidiOutput]: MidiOutput;\n};\n\nexport default abstract class IOCollection<T extends CollectionType> {\n module: Module<ModuleType> | PolyModule<ModuleType>;\n collection: Base[] = [];\n collectionType: T;\n\n constructor(\n collectionType: T,\n module: Module<ModuleType> | PolyModule<ModuleType>,\n ) {\n this.collectionType = collectionType;\n this.module = module;\n }\n\n add<TT extends IMappedIOProps[T]>(props: TT): IIOTypeTOClass[TT[\"ioType\"]] {\n let io:\n | AudioInput\n | AudioOutput\n | PolyAudioInput\n | PolyAudioOutput\n | MidiInput\n | MidiOutput;\n this.validateUniqName(props.name);\n\n switch (props.ioType) {\n case IOType.AudioInput:\n if (this.module instanceof PolyModule) throw Error(\"Not compatible\");\n io = new AudioInput(this.module, props);\n break;\n case IOType.AudioOutput:\n if (this.module instanceof PolyModule) throw Error(\"Not compatible\");\n io = new AudioOutput(this.module, props);\n break;\n case IOType.PolyAudioInput:\n if (this.module instanceof Module) throw Error(\"Not compatible\");\n io = new PolyAudioInput(this.module, props);\n break;\n case IOType.PolyAudioOutput:\n if (this.module instanceof Module) throw Error(\"Not compatible\");\n io = new PolyAudioOutput(this.module, props);\n break;\n case IOType.MidiInput:\n io = new MidiInput(this.module, props);\n break;\n case IOType.MidiOutput:\n io = new MidiOutput(this.module, props);\n break;\n default:\n assertNever(props);\n }\n\n this.collection.push(io);\n\n return io as IIOTypeTOClass[TT[\"ioType\"]];\n }\n\n unPlugAll() {\n this.collection.forEach((io) => {\n io.unPlugAll();\n });\n }\n\n rePlugAll(callback?: () => void) {\n this.collection.forEach((io) => {\n io.rePlugAll(callback);\n });\n }\n\n find(id: string) {\n const io = this.collection.find((io) => io.id === id);\n if (!io) throw Error(`The io with id ${id} is not exists`);\n\n return io;\n }\n\n findByName(name: string) {\n const io = this.collection.find((io) => io.name === name);\n if (!io) throw Error(`The io with name ${name} is not exists`);\n\n return io;\n }\n\n serialize() {\n return sortBy(this.collection, [(io) => (io.isMidi() ? -1 : 1)]).map((io) =>\n io.serialize(),\n );\n }\n\n private validateUniqName(name: string) {\n if (this.collection.some((io) => io.name === name)) {\n throw Error(`An io with name ${name} is already exists`);\n }\n }\n}\n\nexport class InputCollection extends IOCollection<CollectionType.Input> {\n constructor(module: Module<ModuleType> | PolyModule<ModuleType>) {\n super(CollectionType.Input, module);\n }\n}\n\nexport class OutputCollection extends IOCollection<CollectionType.Output> {\n constructor(module: Module<ModuleType> | PolyModule<ModuleType>) {\n super(CollectionType.Output, module);\n }\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport {\n deterministicId,\n Optional,\n uuidv4,\n requestAnimationFrame,\n} from \"@blibliki/utils\";\nimport { Engine } from \"@/Engine\";\nimport { ModuleType, ModuleTypeToPropsMapping } from \"@/modules\";\nimport {\n IIOSerialize,\n InputCollection,\n IOType,\n MidiInputProps,\n MidiOutputProps,\n OutputCollection,\n} from \"../IO\";\nimport { PolyAudioInputProps, PolyAudioOutputProps } from \"../IO/PolyAudioIO\";\nimport MidiEvent from \"../midi/MidiEvent\";\nimport { IModule, IModuleConstructor, Module } from \"./Module\";\n\nexport type IPolyModule<T extends ModuleType> = Omit<IModule<T>, \"voiceNo\"> & {\n voices: number;\n};\n\nexport type IPolyModuleSerialize<T extends ModuleType> = IPolyModule<T> & {\n inputs: IIOSerialize[];\n outputs: IIOSerialize[];\n};\n\nexport type IPolyModuleConstructor<T extends ModuleType> = Optional<\n IPolyModule<T>,\n \"id\"\n> & {\n monoModuleConstructor: (\n engineId: string,\n params: IModuleConstructor<T>,\n ) => Module<T>;\n};\n\nexport abstract class PolyModule<\n T extends ModuleType,\n> implements IPolyModule<T> {\n id: string;\n engineId: string;\n moduleType: T;\n audioModules!: Module<T>[];\n inputs: InputCollection;\n outputs: OutputCollection;\n protected monoModuleConstructor: IPolyModuleConstructor<T>[\"monoModuleConstructor\"];\n protected _props!: ModuleTypeToPropsMapping[T];\n private _voices!: number;\n private _name!: string;\n private pendingUIUpdates = false;\n\n constructor(engineId: string, params: IPolyModuleConstructor<T>) {\n const { id, name, moduleType, voices, monoModuleConstructor, props } =\n params;\n\n this.audioModules = [];\n\n this.monoModuleConstructor = monoModuleConstructor;\n this.id = id ?? uuidv4();\n this.engineId = engineId;\n this.name = name;\n this.moduleType = moduleType;\n this._props = props;\n\n this.inputs = new InputCollection(\n this as unknown as PolyModule<ModuleType>,\n );\n this.outputs = new OutputCollection(\n this as unknown as PolyModule<ModuleType>,\n );\n\n // Defer hook calls until after subclass is fully initialized\n queueMicrotask(() => {\n this.voices = voices || 1;\n this.props = props;\n this.triggerPropsUpdate();\n });\n }\n\n get name() {\n return this._name;\n }\n\n set name(value: string) {\n this._name = value;\n this.audioModules.forEach((m) => (m.name = value));\n }\n\n get props(): ModuleTypeToPropsMapping[T] {\n return this._props;\n }\n\n set props(value: Partial<ModuleTypeToPropsMapping[T]>) {\n this._props = { ...this._props, ...value };\n this.audioModules.forEach((m) => (m.props = value));\n }\n\n get voices() {\n return this._voices;\n }\n\n set voices(value: number) {\n this._voices = value;\n this.adjustNumberOfModules();\n this.rePlugAll();\n }\n\n start(time: ContextTime): void {\n this.audioModules.forEach((m) => {\n m.start(time);\n });\n }\n\n stop(time: ContextTime): void {\n this.audioModules.forEach((m) => {\n m.stop(time);\n });\n }\n\n serialize(): IPolyModuleSerialize<T> {\n return {\n id: this.id,\n name: this.name,\n moduleType: this.moduleType,\n voices: this.voices,\n props: this.props,\n inputs: this.inputs.serialize(),\n outputs: this.outputs.serialize(),\n };\n }\n\n plug({\n audioModule,\n from,\n to,\n }: {\n audioModule: Module<ModuleType> | PolyModule<ModuleType>;\n from: string;\n to: string;\n }) {\n const output = this.outputs.findByName(from);\n const input = audioModule.inputs.findByName(to);\n\n output.plug(input);\n }\n\n rePlugAll(callback?: () => void) {\n this.inputs.rePlugAll(callback);\n this.outputs.rePlugAll(callback);\n }\n\n protected unPlugAll() {\n this.inputs.unPlugAll();\n this.outputs.unPlugAll();\n }\n\n dispose() {\n this.inputs.unPlugAll();\n this.outputs.unPlugAll();\n this.audioModules.forEach((m) => {\n m.dispose();\n });\n }\n\n onMidiEvent = (midiEvent: MidiEvent) => {\n const voiceNo = midiEvent.voiceNo ?? 0;\n const audioModule = this.findVoice(voiceNo);\n audioModule.onMidiEvent(midiEvent);\n };\n\n triggerPropsUpdate = () => {\n if (this.pendingUIUpdates) return;\n\n this.pendingUIUpdates = true;\n this.sheduleTriggerUpdate();\n };\n\n private sheduleTriggerUpdate() {\n requestAnimationFrame(() => {\n this.engine._triggerPropsUpdate({\n id: this.id,\n moduleType: this.moduleType,\n voices: this.voices,\n name: this.name,\n props: this.props,\n });\n this.pendingUIUpdates = false;\n });\n }\n\n findVoice(voiceNo: number) {\n const moduleByVoice = this.audioModules.find((m) => m.voiceNo === voiceNo);\n if (!moduleByVoice)\n throw Error(`Voice ${voiceNo} on module ${this.name} not found`);\n\n return moduleByVoice;\n }\n\n protected registerDefaultIOs(value: \"both\" | \"in\" | \"out\" = \"both\") {\n this.registerMidiInput({\n name: \"midi in\",\n onMidiEvent: this.onMidiEvent,\n });\n\n if (value === \"in\" || value === \"both\") {\n this.registerAudioInput({\n name: \"in\",\n });\n }\n\n if (value === \"out\" || value === \"both\") {\n this.registerAudioOutput({\n name: \"out\",\n });\n }\n }\n\n protected registerAudioInput(props: Omit<PolyAudioInputProps, \"ioType\">) {\n return this.inputs.add({ ...props, ioType: IOType.PolyAudioInput });\n }\n\n protected registerAudioOutput(props: Omit<PolyAudioOutputProps, \"ioType\">) {\n return this.outputs.add({ ...props, ioType: IOType.PolyAudioOutput });\n }\n\n protected registerMidiInput(props: Omit<MidiInputProps, \"ioType\">) {\n return this.inputs.add({ ...props, ioType: IOType.MidiInput });\n }\n\n protected registerMidiOutput(props: Omit<MidiOutputProps, \"ioType\">) {\n return this.outputs.add({\n ...props,\n ioType: IOType.MidiOutput,\n });\n }\n\n private adjustNumberOfModules() {\n if (this.audioModules.length === this.voices) return;\n\n if (this.audioModules.length > this.voices) {\n const audioModule = this.audioModules.pop();\n audioModule?.dispose();\n } else {\n const voiceNo = this.audioModules.length;\n const id = deterministicId(this.id, voiceNo.toString());\n\n const audioModule = this.monoModuleConstructor(this.engineId, {\n id,\n name: this.name,\n moduleType: this.moduleType,\n voiceNo,\n props: { ...this.props },\n });\n\n this.audioModules.push(audioModule);\n }\n\n this.adjustNumberOfModules();\n }\n\n protected get engine() {\n return Engine.getById(this.engineId);\n }\n\n protected get context() {\n return this.engine.context;\n }\n}\n","import { AudioParam } from \"@blibliki/utils/web-audio-api\";\nimport { ModuleType } from \"@/modules\";\nimport { Module } from \"../module\";\nimport IO, { IOProps, IOType } from \"./Base\";\nimport { PolyAudioInput, PolyAudioOutput } from \"./PolyAudioIO\";\n\nexport type AudioIO = AudioInput | AudioOutput;\n\nexport type AudioInputProps = IOProps & {\n ioType: IOType.AudioInput;\n getAudioNode: () => AudioNode | AudioParam | AudioDestinationNode;\n};\n\nexport type AudioOutputProps = IOProps & {\n ioType: IOType.AudioOutput;\n getAudioNode: () => AudioNode;\n};\n\nexport class AudioInput\n extends IO<AudioOutput | PolyAudioOutput>\n implements AudioInputProps\n{\n declare ioType: IOType.AudioInput;\n getAudioNode: AudioInputProps[\"getAudioNode\"];\n\n constructor(module: Module<ModuleType>, props: AudioInputProps) {\n super(module, props);\n this.getAudioNode = props.getAudioNode;\n }\n}\n\nexport class AudioOutput\n extends IO<AudioInput | PolyAudioInput>\n implements AudioOutputProps\n{\n declare ioType: IOType.AudioOutput;\n getAudioNode!: AudioOutputProps[\"getAudioNode\"];\n\n constructor(module: Module<ModuleType>, props: AudioOutputProps) {\n super(module, props);\n this.getAudioNode = props.getAudioNode;\n }\n\n plug(io: AudioInput | PolyAudioInput, plugOther = true) {\n super.plug(io, plugOther);\n if (io instanceof PolyAudioInput) return;\n\n const input = io.getAudioNode();\n\n if (input instanceof AudioParam) {\n this.getAudioNode().connect(input);\n } else {\n this.getAudioNode().connect(input);\n }\n }\n\n unPlug(io: AudioInput | PolyAudioInput, plugOther = true) {\n super.unPlug(io, plugOther);\n if (io instanceof PolyAudioInput) return;\n\n const input = io.getAudioNode();\n\n try {\n if (input instanceof AudioParam) {\n this.getAudioNode().disconnect(input);\n } else {\n this.getAudioNode().disconnect(input);\n }\n } catch {\n // Ignore disconnect errors\n }\n }\n}\n","import { deterministicId } from \"@blibliki/utils\";\nimport { ModuleType } from \"@/modules\";\nimport { Module } from \"../module\";\nimport { PolyModule } from \"../module/PolyModule\";\nimport { AudioInput, AudioOutput } from \"./AudioIO\";\nimport { MidiInput, MidiOutput } from \"./MidiIO\";\nimport { PolyAudioInput, PolyAudioOutput } from \"./PolyAudioIO\";\n\nexport type IOProps = {\n name: string;\n ioType: IOType;\n};\n\nexport type IIOSerialize = IOProps & {\n id: string;\n moduleId: string;\n};\n\nexport enum IOType {\n AudioInput = \"audioInput\",\n AudioOutput = \"audioOutput\",\n PolyAudioInput = \"polyAudioInput\",\n PolyAudioOutput = \"polyAudioOutput\",\n MidiOutput = \"midiOutput\",\n MidiInput = \"midiInput\",\n}\n\nexport type IIO = {\n id: string;\n module: Module<ModuleType> | PolyModule<ModuleType>;\n} & IOProps;\n\nexport abstract class Base implements IIO {\n id: string;\n ioType: IOType;\n name: string;\n module: Module<ModuleType> | PolyModule<ModuleType>;\n connections: Base[];\n\n constructor(\n module: Module<ModuleType> | PolyModule<ModuleType>,\n props: IOProps,\n ) {\n this.module = module;\n this.name = props.name;\n this.ioType = props.ioType;\n this.id = deterministicId(this.module.id, this.name);\n this.connections = [];\n }\n\n plug(io: Base, plugOther = true) {\n this.connections.push(io);\n if (plugOther) io.plug(this, false);\n }\n\n unPlug(io: Base, plugOther = true) {\n this.connections = this.connections.filter(\n (currentIO) => currentIO.id !== io.id,\n );\n if (plugOther) io.unPlug(this, false);\n }\n\n rePlugAll(callback?: () => void) {\n const connections = this.connections;\n this.unPlugAll();\n if (callback) callback();\n\n connections.forEach((otherIO) => {\n this.plug(otherIO);\n });\n }\n\n unPlugAll() {\n this.connections.forEach((otherIO) => {\n this.unPlug(otherIO);\n });\n }\n\n isAudio(): this is\n | AudioInput\n | AudioOutput\n | PolyAudioInput\n | PolyAudioOutput {\n return (\n this.ioType === IOType.AudioInput ||\n this.ioType === IOType.AudioOutput ||\n this.ioType === IOType.PolyAudioInput ||\n this.ioType === IOType.PolyAudioOutput\n );\n }\n\n isMidi(): this is MidiInput | MidiOutput {\n return (\n this.ioType === IOType.MidiInput || this.ioType === IOType.MidiOutput\n );\n }\n\n serialize(): IIOSerialize {\n return {\n id: this.id,\n name: this.name,\n ioType: this.ioType,\n moduleId: this.module.id,\n };\n }\n}\n\nexport default abstract class IO<Connection extends Base> extends Base {\n declare connections: Connection[];\n\n plug(io: Connection, plugOther?: boolean): void {\n super.plug(io, plugOther);\n }\n\n unPlug(io: Connection, plugOther?: boolean): void {\n super.unPlug(io, plugOther);\n }\n}\n","import { ModuleType } from \"@/modules\";\nimport { PolyModule } from \"../module/PolyModule\";\nimport { AudioInput, AudioOutput } from \"./AudioIO\";\nimport IO, { IOProps, IOType } from \"./Base\";\n\nexport type PolyAudioIO = PolyAudioInput | PolyAudioOutput;\n\nexport type PolyAudioInputProps = IOProps & {\n ioType: IOType.PolyAudioInput;\n};\n\nexport type PolyAudioOutputProps = IOProps & {\n ioType: IOType.PolyAudioOutput;\n};\n\nexport class PolyAudioInput\n extends IO<PolyAudioOutput | AudioOutput>\n implements PolyAudioInputProps\n{\n declare ioType: IOType.PolyAudioInput;\n declare module: PolyModule<ModuleType>;\n\n plug(io: PolyAudioOutput | AudioOutput, plugOther = true) {\n super.plug(io, plugOther);\n if (!plugOther && io instanceof PolyAudioOutput) return;\n\n plugOrUnplug(this, io, true);\n }\n\n unPlug(io: PolyAudioOutput | AudioOutput, plugOther = true) {\n super.unPlug(io, plugOther);\n if (!plugOther && io instanceof PolyAudioOutput) return;\n\n plugOrUnplug(this, io, false);\n }\n\n findIOByVoice(voice: number): AudioInput {\n return this.module\n .findVoice(voice)\n .inputs.findByName(this.name) as AudioInput;\n }\n}\n\nexport class PolyAudioOutput\n extends IO<PolyAudioInput | AudioInput>\n implements PolyAudioOutputProps\n{\n declare ioType: IOType.PolyAudioOutput;\n declare module: PolyModule<ModuleType>;\n\n plug(io: PolyAudioInput | AudioInput, plugOther = true) {\n super.plug(io, plugOther);\n if (!plugOther && io instanceof PolyAudioInput) return;\n\n plugOrUnplug(this, io, true);\n }\n\n unPlug(io: PolyAudioInput | AudioInput, plugOther = true) {\n super.unPlug(io, plugOther);\n if (!plugOther && io instanceof PolyAudioInput) return;\n\n plugOrUnplug(this, io, false);\n }\n\n findIOByVoice(voice: number): AudioOutput {\n return this.module\n .findVoice(voice)\n .outputs.findByName(this.name) as AudioOutput;\n }\n}\n\nfunction plugOrUnplug(\n thisIO: PolyAudioInput,\n otherIO: PolyAudioOutput | AudioOutput,\n isPlug: boolean,\n): void;\nfunction plugOrUnplug(\n thisIO: PolyAudioOutput,\n otherIO: PolyAudioInput | AudioInput,\n isPlug: boolean,\n): void;\nfunction plugOrUnplug(\n thisIO: PolyAudioInput | PolyAudioOutput,\n otherIO: PolyAudioOutput | AudioOutput | PolyAudioInput | AudioInput,\n isPlug: boolean,\n) {\n if (otherIO instanceof PolyAudioInput || otherIO instanceof PolyAudioOutput) {\n const maxVoices = Math.max(thisIO.module.voices, otherIO.module.voices);\n\n for (let voice = 0; voice < maxVoices; voice++) {\n const thisMonoIO = thisIO.findIOByVoice(voice % thisIO.module.voices);\n const otherMonoIO = otherIO.findIOByVoice(voice % otherIO.module.voices);\n\n if (isPlug) {\n // @ts-expect-error: temp solution until guard this input plug to output\n thisMonoIO.plug(otherMonoIO);\n } else {\n // @ts-expect-error: temp solution until guard this input plug to output\n thisMonoIO.unPlug(otherMonoIO);\n }\n }\n } else {\n for (let voice = 0; voice < thisIO.module.voices; voice++) {\n const thisMonoIO = thisIO.findIOByVoice(voice);\n\n if (isPlug) {\n // @ts-expect-error: temp solution until guard this input plug to output\n thisMonoIO.plug(otherIO);\n } else {\n // @ts-expect-error: temp solution until guard this input plug to output\n thisMonoIO.unPlug(otherIO);\n }\n }\n }\n}\n","import { ModuleType } from \"@/modules\";\nimport MidiEvent from \"../midi/MidiEvent\";\nimport { Module } from \"../module\";\nimport { PolyModule } from \"../module/PolyModule\";\nimport IO, { IOProps, IOType } from \"./Base\";\n\nexport type MidiIO = MidiInput | MidiOutput;\n\nexport type MidiInputProps = IOProps & {\n ioType: IOType.MidiInput;\n onMidiEvent: (event: MidiEvent) => void;\n};\n\nexport type MidiOutputProps = IOProps & {\n ioType: IOType.MidiOutput;\n};\n\nexport class MidiInput extends IO<MidiOutput> implements MidiInputProps {\n declare ioType: IOType.MidiInput;\n onMidiEvent: MidiInputProps[\"onMidiEvent\"];\n\n constructor(\n module: Module<ModuleType> | PolyModule<ModuleType>,\n props: MidiInputProps,\n ) {\n super(module, props);\n this.onMidiEvent = props.onMidiEvent;\n }\n}\n\nexport class MidiOutput extends IO<MidiInput> implements MidiOutputProps {\n declare ioType: IOType.MidiOutput;\n\n onMidiEvent = (event: MidiEvent) => {\n this.midiConnections.forEach((input) => {\n input.onMidiEvent(event);\n });\n };\n\n private get midiConnections() {\n return this.connections.filter((input) => input instanceof MidiInput);\n }\n}\n","const frequencyTable = new Map<string, number>([\n [\"C0\", 16.35],\n [\"C#0\", 17.32],\n [\"Db0\", 17.32],\n [\"D0\", 18.35],\n [\"D#0\", 19.45],\n [\"Eb0\", 19.45],\n [\"E0\", 20.6],\n [\"F0\", 21.83],\n [\"F#0\", 23.12],\n [\"Gb0\", 23.12],\n [\"G0\", 24.5],\n [\"G#0\", 25.96],\n [\"Ab0\", 25.96],\n [\"A0\", 27.5],\n [\"A#0\", 29.14],\n [\"Bb0\", 29.14],\n [\"B0\", 30.87],\n [\"C1\", 32.7],\n [\"C#1\", 34.65],\n [\"Db1\", 34.65],\n [\"D1\", 36.71],\n [\"D#1\", 38.89],\n [\"Eb1\", 38.89],\n [\"E1\", 41.2],\n [\"F1\", 43.65],\n [\"F#1\", 46.25],\n [\"Gb1\", 46.25],\n [\"G1\", 49.0],\n [\"G#1\", 51.91],\n [\"Ab1\", 51.91],\n [\"A1\", 55.0],\n [\"A#1\", 58.27],\n [\"Bb1\", 58.27],\n [\"B1\", 61.74],\n [\"C2\", 65.41],\n [\"C#2\", 69.3],\n [\"Db2\", 69.3],\n [\"D2\", 73.42],\n [\"D#2\", 77.78],\n [\"Eb2\", 77.78],\n [\"E2\", 82.41],\n [\"F2\", 87.31],\n [\"F#2\", 92.5],\n [\"Gb2\", 92.5],\n [\"G2\", 98.0],\n [\"G#2\", 103.83],\n [\"Ab2\", 103.83],\n [\"A2\", 110.0],\n [\"A#2\", 116.54],\n [\"Bb2\", 116.54],\n [\"B2\", 123.47],\n [\"C3\", 130.81],\n [\"C#3\", 138.59],\n [\"Db3\", 138.59],\n [\"D3\", 146.83],\n [\"D#3\", 155.56],\n [\"Eb3\", 155.56],\n [\"E3\", 164.81],\n [\"F3\", 174.61],\n [\"F#3\", 185.0],\n [\"Gb3\", 185.0],\n [\"G3\", 196.0],\n [\"G#3\", 207.65],\n [\"Ab3\", 207.65],\n [\"A3\", 220.0],\n [\"A#3\", 233.08],\n [\"Bb3\", 233.08],\n [\"B3\", 246.94],\n [\"C4\", 261.63],\n [\"C#4\", 277.18],\n [\"Db4\", 277.18],\n [\"D4\", 293.66],\n [\"D#4\", 311.13],\n [\"Eb4\", 311.13],\n [\"E4\", 329.63],\n [\"F4\", 349.23],\n [\"F#4\", 369.99],\n [\"Gb4\", 369.99],\n [\"G4\", 392.0],\n [\"G#4\", 415.3],\n [\"Ab4\", 415.3],\n [\"A4\", 440.0],\n [\"A#4\", 466.16],\n [\"Bb4\", 466.16],\n [\"B4\", 493.88],\n [\"C5\", 523.25],\n [\"C#5\", 554.37],\n [\"Db5\", 554.37],\n [\"D5\", 587.33],\n [\"D#5\", 622.25],\n [\"Eb5\", 622.25],\n [\"E5\", 659.26],\n [\"F5\", 698.46],\n [\"F#5\", 739.99],\n [\"Gb5\", 739.99],\n [\"G5\", 783.99],\n [\"G#5\", 830.61],\n [\"Ab5\", 830.61],\n [\"A5\", 880.0],\n [\"A#5\", 932.33],\n [\"Bb5\", 932.33],\n [\"B5\", 987.77],\n [\"C6\", 1046.5],\n [\"C#6\", 1108.73],\n [\"Db6\", 1108.73],\n [\"D6\", 1174.66],\n [\"D#6\", 1244.51],\n [\"Eb6\", 1244.51],\n [\"E6\", 1318.51],\n [\"F6\", 1396.91],\n [\"F#6\", 1479.98],\n [\"Gb6\", 1479.98],\n [\"G6\", 1567.98],\n [\"G#6\", 1661.22],\n [\"Ab6\", 1661.22],\n [\"A6\", 1760.0],\n [\"A#6\", 1864.66],\n [\"Bb6\", 1864.66],\n [\"B6\", 1975.53],\n [\"C7\", 2093.0],\n [\"C#7\", 2217.46],\n [\"Db7\", 2217.46],\n [\"D7\", 2349.32],\n [\"D#7\", 2489.02],\n [\"Eb7\", 2489.02],\n [\"E7\", 2637.02],\n [\"F7\", 2793.83],\n [\"F#7\", 2959.96],\n [\"Gb7\", 2959.96],\n [\"G7\", 3135.96],\n [\"G#7\", 3322.44],\n [\"Ab7\", 3322.44],\n [\"A7\", 3520.0],\n [\"A#7\", 3729.31],\n [\"Bb7\", 3729.31],\n [\"B7\", 3951.07],\n [\"C8\", 4186.01],\n [\"C#8\", 4434.92],\n [\"Db8\", 4434.92],\n [\"D8\", 4698.64],\n [\"D#8\", 4978.03],\n [\"Eb8\", 4978.03],\n]);\n\nexport default frequencyTable;\n","import { Seconds } from \"@blibliki/transport\";\nimport Message from \"../midi/Message\";\nimport frequencyTable from \"./frequencyTable\";\n\nconst Notes = [\"C\", \"C#\", \"D\", \"D#\", \"E\", \"F\", \"F#\", \"G\", \"G#\", \"A\", \"A#\", \"B\"];\n\nconst MIDI_OCTAVE_SYTSTEM = 2;\n\nexport type INote = {\n name: string;\n octave: number;\n frequency: number;\n duration?: Seconds;\n velocity?: number;\n};\n\nexport default class Note implements INote {\n static _notes: Note[];\n name!: string;\n octave!: number;\n velocity = 1;\n duration?: Seconds;\n\n static fromFrequency(frequency: number) {\n let noteName: string | undefined;\n\n for (const [note, freq] of frequencyTable) {\n if (freq !== frequency) continue;\n\n noteName = note;\n break;\n }\n\n if (!noteName) throw Error(\"Not matching frequency with a note\");\n\n return new Note(noteName);\n }\n\n static fromEvent(message: Message) {\n const dataByte = message.data[1];\n if (dataByte === undefined) {\n throw new Error(\"Invalid MIDI message: missing data byte\");\n }\n const name = Notes[dataByte % 12];\n if (!name) {\n throw new Error(`Invalid MIDI note number: ${dataByte}`);\n }\n const octave = Math.floor(dataByte / 12) - 2;\n\n return new Note(`${name}${octave}`);\n }\n\n static notes(octave = 3) {\n return Notes.map((note: string) => new Note(`${note}${octave}`));\n }\n\n constructor(note: Omit<INote, \"frequency\"> | string) {\n if (typeof note === \"string\") {\n this.fromString(note);\n } else {\n this.fromProps(note);\n }\n }\n\n get isSemi() {\n return this.name.endsWith(\"#\");\n }\n\n get fullName() {\n return `${this.name}${this.octave}`;\n }\n\n get frequency(): number {\n return frequencyTable.get(`${this.name}${this.octave}`)!;\n }\n\n midiData(noteOn = true): Uint8Array {\n const statusByte = noteOn ? 0x90 : 0x80;\n return new Uint8Array([statusByte, this.midiNumber, this.velocity * 100]);\n }\n\n get midiNumber(): number {\n return (this.octave + MIDI_OCTAVE_SYTSTEM) * 12 + this.noteIndex;\n }\n\n get noteIndex(): number {\n return Notes.indexOf(this.name);\n }\n\n valueOf() {\n return this.fullName;\n }\n\n serialize(): INote {\n return {\n name: this.name,\n octave: this.octave,\n frequency: this.frequency,\n velocity: this.velocity,\n duration: this.duration,\n };\n }\n\n private fromString(string: string) {\n const matches = /(\\w#?)(\\d)?/.exec(string);\n if (!matches) {\n throw new Error(`Invalid note string: ${string}`);\n }\n\n const name = matches[1];\n if (!name) {\n throw new Error(`Invalid note name in: ${string}`);\n }\n\n this.name = name;\n this.octave = matches[2] ? parseInt(matches[2]) : 1;\n }\n\n private fromProps(props: Omit<INote, \"frequency\">) {\n Object.assign(this, props);\n }\n}\n","/**\n * Simple wrapper around MIDI message data (Uint8Array)\n * Replaces the webmidi Message class with native Web MIDI API data\n */\nexport default class Message {\n public readonly data: Uint8Array;\n\n constructor(data: Uint8Array) {\n this.data = data;\n }\n\n /**\n * Returns the data bytes (excluding the status byte)\n */\n get dataBytes(): number[] {\n return Array.from(this.data.slice(1));\n }\n\n /**\n * Returns the MIDI message type based on the status byte\n */\n get type(): string {\n const statusByte = this.data[0];\n if (statusByte === undefined) return \"unknown\";\n const messageType = statusByte & 0xf0;\n\n switch (messageType) {\n case 0x90: // Note On\n // Check if velocity is 0 (which is actually Note Off)\n return this.data[2] === 0 ? \"noteoff\" : \"noteon\";\n case 0x80: // Note Off\n return \"noteoff\";\n case 0xb0: // Control Change\n return \"controlchange\";\n case 0xe0: // Pitch Bend\n return \"pitchbend\";\n case 0xd0: // Channel Pressure (Aftertouch)\n return \"channelaftertouch\";\n case 0xa0: // Polyphonic Key Pressure\n return \"keyaftertouch\";\n case 0xc0: // Program Change\n return \"programchange\";\n default:\n return \"unknown\";\n }\n }\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport Note, { INote } from \"../Note\";\nimport Message from \"./Message\";\n\nexport enum MidiEventType {\n noteOn = \"noteon\",\n noteOff = \"noteoff\",\n cc = \"controlchange\",\n}\n\nexport default class MidiEvent {\n note?: Note;\n voiceNo?: number;\n readonly triggeredAt: ContextTime;\n private message: Message;\n\n static fromNote(\n noteName: string | Note | Omit<INote, \"frequency\">,\n noteOn = true,\n triggeredAt: ContextTime,\n ): MidiEvent {\n const note = noteName instanceof Note ? noteName : new Note(noteName);\n\n return new MidiEvent(new Message(note.midiData(noteOn)), triggeredAt);\n }\n\n static fromCC(\n cc: number,\n value: number,\n triggeredAt: ContextTime,\n ): MidiEvent {\n return new MidiEvent(\n new Message(new Uint8Array([0xb0, cc, value])),\n triggeredAt,\n );\n }\n\n constructor(message: Message, triggeredAt: ContextTime) {\n this.message = message;\n this.triggeredAt = triggeredAt;\n this.defineNotes();\n }\n\n get type() {\n return this.message.type as MidiEventType;\n }\n\n get isNote() {\n return (\n this.type === MidiEventType.noteOn || this.type === MidiEventType.noteOff\n );\n }\n\n get isCC() {\n return this.type === MidiEventType.cc;\n }\n\n get cc(): number | undefined {\n if (!this.isCC) return;\n\n return this.message.dataBytes[0];\n }\n\n get ccValue(): number | undefined {\n if (!this.isCC) return;\n\n return this.message.dataBytes[1];\n }\n\n defineNotes() {\n if (!this.isNote) return;\n if (this.note) return;\n\n this.note = Note.fromEvent(this.message);\n }\n\n get rawMessage() {\n return this.message;\n }\n\n clone(voiceNo?: number) {\n const newEvent = new MidiEvent(this.message, this.triggeredAt);\n newEvent.voiceNo = voiceNo;\n\n return newEvent;\n }\n}\n","import { Optional, uuidv4 } from \"@blibliki/utils\";\nimport { Engine } from \"@/Engine\";\n\ntype IPlug = {\n moduleId: string;\n ioName: string;\n};\n\nexport type IRoute = {\n id: string;\n source: IPlug;\n destination: IPlug;\n};\n\nexport class Routes {\n engine: Engine;\n routes: Map<string, IRoute>;\n\n constructor(engine: Engine) {\n this.engine = engine;\n this.routes = new Map();\n }\n\n addRoute(props: Optional<IRoute, \"id\">): IRoute {\n const id = props.id ?? uuidv4();\n const route = { ...props, id };\n this.routes.set(id, route);\n\n this.plug(id);\n\n return route;\n }\n\n removeRoute(id: string) {\n this.unPlug(id);\n this.routes.delete(id);\n }\n\n clear() {\n this.routes.forEach((_, id) => {\n this.removeRoute(id);\n });\n }\n\n replug() {\n this.routes.forEach((_, id) => {\n const { sourceIO, destinationIO } = this.getIOs(id);\n sourceIO.rePlugAll();\n destinationIO.rePlugAll();\n });\n }\n\n serialize(): IRoute[] {\n return Array.from(this.routes.values());\n }\n\n private plug(id: string) {\n const { sourceIO, destinationIO } = this.getIOs(id);\n sourceIO.plug(destinationIO);\n }\n\n private unPlug(id: string) {\n const { sourceIO, destinationIO } = this.getIOs(id);\n sourceIO.unPlug(destinationIO);\n }\n\n private find(id: string): IRoute {\n const route = this.routes.get(id);\n if (!route) throw Error(`Route with id ${id} not found`);\n\n return route;\n }\n\n private getIOs(id: string) {\n const route = this.find(id);\n const { source, destination } = route;\n\n const sourceIO = this.engine.findIO(\n source.moduleId,\n source.ioName,\n \"output\",\n );\n const destinationIO = this.engine.findIO(\n destination.moduleId,\n destination.ioName,\n \"input\",\n );\n\n return { sourceIO, destinationIO };\n }\n}\n","import { Context } from \"@blibliki/utils\";\nimport Message from \"./Message\";\nimport MidiEvent, { MidiEventType } from \"./MidiEvent\";\nimport type { IMidiInputPort, IMidiMessageEvent } from \"./adapters\";\n\nexport enum MidiPortState {\n connected = \"connected\",\n disconnected = \"disconnected\",\n}\n\nexport type IMidiDevice = {\n id: string;\n name: string;\n state: MidiPortState;\n};\n\nexport type IMidiInput = IMidiDevice & {\n eventListerCallbacks: EventListerCallback[];\n};\n\nexport type EventListerCallback = (event: MidiEvent) => void;\n\nexport default class MidiDevice implements IMidiDevice {\n id: string;\n name: string;\n eventListerCallbacks: EventListerCallback[] = [];\n\n private context: Readonly<Context>;\n private input: IMidiInputPort;\n private messageHandler: ((event: IMidiMessageEvent) => void) | null = null;\n\n constructor(input: IMidiInputPort, context: Context) {\n this.id = input.id;\n this.name = input.name;\n this.input = input;\n this.context = context;\n\n this.connect();\n }\n\n get state() {\n return this.input.state as MidiPortState;\n }\n\n connect() {\n this.messageHandler = (e: IMidiMessageEvent) => {\n this.processEvent(e);\n };\n this.input.addEventListener(this.messageHandler);\n }\n\n disconnect() {\n if (this.messageHandler) {\n this.input.removeEventListener(this.messageHandler);\n this.messageHandler = null;\n }\n }\n\n serialize() {\n const { id, name, state } = this;\n\n return { id, name, state };\n }\n\n addEventListener(callback: EventListerCallback) {\n this.eventListerCallbacks.push(callback);\n }\n\n removeEventListener(callback: EventListerCallback) {\n this.eventListerCallbacks = this.eventListerCallbacks.filter(\n (c) => c !== callback,\n );\n }\n\n private processEvent(event: IMidiMessageEvent) {\n const message = new Message(event.data);\n const midiEvent = new MidiEvent(\n message,\n this.context.browserToContextTime(event.timeStamp),\n );\n\n switch (midiEvent.type) {\n case MidiEventType.noteOn:\n case MidiEventType.noteOff:\n case MidiEventType.cc:\n this.eventListerCallbacks.forEach((callback) => {\n callback(midiEvent);\n });\n }\n }\n}\n","import { Context } from \"@blibliki/utils\";\nimport Note from \"../Note\";\nimport { EventListerCallback, IMidiInput, MidiPortState } from \"./MidiDevice\";\nimport MidiEvent from \"./MidiEvent\";\n\nconst MAP_KEYS: Record<string, Note> = {\n a: new Note(\"C3\"),\n s: new Note(\"D3\"),\n d: new Note(\"E3\"),\n f: new Note(\"F3\"),\n g: new Note(\"G3\"),\n h: new Note(\"A3\"),\n j: new Note(\"B3\"),\n k: new Note(\"C4\"),\n l: new Note(\"D4\"),\n w: new Note(\"C#3\"),\n e: new Note(\"D#3\"),\n t: new Note(\"F#3\"),\n y: new Note(\"G#3\"),\n u: new Note(\"A#3\"),\n o: new Note(\"C#4\"),\n p: new Note(\"D#4\"),\n};\n\nconst computerKeyboardData = () => ({\n id: \"computer_keyboard\",\n name: \"Computer Keyboard\",\n state: MidiPortState.connected,\n});\n\nexport default class ComputerKeyboardInput implements IMidiInput {\n id: string;\n name: string;\n state: MidiPortState;\n eventListerCallbacks: EventListerCallback[] = [];\n private context: Readonly<Context>;\n\n constructor(context: Context) {\n const { id, name, state } = computerKeyboardData();\n this.id = id;\n this.name = name;\n this.state = state;\n this.context = context;\n\n document.addEventListener(\"keydown\", this.onKeyTrigger(true));\n document.addEventListener(\"keyup\", this.onKeyTrigger(false));\n }\n\n addEventListener(callback: EventListerCallback) {\n this.eventListerCallbacks.push(callback);\n }\n\n removeEventListener(callback: EventListerCallback) {\n this.eventListerCallbacks = this.eventListerCallbacks.filter(\n (c) => c !== callback,\n );\n }\n\n serialize() {\n const { id, name, state } = this;\n\n return { id, name, state };\n }\n\n onKeyTrigger = (noteOn: boolean) => (event: KeyboardEvent) => {\n const note = this.extractNote(event);\n if (!note) return;\n\n const midiEvent = MidiEvent.fromNote(\n note,\n noteOn,\n this.context.browserToContextTime(event.timeStamp),\n );\n this.eventListerCallbacks.forEach((callback) => {\n callback(midiEvent);\n });\n };\n\n private extractNote(event: KeyboardEvent): Note | undefined {\n if (event.repeat) return;\n\n return MAP_KEYS[event.key];\n }\n}\n","/**\n * MIDI adapter factory\n * Automatically selects the correct MIDI implementation based on the platform\n */\nimport { isNode } from \"es-toolkit\";\nimport NodeMidiAdapter from \"./NodeMidiAdapter\";\nimport WebMidiAdapter from \"./WebMidiAdapter\";\nimport type { IMidiAdapter } from \"./types\";\n\nexport * from \"./types\";\n\n/**\n * Creates the appropriate MIDI adapter for the current platform\n * @returns The MIDI adapter (Web MIDI API for browsers, node-midi for Node.js)\n */\nexport function createMidiAdapter(): IMidiAdapter {\n if (isNode()) {\n return new NodeMidiAdapter();\n }\n\n // Default to Web MIDI API for browsers\n return new WebMidiAdapter();\n}\n","/**\n * node-midi adapter for Node.js\n */\nimport { isNode } from \"es-toolkit\";\nimport type {\n IMidiAccess,\n IMidiAdapter,\n IMidiInputPort,\n MidiMessageCallback,\n} from \"./types\";\n\n// Dynamic import type for node-midi\ntype NodeMidiInput = {\n getPortCount(): number;\n getPortName(port: number): string;\n openPort(port: number): void;\n closePort(): void;\n on(\n event: \"message\",\n callback: (deltaTime: number, message: number[]) => void,\n ): void;\n off(\n event: \"message\",\n callback: (deltaTime: number, message: number[]) => void,\n ): void;\n isPortOpen(): boolean;\n};\n\ntype NodeMidiModule = {\n Input: new () => NodeMidiInput;\n};\n\nclass NodeMidiInputPort implements IMidiInputPort {\n readonly id: string;\n readonly name: string;\n private portIndex: number;\n private input: NodeMidiInput;\n private callbacks = new Set<MidiMessageCallback>();\n private handler: ((deltaTime: number, message: number[]) => void) | null =\n null;\n private _state: \"connected\" | \"disconnected\" = \"disconnected\";\n\n constructor(portIndex: number, name: string, input: NodeMidiInput) {\n this.portIndex = portIndex;\n this.id = `node-midi-${portIndex}`;\n this.name = name;\n this.input = input;\n }\n\n get state(): \"connected\" | \"disconnected\" {\n return this._state;\n }\n\n setState(state: \"connected\" | \"disconnected\"): void {\n this._state = state;\n }\n\n addEventListener(callback: MidiMessageCallback): void {\n if (this.callbacks.size === 0) {\n this.handler = (_deltaTime: number, message: number[]) => {\n const event = {\n data: new Uint8Array(message),\n timeStamp: performance.now(),\n };\n\n this.callbacks.forEach((cb) => {\n cb(event);\n });\n };\n\n try {\n if (!this.input.isPortOpen()) {\n this.input.openPort(this.portIndex);\n this._state = \"connected\";\n }\n this.input.on(\"message\", this.handler);\n } catch (err) {\n console.error(`Error opening MIDI port ${this.portIndex}:`, err);\n }\n }\n this.callbacks.add(callback);\n }\n\n removeEventListener(callback: MidiMessageCallback): void {\n this.callbacks.delete(callback);\n\n if (this.callbacks.size === 0 && this.handler) {\n try {\n this.input.off(\"message\", this.handler);\n if (this.input.isPortOpen()) {\n this.input.closePort();\n this._state = \"disconnected\";\n }\n } catch (err) {\n console.error(`Error closing MIDI port ${this.portIndex}:`, err);\n }\n this.handler = null;\n }\n }\n}\n\nclass NodeMidiAccess implements IMidiAccess {\n private ports = new Map<string, NodeMidiInputPort>();\n private MidiModule: NodeMidiModule;\n\n constructor(MidiModule: NodeMidiModule) {\n this.MidiModule = MidiModule;\n this.scanPorts();\n }\n\n private scanPorts(): void {\n try {\n const input = new this.MidiModule.Input();\n const portCount = input.getPortCount();\n\n for (let i = 0; i < portCount; i++) {\n const portName = input.getPortName(i);\n const id = `node-midi-${i}`;\n\n if (!this.ports.has(id)) {\n // Create a new input instance for each port\n const portInput = new this.MidiModule.Input();\n const port = new NodeMidiInputPort(i, portName, portInput);\n this.ports.set(id, port);\n }\n }\n\n // Clean up the scanning input\n if (input.isPortOpen()) {\n input.closePort();\n }\n } catch (err) {\n console.error(\"Error scanning MIDI ports:\", err);\n }\n }\n\n *inputs(): IterableIterator<IMidiInputPort> {\n for (const [, port] of this.ports) {\n yield port;\n }\n }\n\n addEventListener(\n _event: \"statechange\",\n _callback: (port: IMidiInputPort) => void,\n ): void {\n // node-midi doesn't support hot-plugging detection\n // This could be implemented with polling if needed\n console.warn(\n \"Hot-plug detection not supported with node-midi adapter. Restart required for new devices.\",\n );\n }\n}\n\nexport default class NodeMidiAdapter implements IMidiAdapter {\n async requestMIDIAccess(): Promise<IMidiAccess | null> {\n try {\n // Dynamic import to avoid bundling in browser builds\n const midi = (await import(\"@julusian/midi\")) as\n | NodeMidiModule\n | { default: NodeMidiModule };\n const midiModule = \"default\" in midi ? midi.default : midi;\n return new NodeMidiAccess(midiModule);\n } catch (err) {\n console.error(\"Error loading node-midi:\", err);\n return null;\n }\n }\n\n isSupported(): boolean {\n // Check if we're in Node.js environment\n return isNode();\n }\n}\n","/**\n * Web MIDI API adapter for browsers\n */\nimport type {\n IMidiAccess,\n IMidiAdapter,\n IMidiInputPort,\n MidiMessageCallback,\n} from \"./types\";\n\nclass WebMidiInputPort implements IMidiInputPort {\n private input: MIDIInput;\n private callbacks = new Set<MidiMessageCallback>();\n private handler: ((e: MIDIMessageEvent) => void) | null = null;\n\n constructor(input: MIDIInput) {\n this.input = input;\n }\n\n get id(): string {\n return this.input.id;\n }\n\n get name(): string {\n return this.input.name ?? `Device ${this.input.id}`;\n }\n\n get state(): \"connected\" | \"disconnected\" {\n return this.input.state as \"connected\" | \"disconnected\";\n }\n\n addEventListener(callback: MidiMessageCallback): void {\n if (this.callbacks.size === 0) {\n this.handler = (e: MIDIMessageEvent) => {\n if (!e.data) return;\n\n const event = {\n data: e.data,\n timeStamp: e.timeStamp,\n };\n\n this.callbacks.forEach((cb) => {\n cb(event);\n });\n };\n this.input.addEventListener(\"midimessage\", this.handler);\n }\n this.callbacks.add(callback);\n }\n\n removeEventListener(callback: MidiMessageCallback): void {\n this.callbacks.delete(callback);\n\n if (this.callbacks.size === 0 && this.handler) {\n this.input.removeEventListener(\"midimessage\", this.handler);\n this.handler = null;\n }\n }\n}\n\nclass WebMidiAccess implements IMidiAccess {\n private midiAccess: MIDIAccess;\n private portCache = new Map<string, WebMidiInputPort>();\n\n constructor(midiAccess: MIDIAccess) {\n this.midiAccess = midiAccess;\n }\n\n *inputs(): IterableIterator<IMidiInputPort> {\n for (const [, input] of this.midiAccess.inputs) {\n if (!this.portCache.has(input.id)) {\n this.portCache.set(input.id, new WebMidiInputPort(input));\n }\n yield this.portCache.get(input.id)!;\n }\n }\n\n addEventListener(\n event: \"statechange\",\n callback: (port: IMidiInputPort) => void,\n ): void {\n this.midiAccess.addEventListener(event, (e) => {\n const port = e.port;\n if (port?.type !== \"input\") return;\n\n const input = port as MIDIInput;\n if (!this.portCache.has(input.id)) {\n this.portCache.set(input.id, new WebMidiInputPort(input));\n }\n\n callback(this.portCache.get(input.id)!);\n });\n }\n}\n\nexport default class WebMidiAdapter implements IMidiAdapter {\n async requestMIDIAccess(): Promise<IMidiAccess | null> {\n try {\n if (\n typeof navigator === \"undefined\" ||\n typeof navigator.requestMIDIAccess !== \"function\"\n ) {\n return null;\n }\n\n const midiAccess = await navigator.requestMIDIAccess();\n return new WebMidiAccess(midiAccess);\n } catch (err) {\n console.error(\"Error enabling Web MIDI API:\", err);\n return null;\n }\n }\n\n isSupported(): boolean {\n return (\n typeof navigator !== \"undefined\" &&\n typeof navigator.requestMIDIAccess === \"function\"\n );\n }\n}\n","/**\n * Utilities for fuzzy matching MIDI device names across different platforms\n *\n * MIDI devices can have different names in browser vs Node.js:\n * - Browser: \"Launchkey Mini MK3 MIDI 1\"\n * - Node.js: \"Launchkey Mini MK3:Launchkey Mini MK3 MIDI 1 20:0\"\n *\n * This module provides fuzzy matching to find the same physical device\n * across platforms based on name similarity.\n */\n\n/**\n * Normalizes a MIDI device name by:\n * - Converting to lowercase\n * - Removing common suffixes/prefixes\n * - Removing port numbers and ALSA identifiers\n * - Removing extra whitespace\n * - Removing special characters\n */\nexport function normalizeDeviceName(name: string): string {\n let normalized = name.toLowerCase();\n\n // First, remove ALSA port numbers (e.g., \"20:0\" at the very end)\n // Do this BEFORE splitting by colons\n normalized = normalized.replace(/\\s+\\d+:\\d+\\s*$/g, \"\");\n\n // Remove colon-separated duplicates (Node.js format: \"Device:Device Port\")\n const parts = normalized.split(\":\");\n if (parts.length > 1) {\n // Take the longest part as it usually has more info\n normalized = parts.reduce((longest, current) =>\n current.length > longest.length ? current : longest,\n );\n }\n\n // Remove common port descriptors (but keep the number if it's part of the device name)\n // This regex only matches MIDI/Input/Output/Port at the END of the string\n normalized = normalized.replace(\n /\\s+(midi|input|output|port)(\\s+\\d+)?$/gi,\n \"\",\n );\n\n // Remove \"device\" prefix if present at the start\n normalized = normalized.replace(/^device\\s+/gi, \"\");\n\n // Remove multiple spaces\n normalized = normalized.replace(/\\s+/g, \" \").trim();\n\n return normalized;\n}\n\n/**\n * Extracts core device name tokens for matching\n * Removes generic words and focuses on manufacturer/model identifiers\n */\nexport function extractCoreTokens(name: string): string[] {\n const normalized = normalizeDeviceName(name);\n\n // Split into tokens\n const tokens = normalized.split(/[\\s\\-_:]+/);\n\n // Filter out very short tokens and common generic words\n const genericWords = new Set([\n \"midi\",\n \"input\",\n \"output\",\n \"port\",\n \"device\",\n \"in\",\n \"out\",\n ]);\n\n return tokens.filter((token) => token.length > 1 && !genericWords.has(token));\n}\n\n/**\n * Calculates Levenshtein distance between two strings\n * Used for fuzzy string matching\n */\nfunction levenshteinDistance(str1: string, str2: string): number {\n const len1 = str1.length;\n const len2 = str2.length;\n const matrix: number[][] = [];\n\n // Initialize matrix\n for (let i = 0; i <= len1; i++) {\n matrix[i] = [i];\n }\n for (let j = 0; j <= len2; j++) {\n if (matrix[0]) {\n matrix[0][j] = j;\n }\n }\n\n // Fill matrix\n for (let i = 1; i <= len1; i++) {\n for (let j = 1; j <= len2; j++) {\n const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;\n const prevRow = matrix[i - 1];\n const currRow = matrix[i];\n const prevCell = currRow?.[j - 1];\n const diagCell = prevRow?.[j - 1];\n\n const prevCellInRow = prevRow?.[j];\n if (\n currRow &&\n prevCellInRow !== undefined &&\n prevCell !== undefined &&\n diagCell !== undefined\n ) {\n currRow[j] = Math.min(\n prevCellInRow + 1, // deletion\n prevCell + 1, // insertion\n diagCell + cost, // substitution\n );\n }\n }\n }\n\n const lastRow = matrix[len1];\n return lastRow?.[len2] ?? 0;\n}\n\n/**\n * Calculates similarity score between two device names\n * Returns a score between 0 (no match) and 1 (perfect match)\n *\n * Uses multiple strategies:\n * 1. Exact normalized match (score: 1.0)\n * 2. Token overlap (Jaccard similarity)\n * 3. String similarity (based on Levenshtein distance)\n * 4. Substring matching\n */\nexport function calculateSimilarity(name1: string, name2: string): number {\n const normalized1 = normalizeDeviceName(name1);\n const normalized2 = normalizeDeviceName(name2);\n\n // Exact match after normalization\n if (normalized1 === normalized2) {\n return 1.0;\n }\n\n const tokens1 = new Set(extractCoreTokens(name1));\n const tokens2 = new Set(extractCoreTokens(name2));\n\n // If no tokens extracted, fall back to pure string similarity\n if (tokens1.size === 0 || tokens2.size === 0) {\n const maxLen = Math.max(normalized1.length, normalized2.length);\n if (maxLen === 0) return 0;\n const distance = levenshteinDistance(normalized1, normalized2);\n return 1 - distance / maxLen;\n }\n\n // Calculate Jaccard similarity for tokens\n const intersection = new Set([...tokens1].filter((x) => tokens2.has(x)));\n const union = new Set([...tokens1, ...tokens2]);\n const jaccardScore = intersection.size / union.size;\n\n // Calculate string similarity\n const maxLen = Math.max(normalized1.length, normalized2.length);\n const distance = levenshteinDistance(normalized1, normalized2);\n const stringScore = 1 - distance / maxLen;\n\n // Check for substring matches\n const substringScore =\n normalized1.includes(normalized2) || normalized2.includes(normalized1)\n ? 0.8\n : 0;\n\n // Weighted combination of scores\n // Token overlap is most important, then string similarity, then substring\n const finalScore =\n jaccardScore * 0.5 + stringScore * 0.3 + substringScore * 0.2;\n\n return finalScore;\n}\n\n/**\n * Finds the best matching device name from a list of candidates\n * Returns the best match and its confidence score\n *\n * @param targetName - The name to match against\n * @param candidateNames - List of possible matches\n * @param threshold - Minimum similarity score to consider a match (default: 0.6)\n * @returns Best match and score, or null if no match above threshold\n */\nexport function findBestMatch(\n targetName: string,\n candidateNames: string[],\n threshold = 0.6,\n): { name: string; score: number } | null {\n let bestMatch: { name: string; score: number } | null = null;\n\n for (const candidateName of candidateNames) {\n const score = calculateSimilarity(targetName, candidateName);\n\n if (score >= threshold && (!bestMatch || score > bestMatch.score)) {\n bestMatch = { name: candidateName, score };\n }\n }\n\n return bestMatch;\n}\n","import { Context } from \"@blibliki/utils\";\nimport ComputerKeyboardDevice from \"./ComputerKeyboardDevice\";\nimport MidiDevice from \"./MidiDevice\";\nimport { createMidiAdapter, type IMidiAccess } from \"./adapters\";\nimport { findBestMatch } from \"./deviceMatcher\";\n\ntype ListenerCallback = (device: MidiDevice) => void;\n\nexport default class MidiDeviceManager {\n devices = new Map<string, MidiDevice | ComputerKeyboardDevice>();\n private initialized = false;\n private listeners: ListenerCallback[] = [];\n private context: Readonly<Context>;\n private midiAccess: IMidiAccess | null = null;\n private adapter = createMidiAdapter();\n\n constructor(context: Context) {\n this.context = context;\n this.addComputerKeyboard();\n }\n\n async initialize() {\n await this.initializeDevices();\n\n this.listenChanges();\n this.initialized = true;\n }\n\n find(id: string): MidiDevice | ComputerKeyboardDevice | undefined {\n return this.devices.get(id);\n }\n\n findByName(name: string): MidiDevice | ComputerKeyboardDevice | undefined {\n return Array.from(this.devices.values()).find((d) => d.name === name);\n }\n\n /**\n * Finds a device using fuzzy name matching\n * Useful for matching devices across browser/Node.js environments where names differ\n *\n * @param targetName - The device name to match\n * @param threshold - Minimum similarity score (0-1, default: 0.6)\n * @returns The best matching device and confidence score, or null\n */\n findByFuzzyName(\n targetName: string,\n threshold = 0.6,\n ): { device: MidiDevice | ComputerKeyboardDevice; score: number } | null {\n const deviceEntries = Array.from(this.devices.values());\n const candidateNames = deviceEntries.map((d) => d.name);\n\n const match = findBestMatch(targetName, candidateNames, threshold);\n\n if (!match) return null;\n\n const device = deviceEntries.find((d) => d.name === match.name);\n\n return device ? { device, score: match.score } : null;\n }\n\n addListener(callback: ListenerCallback) {\n this.listeners.push(callback);\n }\n\n private async initializeDevices() {\n if (this.initialized) return;\n\n try {\n if (!this.adapter.isSupported()) {\n console.warn(\"MIDI is not supported on this platform\");\n return;\n }\n\n this.midiAccess = await this.adapter.requestMIDIAccess();\n\n if (!this.midiAccess) {\n console.error(\"Failed to get MIDI access\");\n return;\n }\n\n for (const input of this.midiAccess.inputs()) {\n if (!this.devices.has(input.id)) {\n this.devices.set(input.id, new MidiDevice(input, this.context));\n }\n }\n } catch (err) {\n console.error(\"Error enabling MIDI:\", err);\n }\n }\n\n private addComputerKeyboard() {\n if (typeof document === \"undefined\") return;\n\n const computerKeyboardDevice = new ComputerKeyboardDevice(this.context);\n this.devices.set(computerKeyboardDevice.id, computerKeyboardDevice);\n }\n\n private listenChanges() {\n if (!this.midiAccess) return;\n\n this.midiAccess.addEventListener(\"statechange\", (port) => {\n if (port.state === \"connected\") {\n // Device connected\n if (this.devices.has(port.id)) return;\n\n const device = new MidiDevice(port, this.context);\n this.devices.set(device.id, device);\n\n this.listeners.forEach((listener) => {\n listener(device);\n });\n } else {\n // Device disconnected\n const device = this.devices.get(port.id);\n if (!device) return;\n if (device instanceof ComputerKeyboardDevice) return;\n\n device.disconnect();\n this.devices.delete(device.id);\n\n this.listeners.forEach((listener) => {\n listener(device);\n });\n }\n });\n }\n}\n","import { assertNever } from \"@blibliki/utils\";\nimport { IModule, Module } from \"@/core\";\nimport { IPolyModuleConstructor } from \"@/core/module/PolyModule\";\nimport VoiceScheduler, {\n IVoiceSchedulerProps,\n voiceSchedulerPropSchema,\n} from \"@/core/module/VoiceScheduler\";\nimport Constant, { constantPropSchema, IConstantProps } from \"./Constant\";\nimport Envelope, { envelopePropSchema, IEnvelopeProps } from \"./Envelope\";\nimport Filter, { filterPropSchema, IFilterProps } from \"./Filter\";\nimport Gain, { gainPropSchema, IGainProps } from \"./Gain\";\nimport Inspector, { IInspectorProps, inspectorPropSchema } from \"./Inspector\";\nimport Master, { IMasterProps, masterPropSchema } from \"./Master\";\nimport MidiMapper, {\n IMidiMapperProps,\n midiMapperPropSchema,\n} from \"./MidiMapper\";\nimport MidiSelector, {\n IMidiSelectorProps,\n midiSelectorPropSchema,\n} from \"./MidiSelector\";\nimport Oscillator, {\n IOscillatorProps,\n oscillatorPropSchema,\n} from \"./Oscillator\";\nimport Scale, { IScaleProps, scalePropSchema } from \"./Scale\";\nimport StepSequencer, {\n IStepSequencerProps,\n stepSequencerPropSchema,\n} from \"./StepSequencer\";\nimport StereoPanner, {\n IStereoPannerProps,\n stereoPannerPropSchema,\n} from \"./StereoPanner\";\nimport VirtualMidi, {\n IVirtualMidiProps,\n virtualMidiPropSchema,\n} from \"./VirtualMidi\";\n\nexport enum ModuleType {\n Master = \"Master\",\n Oscillator = \"Oscillator\",\n Gain = \"Gain\",\n MidiSelector = \"MidiSelector\",\n Envelope = \"Envelope\",\n Filter = \"Filter\",\n Scale = \"Scale\",\n StereoPanner = \"StereoPanner\",\n Inspector = \"Inspector\",\n Constant = \"Constant\",\n MidiMapper = \"MidiMapper\",\n VirtualMidi = \"VirtualMidi\",\n StepSequencer = \"StepSequencer\",\n VoiceScheduler = \"VoiceScheduler\",\n}\n\nexport type ModuleTypeToPropsMapping = {\n [ModuleType.Oscillator]: IOscillatorProps;\n [ModuleType.Gain]: IGainProps;\n [ModuleType.Master]: IMasterProps;\n [ModuleType.MidiSelector]: IMidiSelectorProps;\n [ModuleType.Envelope]: IEnvelopeProps;\n [ModuleType.Filter]: IFilterProps;\n [ModuleType.Scale]: IScaleProps;\n [ModuleType.StereoPanner]: IStereoPannerProps;\n [ModuleType.Inspector]: IInspectorProps;\n [ModuleType.Constant]: IConstantProps;\n [ModuleType.MidiMapper]: IMidiMapperProps;\n [ModuleType.VirtualMidi]: IVirtualMidiProps;\n [ModuleType.StepSequencer]: IStepSequencerProps;\n [ModuleType.VoiceScheduler]: IVoiceSchedulerProps;\n};\n\nexport type ModuleTypeToModuleMapping = {\n [ModuleType.Oscillator]: Oscillator;\n [ModuleType.Gain]: Gain;\n [ModuleType.Master]: Master;\n [ModuleType.MidiSelector]: MidiSelector;\n [ModuleType.Envelope]: Envelope;\n [ModuleType.Filter]: Filter;\n [ModuleType.Scale]: Scale;\n [ModuleType.StereoPanner]: StereoPanner;\n [ModuleType.Inspector]: Inspector;\n [ModuleType.Constant]: Constant;\n [ModuleType.MidiMapper]: MidiMapper;\n [ModuleType.VirtualMidi]: VirtualMidi;\n [ModuleType.StepSequencer]: StepSequencer;\n [ModuleType.VoiceScheduler]: VoiceScheduler;\n};\n\nexport const moduleSchemas = {\n [ModuleType.Oscillator]: oscillatorPropSchema,\n [ModuleType.Gain]: gainPropSchema,\n [ModuleType.Master]: masterPropSchema,\n [ModuleType.MidiSelector]: midiSelectorPropSchema,\n [ModuleType.Envelope]: envelopePropSchema,\n [ModuleType.Filter]: filterPropSchema,\n [ModuleType.Scale]: scalePropSchema,\n [ModuleType.StereoPanner]: stereoPannerPropSchema,\n [ModuleType.Inspector]: inspectorPropSchema,\n [ModuleType.Constant]: constantPropSchema,\n [ModuleType.MidiMapper]: midiMapperPropSchema,\n [ModuleType.VirtualMidi]: virtualMidiPropSchema,\n [ModuleType.StepSequencer]: stepSequencerPropSchema,\n [ModuleType.VoiceScheduler]: voiceSchedulerPropSchema,\n};\n\nexport type { IOscillator } from \"./Oscillator\";\nexport { OscillatorWave } from \"./Oscillator\";\nexport type { IGain } from \"./Gain\";\nexport type { IMaster } from \"./Master\";\nexport type { IMidiSelector } from \"./MidiSelector\";\nexport type { IStereoPanner } from \"./StereoPanner\";\nexport type {\n IStepSequencer,\n IStepSequencerProps,\n ISequence,\n} from \"./StepSequencer\";\nexport type { IMidiMapper, IMidiMapperProps, MidiMapping } from \"./MidiMapper\";\nexport { MidiMappingMode } from \"./MidiMapper\";\n\nexport type AnyModule = Module<ModuleType>;\nexport type IAnyModule = IModule<ModuleType>;\n\nexport type ICreateModule<T extends ModuleType> = {\n id?: string;\n name: string;\n moduleType: T;\n props: Partial<ModuleTypeToPropsMapping[T]>;\n};\n\nexport type ModuleParams = {\n [K in ModuleType]: K extends\n | ModuleType.Oscillator\n | ModuleType.Gain\n | ModuleType.Envelope\n | ModuleType.Filter\n | ModuleType.StereoPanner\n | ModuleType.VoiceScheduler\n ? IPolyModuleConstructor<K>\n : ICreateModule<K>;\n}[ModuleType];\n\nexport function createModule(\n engineId: string,\n params: ModuleParams,\n): ModuleTypeToModuleMapping[keyof ModuleTypeToModuleMapping] {\n switch (params.moduleType) {\n case ModuleType.Oscillator:\n return new Oscillator(engineId, params);\n case ModuleType.Gain:\n return new Gain(engineId, params);\n case ModuleType.Master:\n return new Master(engineId, params);\n case ModuleType.MidiSelector:\n return new MidiSelector(engineId, params);\n case ModuleType.Envelope:\n return new Envelope(engineId, params);\n case ModuleType.Filter:\n return new Filter(engineId, params);\n case ModuleType.Scale:\n return new Scale(engineId, params);\n case ModuleType.StereoPanner:\n return new StereoPanner(engineId, params);\n case ModuleType.Inspector:\n return new Inspector(engineId, params);\n case ModuleType.Constant:\n return new Constant(engineId, params);\n case ModuleType.MidiMapper:\n return new MidiMapper(engineId, params);\n case ModuleType.VirtualMidi:\n return new VirtualMidi(engineId, params);\n case ModuleType.StepSequencer:\n return new StepSequencer(engineId, params);\n case ModuleType.VoiceScheduler:\n return new VoiceScheduler(engineId, params);\n default:\n assertNever(params);\n }\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport { EmptyObject } from \"@blibliki/utils\";\nimport { ICreateModule, ModuleType } from \"@/modules\";\nimport { MidiOutput } from \"../IO\";\nimport MidiEvent, { MidiEventType } from \"../midi/MidiEvent\";\nimport { ModulePropSchema } from \"../schema\";\nimport { IModuleConstructor, Module } from \"./Module\";\nimport { IPolyModuleConstructor, PolyModule } from \"./PolyModule\";\n\nexport type IVoiceSchedulerProps = EmptyObject;\nexport const voiceSchedulerPropSchema: ModulePropSchema<IVoiceSchedulerProps> =\n {};\nconst DEFAULT_PROPS = {};\n\nclass Voice extends Module<ModuleType.VoiceScheduler> {\n declare audioNode: undefined;\n activeNote: string | null = null;\n triggeredAt: ContextTime = 0;\n\n constructor(\n engineId: string,\n params: ICreateModule<ModuleType.VoiceScheduler>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n\n super(engineId, {\n ...params,\n props,\n });\n }\n\n midiTriggered = (midiEvent: MidiEvent) => {\n const { triggeredAt, note, type } = midiEvent;\n\n if (!note) return;\n const noteName = note.fullName;\n\n switch (type) {\n case MidiEventType.noteOn:\n this.activeNote = noteName;\n this.triggeredAt = triggeredAt;\n\n break;\n case MidiEventType.noteOff:\n this.activeNote = null;\n break;\n default:\n throw Error(\"This type is not a note\");\n }\n };\n}\n\nexport default class VoiceScheduler extends PolyModule<ModuleType.VoiceScheduler> {\n declare audioModules: Voice[];\n midiOutput!: MidiOutput;\n\n constructor(\n engineId: string,\n params: IPolyModuleConstructor<ModuleType.VoiceScheduler>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const monoModuleConstructor = (\n engineId: string,\n params: IModuleConstructor<ModuleType.VoiceScheduler>,\n ) => new Voice(engineId, params);\n\n super(engineId, {\n ...params,\n props,\n monoModuleConstructor,\n });\n\n this.registerInputs();\n this.registerOutputs();\n }\n\n onMidiEvent = (midiEvent: MidiEvent) => {\n let voice: Voice | undefined;\n\n switch (midiEvent.type) {\n case MidiEventType.noteOn:\n voice = this.findFreeVoice();\n\n break;\n case MidiEventType.noteOff:\n voice = this.audioModules.find(\n (v) => v.activeNote === midiEvent.note!.fullName,\n );\n break;\n default:\n throw Error(\"This type is not a note\");\n }\n\n if (!voice) return;\n\n voice.midiTriggered(midiEvent);\n midiEvent.voiceNo = voice.voiceNo;\n this.midiOutput.onMidiEvent(midiEvent);\n };\n\n private findFreeVoice(): Voice {\n let voice = this.audioModules.find((v) => !v.activeNote);\n\n // If no available voice, get the one with the lowest triggeredAt\n if (!voice) {\n const sorted = this.audioModules.sort((a, b) => {\n return a.triggeredAt - b.triggeredAt;\n });\n voice = sorted[0];\n if (!voice) {\n throw new Error(\"No voices available in voice scheduler\");\n }\n }\n\n return voice;\n }\n\n private registerInputs() {\n this.registerMidiInput({\n name: \"midi in\",\n onMidiEvent: this.onMidiEvent,\n });\n }\n\n private registerOutputs() {\n this.midiOutput = this.registerMidiOutput({ name: \"midi out\" });\n }\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport { Context } from \"@blibliki/utils\";\nimport { ConstantSourceNode } from \"@blibliki/utils/web-audio-api\";\nimport { IModule, Module, ModulePropSchema, SetterHooks } from \"@/core\";\nimport Note from \"@/core/Note\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IConstant = IModule<ModuleType.Constant>;\nexport type IConstantProps = {\n value: number;\n};\n\nexport const constantPropSchema: ModulePropSchema<IConstantProps> = {\n value: {\n kind: \"number\",\n min: -Infinity,\n max: Infinity,\n step: 0.01,\n label: \"Value\",\n },\n};\n\nconst DEFAULT_PROPS: IConstantProps = { value: 1 };\n\nexport default class Constant\n extends Module<ModuleType.Constant>\n implements Pick<SetterHooks<IConstantProps>, \"onAfterSetValue\">\n{\n declare audioNode: ConstantSourceNode;\n isStated = false;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.Constant>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const audioNodeConstructor = (context: Context) =>\n new ConstantSourceNode(context.audioContext);\n\n super(engineId, {\n ...params,\n props,\n audioNodeConstructor,\n });\n\n this.registerDefaultIOs(\"out\");\n }\n\n onAfterSetValue: SetterHooks<IConstantProps>[\"onAfterSetValue\"] = (value) => {\n this.audioNode.offset.value = value;\n };\n\n start(time: ContextTime) {\n if (this.isStated) return;\n\n this.isStated = true;\n this.audioNode.start(time);\n }\n\n stop(time: ContextTime) {\n if (!this.isStated) return;\n\n this.audioNode.stop(time);\n this.rePlugAll(() => {\n this.audioNode = new ConstantSourceNode(this.context.audioContext, {\n offset: this.props.value,\n });\n });\n\n this.isStated = false;\n }\n\n triggerAttack = (note: Note, triggeredAt: ContextTime) => {\n this.audioNode.offset.setValueAtTime(note.frequency, triggeredAt);\n this.start(triggeredAt);\n };\n\n triggerRelease = () => {\n // Do nothing\n };\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport { Context, cancelAndHoldAtTime } from \"@blibliki/utils\";\nimport { GainNode } from \"@blibliki/utils/web-audio-api\";\nimport { Module } from \"@/core\";\nimport Note from \"@/core/Note\";\nimport { IModuleConstructor } from \"@/core/module/Module\";\nimport { IPolyModuleConstructor, PolyModule } from \"@/core/module/PolyModule\";\nimport { ModulePropSchema } from \"@/core/schema\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IEnvelopeProps = {\n attack: number;\n decay: number;\n sustain: number;\n release: number;\n};\n\nconst DEFAULT_PROPS: IEnvelopeProps = {\n attack: 0.01,\n decay: 0,\n sustain: 1,\n release: 0,\n};\n\nexport const envelopePropSchema: ModulePropSchema<IEnvelopeProps> = {\n attack: {\n kind: \"number\",\n min: 0.0001,\n max: 20,\n step: 0.01,\n exp: 3,\n label: \"Attack\",\n },\n decay: {\n kind: \"number\",\n min: 0,\n max: 20,\n step: 0.01,\n exp: 3,\n label: \"Decay\",\n },\n sustain: {\n kind: \"number\",\n min: 0,\n max: 1,\n step: 0.01,\n label: \"Sustain\",\n },\n release: {\n kind: \"number\",\n min: 0,\n max: 20,\n step: 0.01,\n exp: 3,\n label: \"Release\",\n },\n};\n\nclass MonoEnvelope extends Module<ModuleType.Envelope> {\n declare audioNode: GainNode;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.Envelope>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const audioNodeConstructor = (context: Context) => {\n const audioNode = new GainNode(context.audioContext);\n audioNode.gain.value = 0;\n return audioNode;\n };\n\n super(engineId, {\n ...params,\n props,\n audioNodeConstructor,\n });\n\n this.registerDefaultIOs();\n }\n\n triggerAttack(note: Note, triggeredAt: ContextTime) {\n super.triggerAttack(note, triggeredAt);\n\n const attack = this.props.attack;\n const decay = this.props.decay;\n const sustain = this.props.sustain;\n\n cancelAndHoldAtTime(this.audioNode.gain, triggeredAt);\n\n // Always start from a tiny value, can't ramp from 0\n if (this.audioNode.gain.value === 0) {\n this.audioNode.gain.setValueAtTime(0.001, triggeredAt);\n }\n\n // Attack\n this.audioNode.gain.exponentialRampToValueAtTime(1.0, triggeredAt + attack);\n\n // Decay\n if (sustain > 0) {\n this.audioNode.gain.exponentialRampToValueAtTime(\n sustain,\n triggeredAt + attack + decay,\n );\n // Do not set to zero or anything else!\n } else {\n this.audioNode.gain.exponentialRampToValueAtTime(\n 0.001,\n triggeredAt + attack + decay,\n );\n }\n }\n\n triggerRelease(note: Note, triggeredAt: ContextTime) {\n super.triggerRelease(note, triggeredAt);\n if (this.activeNotes.length > 0) return;\n\n const release = this.props.release;\n\n // Cancel scheduled automations and set gain to the ACTUAL value at this moment\n const currentGainValue = cancelAndHoldAtTime(\n this.audioNode.gain,\n triggeredAt,\n );\n\n if (currentGainValue >= 0.0001) {\n // Always set the value at the release time to ensure a smooth ramp from here\n this.audioNode.gain.setValueAtTime(currentGainValue, triggeredAt);\n // Exponential ramp to a tiny value\n this.audioNode.gain.exponentialRampToValueAtTime(\n 0.0001,\n triggeredAt + release - 0.0001,\n );\n }\n\n // Set to zero at the very end\n this.audioNode.gain.setValueAtTime(0, triggeredAt + release);\n }\n}\n\nexport default class Envelope extends PolyModule<ModuleType.Envelope> {\n constructor(\n engineId: string,\n params: IPolyModuleConstructor<ModuleType.Envelope>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const monoModuleConstructor = (\n engineId: string,\n params: IModuleConstructor<ModuleType.Envelope>,\n ) => new MonoEnvelope(engineId, params);\n\n super(engineId, {\n ...params,\n props,\n monoModuleConstructor,\n });\n\n this.registerDefaultIOs();\n }\n}\n","import { Context } from \"@blibliki/utils\";\nimport { BiquadFilterNode } from \"@blibliki/utils/web-audio-api\";\nimport { EnumProp, ModulePropSchema } from \"@/core\";\nimport { IModuleConstructor, Module, SetterHooks } from \"@/core/module/Module\";\nimport { IPolyModuleConstructor, PolyModule } from \"@/core/module/PolyModule\";\nimport { createModule, ICreateModule, ModuleType } from \".\";\nimport { MonoGain } from \"./Gain\";\nimport Scale from \"./Scale\";\n\nexport type IFilterProps = {\n cutoff: number;\n envelopeAmount: number;\n type: BiquadFilterType;\n Q: number;\n};\n\nconst MIN_FREQ = 20;\nconst MAX_FREQ = 20000;\n\nconst DEFAULT_PROPS: IFilterProps = {\n cutoff: MAX_FREQ,\n envelopeAmount: 0,\n type: \"lowpass\",\n Q: 1,\n};\n\nexport const filterPropSchema: ModulePropSchema<\n IFilterProps,\n {\n type: EnumProp<BiquadFilterType>;\n }\n> = {\n cutoff: {\n kind: \"number\",\n min: MIN_FREQ,\n max: MAX_FREQ,\n step: 1,\n exp: 5,\n label: \"Cutoff\",\n },\n envelopeAmount: {\n kind: \"number\",\n min: -1,\n max: 1,\n step: 0.01,\n label: \"Envelope Amount\",\n },\n type: {\n kind: \"enum\",\n options: [\"lowpass\", \"highpass\", \"bandpass\"] satisfies BiquadFilterType[],\n label: \"Type\",\n },\n Q: {\n kind: \"number\",\n min: 0.0001,\n max: 1000,\n step: 0.1,\n exp: 5,\n label: \"Q\",\n },\n};\n\nclass MonoFilter\n extends Module<ModuleType.Filter>\n implements\n Pick<\n SetterHooks<IFilterProps>,\n | \"onAfterSetType\"\n | \"onAfterSetCutoff\"\n | \"onAfterSetQ\"\n | \"onAfterSetEnvelopeAmount\"\n >\n{\n declare audioNode: BiquadFilterNode;\n private scale: Scale;\n private amount: MonoGain;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.Filter>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n\n const audioNodeConstructor = (context: Context) =>\n new BiquadFilterNode(context.audioContext, {\n type: props.type,\n frequency: 0,\n Q: props.Q,\n });\n\n super(engineId, {\n ...params,\n props,\n audioNodeConstructor,\n });\n\n this.amount = new MonoGain(engineId, {\n name: \"amount\",\n moduleType: ModuleType.Gain,\n props: { gain: props.envelopeAmount },\n });\n\n this.scale = createModule(engineId, {\n name: \"scale\",\n moduleType: ModuleType.Scale,\n props: { min: MIN_FREQ, max: MAX_FREQ, current: this.props.cutoff },\n }) as Scale;\n\n this.amount.plug({ audioModule: this.scale, from: \"out\", to: \"in\" });\n this.scale.audioNode.connect(this.audioNode.frequency);\n\n this.registerDefaultIOs();\n this.registerInputs();\n }\n\n onAfterSetType: SetterHooks<IFilterProps>[\"onAfterSetType\"] = (value) => {\n this.audioNode.type = value;\n };\n\n onAfterSetCutoff: SetterHooks<IFilterProps>[\"onAfterSetCutoff\"] = (value) => {\n this.scale.props = { current: value };\n };\n\n onAfterSetQ: SetterHooks<IFilterProps>[\"onAfterSetQ\"] = (value) => {\n this.audioNode.Q.value = value;\n };\n\n onAfterSetEnvelopeAmount: SetterHooks<IFilterProps>[\"onAfterSetEnvelopeAmount\"] =\n (value) => {\n this.amount.props = { gain: value };\n };\n\n private registerInputs() {\n this.registerAudioInput({\n name: \"cutoff\",\n getAudioNode: () => this.audioNode.frequency,\n });\n\n this.registerAudioInput({\n name: \"cutoffMod\",\n getAudioNode: () => this.amount.audioNode,\n });\n\n this.registerAudioInput({\n name: \"Q\",\n getAudioNode: () => this.audioNode.Q,\n });\n }\n}\n\nexport default class Filter extends PolyModule<ModuleType.Filter> {\n constructor(\n engineId: string,\n params: IPolyModuleConstructor<ModuleType.Filter>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const monoModuleConstructor = (\n engineId: string,\n params: IModuleConstructor<ModuleType.Filter>,\n ) => new MonoFilter(engineId, params);\n\n super(engineId, {\n ...params,\n props,\n monoModuleConstructor,\n });\n\n this.registerInputs();\n this.registerDefaultIOs();\n }\n\n private registerInputs() {\n this.registerAudioInput({ name: \"cutoff\" });\n this.registerAudioInput({ name: \"cutoffMod\" });\n this.registerAudioInput({ name: \"Q\" });\n }\n}\n","import { Context } from \"@blibliki/utils\";\nimport { GainNode } from \"@blibliki/utils/web-audio-api\";\nimport { IModule, Module, ModulePropSchema, SetterHooks } from \"@/core\";\nimport { IModuleConstructor } from \"@/core/module/Module\";\nimport { IPolyModuleConstructor, PolyModule } from \"@/core/module/PolyModule\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IGain = IModule<ModuleType.Gain>;\nexport type IGainProps = {\n gain: number;\n};\n\nexport const gainPropSchema: ModulePropSchema<IGainProps> = {\n gain: {\n kind: \"number\",\n min: 0,\n max: Infinity,\n step: 0.01,\n label: \"Gain\",\n },\n};\n\nconst DEFAULT_PROPS: IGainProps = { gain: 1 };\n\nexport class MonoGain\n extends Module<ModuleType.Gain>\n implements Pick<SetterHooks<IGainProps>, \"onAfterSetGain\">\n{\n declare audioNode: GainNode;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.Gain>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const audioNodeConstructor = (context: Context) =>\n new GainNode(context.audioContext);\n\n super(engineId, {\n ...params,\n audioNodeConstructor,\n props,\n });\n\n this.registerDefaultIOs();\n this.registerAdditionalInputs();\n }\n\n onAfterSetGain: SetterHooks<IGainProps>[\"onAfterSetGain\"] = (value) => {\n this.audioNode.gain.value = value;\n };\n\n private registerAdditionalInputs() {\n this.registerAudioInput({\n name: \"gain\",\n getAudioNode: () => this.audioNode.gain,\n });\n }\n}\n\nexport default class Gain extends PolyModule<ModuleType.Gain> {\n constructor(\n engineId: string,\n params: IPolyModuleConstructor<ModuleType.Gain>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const monoModuleConstructor = (\n engineId: string,\n params: IModuleConstructor<ModuleType.Gain>,\n ) => new MonoGain(engineId, params);\n\n super(engineId, {\n ...params,\n props,\n monoModuleConstructor,\n });\n\n this.registerAdditionalInputs();\n this.registerDefaultIOs();\n }\n\n private registerAdditionalInputs() {\n this.registerAudioInput({ name: \"gain\" });\n }\n}\n","import { Context } from \"@blibliki/utils\";\nimport { AnalyserNode } from \"@blibliki/utils/web-audio-api\";\nimport { IModule, Module, SetterHooks } from \"@/core\";\nimport { EnumProp, ModulePropSchema } from \"@/core/schema\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IInspector = IModule<ModuleType.Inspector>;\nexport type IInspectorProps = {\n fftSize: number;\n};\n\nexport const inspectorPropSchema: ModulePropSchema<\n IInspectorProps,\n {\n fftSize: EnumProp<number>;\n }\n> = {\n fftSize: {\n kind: \"enum\",\n options: [32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768],\n label: \"FFT size\",\n },\n};\n\nconst DEFAULT_PROPS: IInspectorProps = { fftSize: 512 };\n\nexport default class Inspector\n extends Module<ModuleType.Inspector>\n implements Pick<SetterHooks<IInspectorProps>, \"onAfterSetFftSize\">\n{\n declare audioNode: AnalyserNode;\n private _buffer?: Float32Array<ArrayBuffer>;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.Inspector>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const audioNodeConstructor = (context: Context) =>\n new AnalyserNode(context.audioContext);\n\n super(engineId, {\n ...params,\n props,\n audioNodeConstructor,\n });\n\n this.registerDefaultIOs(\"in\");\n }\n\n onAfterSetFftSize: SetterHooks<IInspectorProps>[\"onAfterSetFftSize\"] = (\n value,\n ) => {\n this._buffer = new Float32Array(value);\n };\n\n get buffer() {\n if (this._buffer) return this._buffer;\n\n this._buffer = new Float32Array(this.props.fftSize);\n\n return this._buffer;\n }\n\n getValue(): number {\n const value = this.getValues()[0];\n return value ?? 0;\n }\n\n getValues(): Float32Array {\n this.audioNode.getFloatTimeDomainData(this.buffer);\n\n return this.buffer;\n }\n}\n","import { Context, EmptyObject } from \"@blibliki/utils\";\nimport { IModule, Module, ModulePropSchema } from \"@/core\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IMaster = IModule<ModuleType.Master>;\nexport type IMasterProps = EmptyObject;\n\nconst DEFAULT_PROPS: IMasterProps = {};\n\nexport const masterPropSchema: ModulePropSchema<IMasterProps> = {};\n\nexport default class Master extends Module<ModuleType.Master> {\n declare audioNode: AudioDestinationNode;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.Master>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const audioNodeConstructor = (context: Context) => context.destination;\n\n super(engineId, { ...params, audioNodeConstructor, props });\n\n this.registerDefaultIOs(\"in\");\n }\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport { IModule, MidiEvent, Module, SetterHooks } from \"@/core\";\nimport { ModulePropSchema, NumberProp, PropSchema } from \"@/core/schema\";\nimport { ICreateModule, moduleSchemas, ModuleType } from \".\";\n\nexport type IMidiMapper = IModule<ModuleType.MidiMapper>;\nexport type IMidiMapperProps = {\n pages: MidiMappingPage[];\n activePage: number;\n globalMappings: MidiMapping<ModuleType>[];\n};\n\nexport type MidiMappingPage = {\n name?: string;\n mappings: MidiMapping<ModuleType>[];\n};\n\nexport enum MidiMappingMode {\n direct = \"direct\",\n directRev = \"directRev\",\n toggleInc = \"toggleInc\",\n toggleDec = \"toggleDec\",\n incDec = \"incDec\",\n incDecRev = \"incDecRev\",\n}\n\nexport type MidiMapping<T extends ModuleType> = {\n cc?: number;\n moduleId?: string;\n moduleType?: T;\n propName?: string;\n autoAssign?: boolean;\n mode?: MidiMappingMode;\n threshold?: number; // For incDec mode (default: 64)\n step?: number;\n};\n\nexport const midiMapperPropSchema: ModulePropSchema<IMidiMapperProps> = {\n pages: {\n kind: \"array\",\n label: \"Midi mapping pages\",\n },\n activePage: {\n kind: \"number\",\n label: \"Active page\",\n min: 0,\n max: 100,\n step: 1,\n },\n globalMappings: {\n kind: \"array\",\n label: \"Global midi mappings\",\n },\n};\n\nconst DEFAULT_PROPS: IMidiMapperProps = {\n pages: [{ name: \"Page 1\", mappings: [{}] }],\n activePage: 0,\n globalMappings: [{}],\n};\n\nfunction getMidiFromMappedValue({\n value,\n midiValue,\n propSchema,\n mapping,\n}: {\n value: number;\n propSchema: NumberProp;\n midiValue: number;\n mapping: MidiMapping<ModuleType>;\n}): number {\n const min = propSchema.min ?? 0;\n const max = propSchema.max ?? 1;\n const exp = propSchema.exp ?? 1;\n\n const { threshold = 64, mode } = mapping;\n\n // Reverse the range mapping: get curvedValue\n const curvedValue = (value - min) / (max - min);\n\n // Reverse the exponential curve: get normalizedMidi\n const normalizedMidi = Math.pow(curvedValue, 1 / exp);\n\n // Reverse the MIDI normalization: get midiValue\n let newMidiValue = normalizedMidi * 127;\n newMidiValue =\n (midiValue >= threshold && mode === MidiMappingMode.incDec) ||\n (midiValue <= threshold && mode === MidiMappingMode.incDecRev)\n ? newMidiValue + 1\n : newMidiValue - 1;\n return Math.round(Math.max(0, Math.min(127, newMidiValue))); // Valid MIDI range\n}\n\ntype MidiMapperSetterHooks = Pick<\n SetterHooks<IMidiMapperProps>,\n \"onSetActivePage\"\n>;\n\nexport default class MidiMapper\n extends Module<ModuleType.MidiMapper>\n implements MidiMapperSetterHooks\n{\n declare audioNode: undefined;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.MidiMapper>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n\n super(engineId, {\n ...params,\n props,\n });\n\n this.registerMidiInput({\n name: \"midi in\",\n onMidiEvent: this.onMidiEvent,\n });\n }\n\n onSetActivePage: MidiMapperSetterHooks[\"onSetActivePage\"] = (value) => {\n return Math.max(Math.min(value, this.props.pages.length - 1), 0);\n };\n\n handleCC = (event: MidiEvent, triggeredAt: ContextTime) => {\n this.checkAutoAssign(event);\n\n const activePage = this.props.pages[this.props.activePage];\n if (!activePage) return;\n\n [\n ...this.props.globalMappings.filter((m) => m.cc === event.cc),\n ...activePage.mappings.filter((m) => m.cc === event.cc),\n ].forEach((mapping) => {\n this.forwardMapping(event, mapping, triggeredAt);\n });\n };\n\n forwardMapping = (\n event: MidiEvent,\n mapping: MidiMapping<ModuleType>,\n _triggeredAt: ContextTime,\n ) => {\n if (\n mapping.moduleId === undefined ||\n mapping.moduleType === undefined ||\n mapping.propName === undefined\n )\n return;\n\n const propName = mapping.propName;\n let midiValue = event.ccValue;\n if (midiValue === undefined) return;\n\n const mode = mapping.mode ?? \"direct\";\n\n // Toggle mode: only respond to 127 (button press), ignore 0\n if (\n (mode === MidiMappingMode.toggleInc ||\n mode === MidiMappingMode.toggleDec) &&\n midiValue !== 127\n ) {\n return;\n }\n\n const mappedModule = this.engine.findModule(mapping.moduleId);\n // @ts-expect-error TS7053 ignore this error\n const propSchema = moduleSchemas[mappedModule.moduleType][\n propName\n ] as PropSchema;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let mappedValue: any;\n\n // Direct mode (default) or Toggle mode: map value directly\n switch (propSchema.kind) {\n case \"number\": {\n // @ts-expect-error TS7053 ignore this error\n const currentValue = mappedModule.props[propName] as number;\n\n if (\n mode === MidiMappingMode.incDec ||\n mode === MidiMappingMode.incDecRev\n ) {\n midiValue = getMidiFromMappedValue({\n value: currentValue,\n propSchema,\n mapping,\n midiValue,\n });\n } else if (mode === MidiMappingMode.directRev) {\n midiValue = 127 - midiValue;\n }\n\n if (mode === MidiMappingMode.toggleInc) {\n mappedValue = currentValue + (propSchema.step ?? 1);\n } else if (mode === MidiMappingMode.toggleDec) {\n mappedValue = currentValue - (propSchema.step ?? 1);\n } else {\n const min = propSchema.min ?? 0;\n const max = propSchema.max ?? 1;\n const normalizedMidi = midiValue / 127;\n const curvedValue = Math.pow(normalizedMidi, propSchema.exp ?? 1);\n mappedValue = min + curvedValue * (max - min);\n\n // Round to step if defined\n if (\n propSchema.step !== undefined &&\n (!propSchema.exp || propSchema.exp === 1)\n ) {\n const steps = Math.round((mappedValue - min) / propSchema.step);\n mappedValue = min + steps * propSchema.step;\n }\n }\n\n break;\n }\n case \"enum\": {\n const optionIndex = Math.floor(\n (midiValue / 127) * propSchema.options.length,\n );\n const clampedIndex = Math.min(\n optionIndex,\n propSchema.options.length - 1,\n );\n mappedValue = propSchema.options[clampedIndex];\n break;\n }\n case \"boolean\":\n mappedValue = midiValue >= 64;\n break;\n case \"string\":\n throw Error(\"MidiMapper not support string type of values\");\n case \"array\":\n throw Error(\"MidiMapper not support array type of values\");\n\n default:\n throw Error(\"MidiMapper unknown type\");\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n mappedModule.props = { [propName]: mappedValue };\n mappedModule.triggerPropsUpdate();\n };\n\n private checkAutoAssign(event: MidiEvent) {\n if (event.cc === undefined) return;\n\n const activePage = this.props.pages[this.props.activePage];\n if (!activePage) return;\n\n const hasGlobalAutoAssign = this.props.globalMappings.some(\n ({ autoAssign }) => autoAssign,\n );\n const hasPageAutoAssign = activePage.mappings.some(\n ({ autoAssign }) => autoAssign,\n );\n\n if (!hasGlobalAutoAssign && !hasPageAutoAssign) return;\n\n // Update global mappings if needed\n const updatedGlobalMappings = hasGlobalAutoAssign\n ? this.props.globalMappings.map((mapping) => {\n if (!mapping.autoAssign) return mapping;\n\n return {\n ...mapping,\n cc: event.cc,\n autoAssign: false,\n };\n })\n : this.props.globalMappings;\n\n // Update page mappings if needed\n const updatedPageMappings = hasPageAutoAssign\n ? activePage.mappings.map((mapping) => {\n if (!mapping.autoAssign) return mapping;\n\n return {\n ...mapping,\n cc: event.cc,\n autoAssign: false,\n };\n })\n : activePage.mappings;\n\n const updatedPages = this.props.pages.map((page, index) =>\n index === this.props.activePage\n ? { ...page, mappings: updatedPageMappings }\n : page,\n );\n\n this.props = { pages: updatedPages, globalMappings: updatedGlobalMappings };\n this.triggerPropsUpdate();\n }\n}\n","import { IModule, Module, MidiOutput, SetterHooks, MidiDevice } from \"@/core\";\nimport ComputerKeyboardInput from \"@/core/midi/ComputerKeyboardDevice\";\nimport MidiEvent from \"@/core/midi/MidiEvent\";\nimport { ModulePropSchema } from \"@/core/schema\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IMidiSelector = IModule<ModuleType.MidiSelector>;\nexport type IMidiSelectorProps = {\n selectedId: string | undefined | null;\n selectedName: string | undefined | null;\n};\n\nexport const midiSelectorPropSchema: ModulePropSchema<IMidiSelectorProps> = {\n selectedId: {\n kind: \"string\",\n label: \"Midi device ID\",\n },\n selectedName: {\n kind: \"string\",\n label: \"Midi device name\",\n },\n};\n\nconst DEFAULT_PROPS: IMidiSelectorProps = {\n selectedId: undefined,\n selectedName: undefined,\n};\n\nexport default class MidiSelector\n extends Module<ModuleType.MidiSelector>\n implements Pick<SetterHooks<IMidiSelectorProps>, \"onSetSelectedId\">\n{\n declare audioNode: undefined;\n midiOutput!: MidiOutput;\n _forwardMidiEvent?: (midiEvent: MidiEvent) => void;\n\n constructor(\n engineId: string,\n params: ICreateModule<ModuleType.MidiSelector>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n\n super(engineId, {\n ...params,\n props,\n });\n\n // Try to find device in order of preference:\n // 1. By exact ID match\n // 2. By exact name match\n // 3. By fuzzy name match (for cross-platform compatibility)\n let midiDevice =\n this.props.selectedId &&\n this.engine.findMidiDevice(this.props.selectedId);\n\n if (!midiDevice && this.props.selectedName) {\n midiDevice = this.engine.findMidiDeviceByName(this.props.selectedName);\n\n // If exact name match fails, try fuzzy matching\n if (!midiDevice) {\n const fuzzyMatch = this.engine.findMidiDeviceByFuzzyName(\n this.props.selectedName,\n 0.6, // 60% similarity threshold\n );\n\n if (fuzzyMatch) {\n midiDevice = fuzzyMatch.device;\n console.log(\n `MIDI device fuzzy matched: \"${this.props.selectedName}\" -> \"${midiDevice.name}\" (confidence: ${Math.round(fuzzyMatch.score * 100)}%)`,\n );\n }\n }\n }\n\n if (midiDevice) {\n this.addEventListener(midiDevice);\n }\n\n this.registerOutputs();\n }\n\n onSetSelectedId: SetterHooks<IMidiSelectorProps>[\"onSetSelectedId\"] = (\n value,\n ) => {\n this.removeEventListener();\n if (!value) return value;\n\n const midiDevice = this.engine.findMidiDevice(value);\n if (!midiDevice) return value;\n\n if (this.props.selectedName !== midiDevice.name) {\n this.props = { selectedName: midiDevice.name };\n this.triggerPropsUpdate();\n }\n this.addEventListener(midiDevice);\n\n return value;\n };\n\n private get forwardMidiEvent() {\n if (this._forwardMidiEvent) return this._forwardMidiEvent;\n\n this._forwardMidiEvent = (midiEvent: MidiEvent) => {\n this.midiOutput.onMidiEvent(midiEvent);\n };\n\n return this._forwardMidiEvent;\n }\n\n private addEventListener(midiDevice: MidiDevice | ComputerKeyboardInput) {\n midiDevice.addEventListener(this.forwardMidiEvent);\n }\n\n private removeEventListener() {\n if (!this.props.selectedId) return;\n\n const midiDevice = this.engine.findMidiDevice(this.props.selectedId);\n midiDevice?.removeEventListener(this.forwardMidiEvent);\n }\n\n private registerOutputs() {\n this.midiOutput = this.registerMidiOutput({ name: \"midi out\" });\n }\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport { Context, dbToGain } from \"@blibliki/utils\";\nimport { GainNode, OscillatorNode } from \"@blibliki/utils/web-audio-api\";\nimport { IModule, Module } from \"@/core\";\nimport Note from \"@/core/Note\";\nimport { IModuleConstructor, SetterHooks } from \"@/core/module/Module\";\nimport { IPolyModuleConstructor, PolyModule } from \"@/core/module/PolyModule\";\nimport { EnumProp, ModulePropSchema } from \"@/core/schema\";\nimport { ICreateModule, ModuleType } from \".\";\n\nconst LOW_GAIN = -18;\n\nexport type IOscillator = IModule<ModuleType.Oscillator>;\n\nexport enum OscillatorWave {\n sine = \"sine\",\n triangle = \"triangle\",\n square = \"square\",\n sawtooth = \"sawtooth\",\n}\n\n/**\n * Props for the Oscillator module.\n *\n * @property wave - Waveform shape of the oscillator.\n * One of: \"sine\", \"square\", \"sawtooth\", \"triangle\", or \"custom\".\n * @property frequency - Base frequency in Hz (e.g. 440 for A4).\n * @property fine - Fine tuning factor in the range [-1, 1], where ±1 represents ±1 semitone.\n * @property coarse - Coarse tuning factor in the range [-1, 1], scaled to ±12 semitones.\n * @property octave - Octave transposition value (e.g. +1 for one octave up, -2 for two octaves down).\n * @property lowGain - Whether to gain reduction (-18dB). When false, oscillator runs at full gain.\n */\nexport type IOscillatorProps = {\n wave: OscillatorWave;\n frequency: number;\n fine: number;\n coarse: number;\n octave: number;\n lowGain: boolean;\n};\n\nexport const oscillatorPropSchema: ModulePropSchema<\n IOscillatorProps,\n {\n wave: EnumProp<OscillatorWave>;\n }\n> = {\n wave: {\n kind: \"enum\",\n options: Object.values(OscillatorWave),\n label: \"Waveform\",\n },\n frequency: {\n kind: \"number\",\n min: 0,\n max: 25000,\n step: 1,\n label: \"Frequency\",\n },\n fine: {\n kind: \"number\",\n min: -1,\n max: 1,\n step: 0.01,\n label: \"Fine\",\n },\n coarse: {\n kind: \"number\",\n min: -12,\n max: 12,\n step: 1,\n label: \"Coarse\",\n },\n octave: {\n kind: \"number\",\n min: -1,\n max: 2,\n step: 1,\n label: \"Octave\",\n },\n lowGain: {\n kind: \"boolean\",\n label: `Use ${LOW_GAIN}db Gain`,\n },\n};\n\nconst DEFAULT_PROPS: IOscillatorProps = {\n wave: OscillatorWave.sine,\n frequency: 440,\n fine: 0,\n coarse: 0,\n octave: 0,\n lowGain: false,\n};\n\ntype OscillatorSetterHooks = Pick<\n SetterHooks<IOscillatorProps>,\n | \"onAfterSetWave\"\n | \"onAfterSetFrequency\"\n | \"onAfterSetFine\"\n | \"onAfterSetCoarse\"\n | \"onAfterSetOctave\"\n | \"onAfterSetLowGain\"\n>;\n\nexport class MonoOscillator\n extends Module<ModuleType.Oscillator>\n implements OscillatorSetterHooks\n{\n declare audioNode: OscillatorNode;\n isStated = false;\n outputGain: GainNode;\n detuneGain!: GainNode;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.Oscillator>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const audioNodeConstructor = (context: Context) =>\n new OscillatorNode(context.audioContext);\n\n super(engineId, {\n ...params,\n props,\n audioNodeConstructor,\n });\n\n this.outputGain = new GainNode(this.context.audioContext, {\n gain: dbToGain(LOW_GAIN),\n });\n\n this.applyOutputGain();\n this.initializeGainDetune();\n this.registerInputs();\n this.registerOutputs();\n }\n\n onAfterSetWave: OscillatorSetterHooks[\"onAfterSetWave\"] = (value) => {\n this.audioNode.type = value;\n };\n\n onAfterSetFrequency: OscillatorSetterHooks[\"onAfterSetFrequency\"] = () => {\n this.updateFrequency();\n };\n\n onAfterSetFine: OscillatorSetterHooks[\"onAfterSetFine\"] = () => {\n this.updateFrequency();\n };\n\n onAfterSetCoarse: OscillatorSetterHooks[\"onAfterSetCoarse\"] = () => {\n this.updateFrequency();\n };\n\n onAfterSetOctave: OscillatorSetterHooks[\"onAfterSetOctave\"] = () => {\n this.updateFrequency();\n };\n\n onAfterSetLowGain: OscillatorSetterHooks[\"onAfterSetLowGain\"] = (lowGain) => {\n this.outputGain.gain.value = lowGain ? dbToGain(LOW_GAIN) : 1;\n };\n\n start(time: ContextTime) {\n if (this.isStated) return;\n\n this.isStated = true;\n this.audioNode.start(time);\n }\n\n stop(time: ContextTime) {\n if (!this.isStated) return;\n\n this.audioNode.stop(time);\n this.rePlugAll(() => {\n this.audioNode = new OscillatorNode(this.context.audioContext, {\n type: this.props.wave,\n frequency: this.finalFrequency,\n });\n this.applyOutputGain();\n this.detuneGain.connect(this.audioNode.detune);\n });\n\n this.isStated = false;\n }\n\n triggerAttack = (note: Note, triggeredAt: ContextTime) => {\n super.triggerAttack(note, triggeredAt);\n\n this.props = { frequency: note.frequency };\n this.updateFrequency(triggeredAt);\n this.start(triggeredAt);\n };\n\n triggerRelease(note: Note, triggeredAt: ContextTime) {\n super.triggerRelease(note, triggeredAt);\n\n const lastNote = this.activeNotes.length\n ? this.activeNotes[this.activeNotes.length - 1]\n : null;\n if (!lastNote) return;\n\n this.props = { frequency: lastNote.frequency };\n this.updateFrequency(triggeredAt);\n }\n\n private get finalFrequency(): number | undefined {\n const { frequency, coarse, octave, fine } = this.props;\n\n const transposed =\n frequency * Math.pow(2, coarse / 12 + octave + fine / 12);\n return transposed;\n }\n\n private updateFrequency(actionAt?: ContextTime) {\n if (this.finalFrequency === undefined) return;\n\n if (actionAt) {\n this.audioNode.frequency.setValueAtTime(this.finalFrequency, actionAt);\n } else {\n this.audioNode.frequency.value = this.finalFrequency;\n }\n }\n\n private applyOutputGain() {\n this.audioNode.connect(this.outputGain);\n }\n\n private initializeGainDetune() {\n this.detuneGain = new GainNode(this.context.audioContext, { gain: 100 });\n this.detuneGain.connect(this.audioNode.detune);\n }\n\n private registerInputs() {\n this.registerAudioInput({\n name: \"detune\",\n getAudioNode: () => this.detuneGain,\n });\n }\n\n private registerOutputs() {\n this.registerAudioOutput({\n name: \"out\",\n getAudioNode: () => this.outputGain,\n });\n }\n}\n\nexport default class Oscillator extends PolyModule<ModuleType.Oscillator> {\n constructor(\n engineId: string,\n params: IPolyModuleConstructor<ModuleType.Oscillator>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const monoModuleConstructor = (\n engineId: string,\n params: IModuleConstructor<ModuleType.Oscillator>,\n ) => new MonoOscillator(engineId, params);\n\n super(engineId, {\n ...params,\n props,\n monoModuleConstructor,\n });\n\n this.registerInputs();\n this.registerDefaultIOs(\"out\");\n }\n\n start(time: ContextTime) {\n this.audioModules.forEach((audioModule) => {\n audioModule.start(time);\n });\n }\n\n stop(time: ContextTime) {\n this.audioModules.forEach((audioModule) => {\n audioModule.stop(time);\n });\n }\n\n private registerInputs() {\n this.registerAudioInput({ name: \"detune\" });\n }\n}\n","import { assertNever, Context } from \"@blibliki/utils\";\nimport { filterProcessorURL } from \"./filter-processor\";\nimport { scaleProcessorURL } from \"./scale-processor\";\n\nexport enum CustomWorklet {\n ScaleProcessor = \"ScaleProcessor\",\n FilterProcessor = \"FilterProcessor\",\n}\n\nexport async function loadProcessors(context: Context) {\n await context.addModule(scaleProcessorURL);\n await context.addModule(filterProcessorURL);\n}\n\nexport function newAudioWorklet(context: Context, worklet: CustomWorklet) {\n switch (worklet) {\n case CustomWorklet.ScaleProcessor:\n return context.newAudioWorklet(\"scale-processor\");\n case CustomWorklet.FilterProcessor:\n return context.newAudioWorklet(\"filter-processor\");\n default:\n assertNever(worklet);\n }\n}\n","export const filterProcessorURL = URL.createObjectURL(\n new Blob(\n [\n \"(\",\n (() => {\n class FilterProcessor extends AudioWorkletProcessor {\n s0: number;\n s1: number;\n\n constructor() {\n super();\n this.s0 = 0;\n this.s1 = 0;\n }\n\n static get parameterDescriptors() {\n return [\n {\n name: \"cutoff\",\n defaultValue: 1000,\n minValue: 20,\n maxValue: 20000,\n },\n {\n name: \"resonance\",\n defaultValue: 0.0,\n minValue: 0.0,\n maxValue: 4.0,\n },\n ];\n }\n\n process(\n inputs: Float32Array[][],\n outputs: Float32Array[][],\n parameters: Record<string, Float32Array>,\n ): boolean {\n const input = inputs[0];\n const output = outputs[0];\n if (!input || !output) return true;\n\n const cutoff = parameters.cutoff;\n const resonance = parameters.resonance;\n if (!cutoff || !resonance) return true;\n\n for (let channelNum = 0; channelNum < input.length; channelNum++) {\n const inputChannel = input[channelNum];\n const outputChannel = output[channelNum];\n if (!inputChannel || !outputChannel) continue;\n\n for (let i = 0; i < inputChannel.length; i++) {\n const s = inputChannel[i];\n if (s === undefined) continue;\n\n // Convert Hz to normalized frequency using logarithmic scale\n // This better matches human hearing perception\n const cutoffHz =\n cutoff.length > 1 ? (cutoff[i] ?? cutoff[0]) : cutoff[0];\n if (cutoffHz === undefined) continue;\n\n const clampedHz = Math.max(20, Math.min(20000, cutoffHz));\n const normalizedCutoff =\n Math.log(clampedHz / 20) / Math.log(20000 / 20);\n const c = Math.pow(0.5, (1 - normalizedCutoff) / 0.125);\n\n const resonanceValue =\n resonance.length > 1\n ? (resonance[i] ?? resonance[0])\n : resonance[0];\n if (resonanceValue === undefined) continue;\n\n const r = Math.pow(0.5, (resonanceValue + 0.125) / 0.125);\n const mrc = 1 - r * c;\n\n this.s0 = mrc * this.s0 - c * this.s1 + c * s;\n this.s1 = mrc * this.s1 + c * this.s0;\n\n outputChannel[i] = this.s1;\n }\n }\n\n return true;\n }\n }\n\n registerProcessor(\"filter-processor\", FilterProcessor);\n }).toString(),\n \")()\",\n ],\n { type: \"application/javascript\" },\n ),\n);\n","export const scaleProcessorURL = URL.createObjectURL(\n new Blob(\n [\n \"(\",\n (() => {\n class ScaleProcessor extends AudioWorkletProcessor {\n static get parameterDescriptors() {\n return [\n {\n name: \"min\",\n defaultValue: 1e-10,\n },\n {\n name: \"max\",\n defaultValue: 1,\n },\n {\n name: \"current\",\n defaultValue: 0.5,\n },\n ];\n }\n\n process(\n inputs: Float32Array[][],\n outputs: Float32Array[][],\n parameters: Record<string, Float32Array>,\n ) {\n const input = inputs[0];\n const output = outputs[0];\n if (!input || !output) return true;\n\n const minValues = parameters.min;\n const maxValues = parameters.max;\n const currentValues = parameters.current;\n if (!minValues || !maxValues || !currentValues) return true;\n\n const firstInput = input[0];\n if (!firstInput || firstInput.length === 0) {\n for (const outputChannel of output) {\n const current =\n currentValues.length > 1\n ? (currentValues[0] ?? 0.5)\n : (currentValues[0] ?? 0.5);\n\n outputChannel.fill(current);\n }\n\n return true;\n }\n\n for (let channel = 0; channel < input.length; channel++) {\n const inputChannel = input[channel];\n const outputChannel = output[channel];\n if (!inputChannel || !outputChannel) continue;\n\n for (let i = 0; i < inputChannel.length; i++) {\n const x = inputChannel[i];\n if (x === undefined) continue;\n\n const min =\n minValues.length > 1\n ? (minValues[i] ?? minValues[0])\n : minValues[0];\n const max =\n maxValues.length > 1\n ? (maxValues[i] ?? maxValues[0])\n : maxValues[0];\n const current =\n currentValues.length > 1\n ? (currentValues[i] ?? currentValues[0])\n : currentValues[0];\n\n if (\n min === undefined ||\n max === undefined ||\n current === undefined\n )\n continue;\n\n if (x < 0) {\n outputChannel[i] = current * Math.pow(min / current, -x);\n } else {\n outputChannel[i] = current * Math.pow(max / current, x);\n }\n }\n }\n\n return true;\n }\n }\n\n registerProcessor(\"scale-processor\", ScaleProcessor);\n }).toString(),\n \")()\",\n ],\n { type: \"application/javascript\" },\n ),\n);\n","import { Context } from \"@blibliki/utils\";\nimport { IModule, Module, SetterHooks } from \"@/core\";\nimport { ModulePropSchema } from \"@/core/schema\";\nimport { CustomWorklet, newAudioWorklet } from \"@/processors\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IScale = IModule<ModuleType.Scale>;\nexport type IScaleProps = {\n min: number;\n max: number;\n current: number;\n};\n\nexport const scalePropSchema: ModulePropSchema<IScaleProps> = {\n min: {\n kind: \"number\",\n min: -Infinity,\n max: Infinity,\n step: 0.01,\n label: \"Min\",\n },\n max: {\n kind: \"number\",\n min: -Infinity,\n max: Infinity,\n step: 0.01,\n label: \"Max\",\n },\n current: {\n kind: \"number\",\n min: -Infinity,\n max: Infinity,\n step: 0.01,\n label: \"Current\",\n },\n};\n\nconst DEFAULT_PROPS: IScaleProps = { min: 0, max: 1, current: 0.5 };\n\nexport default class Scale\n extends Module<ModuleType.Scale>\n implements\n Pick<\n SetterHooks<IScaleProps>,\n \"onAfterSetMin\" | \"onAfterSetMax\" | \"onAfterSetCurrent\"\n >\n{\n declare audioNode: AudioWorkletNode;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.Scale>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const audioNodeConstructor = (context: Context) =>\n newAudioWorklet(context, CustomWorklet.ScaleProcessor);\n\n super(engineId, {\n ...params,\n props,\n audioNodeConstructor,\n });\n\n this.registerDefaultIOs();\n }\n\n get current() {\n return this.audioNode.parameters.get(\"current\")!;\n }\n\n get min() {\n return this.audioNode.parameters.get(\"min\")!;\n }\n\n get max() {\n return this.audioNode.parameters.get(\"max\")!;\n }\n\n onAfterSetMin: SetterHooks<IScaleProps>[\"onAfterSetMin\"] = (value) => {\n this.min.value = value;\n };\n\n onAfterSetMax: SetterHooks<IScaleProps>[\"onAfterSetMax\"] = (value) => {\n this.max.value = value;\n };\n\n onAfterSetCurrent: SetterHooks<IScaleProps>[\"onAfterSetCurrent\"] = (\n value,\n ) => {\n this.current.value = value;\n };\n}\n","import { INote, Module, IModule, MidiOutput, ModulePropSchema } from \"@/core\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IStepSequencer = IModule<ModuleType.StepSequencer>;\n\nexport type ISequence = {\n active: boolean;\n // time: BarsBeatsSixteenths;\n duration: string;\n notes: INote[];\n};\n\nexport type IStepSequencerProps = {\n bars: number;\n steps: number;\n sequences: ISequence[][];\n};\n\nexport const stepSequencerPropSchema: ModulePropSchema<\n Omit<IStepSequencerProps, \"sequences\">\n> = {\n steps: {\n kind: \"number\",\n min: 1,\n max: 16,\n step: 1,\n label: \"Steps\",\n },\n bars: {\n kind: \"number\",\n min: 1,\n max: 16,\n step: 1,\n label: \"Steps\",\n },\n};\n\nconst DEFAULT_PROPS: IStepSequencerProps = {\n sequences: [],\n steps: 16,\n bars: 1,\n};\n\n// Not implemented yet, just the data modeling\nexport default class StepSequencer extends Module<ModuleType.StepSequencer> {\n declare audioNode: undefined;\n midiOutput!: MidiOutput;\n\n constructor(\n engineId: string,\n params: ICreateModule<ModuleType.StepSequencer>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n\n super(engineId, {\n ...params,\n props,\n });\n }\n}\n","import { Context } from \"@blibliki/utils\";\nimport { StereoPannerNode } from \"@blibliki/utils/web-audio-api\";\nimport { IModule, Module, ModulePropSchema } from \"@/core\";\nimport { IModuleConstructor, SetterHooks } from \"@/core/module/Module\";\nimport { IPolyModuleConstructor, PolyModule } from \"@/core/module/PolyModule\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IStereoPanner = IModule<ModuleType.StereoPanner>;\nexport type IStereoPannerProps = {\n pan: number;\n};\n\nexport const stereoPannerPropSchema: ModulePropSchema<IStereoPannerProps> = {\n pan: {\n kind: \"number\",\n min: -1,\n max: 1,\n step: 0.01,\n label: \"Pan\",\n },\n};\n\nconst DEFAULT_PROPS: IStereoPannerProps = {\n pan: 0,\n};\n\nexport class MonoStereoPanner\n extends Module<ModuleType.StereoPanner>\n implements Pick<SetterHooks<IStereoPannerProps>, \"onAfterSetPan\">\n{\n declare audioNode: StereoPannerNode;\n\n constructor(\n engineId: string,\n params: ICreateModule<ModuleType.StereoPanner>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const audioNodeConstructor = (context: Context) =>\n new StereoPannerNode(context.audioContext);\n\n super(engineId, {\n ...params,\n audioNodeConstructor,\n props,\n });\n\n this.registerDefaultIOs();\n this.registerAdditionalInputs();\n }\n\n onAfterSetPan: SetterHooks<IStereoPannerProps>[\"onAfterSetPan\"] = (value) => {\n this.audioNode.pan.value = value;\n };\n\n private registerAdditionalInputs() {\n this.registerAudioInput({\n name: \"pan\",\n getAudioNode: () => this.audioNode.pan,\n });\n }\n}\n\nexport default class StereoPanner extends PolyModule<ModuleType.StereoPanner> {\n constructor(\n engineId: string,\n params: IPolyModuleConstructor<ModuleType.StereoPanner>,\n ) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n const monoModuleConstructor = (\n engineId: string,\n params: IModuleConstructor<ModuleType.StereoPanner>,\n ) => new MonoStereoPanner(engineId, params);\n\n super(engineId, {\n ...params,\n props,\n monoModuleConstructor,\n });\n\n this.registerAdditionalInputs();\n this.registerDefaultIOs();\n }\n\n private registerAdditionalInputs() {\n this.registerAudioInput({ name: \"pan\" });\n }\n}\n","import { ContextTime } from \"@blibliki/transport\";\nimport { Module, IModule, MidiOutput, Note, ModulePropSchema } from \"@/core\";\nimport MidiEvent from \"@/core/midi/MidiEvent\";\nimport { ICreateModule, ModuleType } from \".\";\n\nexport type IVirtualMidi = IModule<ModuleType.VirtualMidi>;\nexport type IVirtualMidiProps = {\n activeNotes: string[];\n};\n\nexport const virtualMidiPropSchema: ModulePropSchema<IVirtualMidiProps> = {\n activeNotes: {\n kind: \"array\",\n label: \"Active notes\",\n },\n};\n\nconst DEFAULT_PROPS: IVirtualMidiProps = { activeNotes: [] };\n\nexport default class VirtualMidi extends Module<ModuleType.VirtualMidi> {\n declare audioNode: undefined;\n midiOutput!: MidiOutput;\n\n constructor(engineId: string, params: ICreateModule<ModuleType.VirtualMidi>) {\n const props = { ...DEFAULT_PROPS, ...params.props };\n\n super(engineId, {\n ...params,\n props,\n });\n\n this.registerInputs();\n this.registerOutputs();\n }\n\n sendMidi(midiEvent: MidiEvent) {\n this.midiOutput.onMidiEvent(midiEvent);\n }\n\n triggerAttack = (note: Note, triggerAttack: ContextTime) => {\n this.props = { activeNotes: [...this.props.activeNotes, note.fullName] };\n this.triggerPropsUpdate();\n this.sendMidi(MidiEvent.fromNote(note, true, triggerAttack));\n };\n\n triggerRelease = (note: Note, triggerAttack: ContextTime) => {\n this.props = {\n activeNotes: this.props.activeNotes.filter(\n (name) => name !== note.fullName,\n ),\n };\n this.triggerPropsUpdate();\n this.sendMidi(MidiEvent.fromNote(note, false, triggerAttack));\n };\n\n private registerInputs() {\n this.registerMidiInput({\n name: \"midi in\",\n onMidiEvent: this.onMidiEvent,\n });\n }\n\n private registerOutputs() {\n this.midiOutput = this.registerMidiOutput({ name: \"midi out\" });\n }\n}\n","export { Engine } from \"./Engine\";\nexport type { ICreateRoute, IUpdateModule, IEngineSerialize } from \"./Engine\";\n\nexport type {\n IRoute,\n IIOSerialize,\n IModule,\n IModuleSerialize,\n IPolyModuleSerialize,\n IAnyModuleSerialize,\n IMidiDevice,\n ModulePropSchema,\n PropSchema,\n StringProp,\n NumberProp,\n EnumProp,\n BooleanProp,\n ArrayProp,\n INote,\n} from \"./core\";\nexport { MidiDevice, MidiPortState, Note } from \"./core\";\n\nexport { TransportState } from \"@blibliki/transport\";\nexport type { TimeSignature, Position } from \"@blibliki/transport\";\n\nexport { Context } from \"@blibliki/utils\";\n\nexport {\n ModuleType,\n moduleSchemas,\n OscillatorWave,\n MidiMappingMode,\n} from \"./modules\";\nexport type {\n IOscillator,\n IGain,\n IMaster,\n ISequence,\n IStepSequencerProps,\n IStepSequencer,\n ModuleTypeToPropsMapping,\n ICreateModule,\n ModuleParams,\n IMidiMapper,\n IMidiMapperProps,\n MidiMapping,\n} from \"./modules\";\n"],"mappings":"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","names":["Transport","assertDefined","Context","pick","uuidv4","upperFirst","uuidv4","requestAnimationFrame","assertNever","sortBy","deterministicId","uuidv4","requestAnimationFrame","PolyModule","engineId","params","id","name","moduleType","voices","monoModuleConstructor","props","uuidv4","InputCollection","OutputCollection","value","m","time","audioModule","from","to","output","input","callback","midiEvent","voiceNo","requestAnimationFrame","moduleByVoice","deterministicId","Engine","AudioParam","deterministicId","Base","module","props","deterministicId","io","plugOther","currentIO","callback","connections","otherIO","IO","PolyAudioInput","IO","io","plugOther","PolyAudioOutput","plugOrUnplug","voice","thisIO","otherIO","isPlug","maxVoices","thisMonoIO","otherMonoIO","AudioInput","IO","module","props","AudioOutput","io","plugOther","PolyAudioInput","input","AudioParam","MidiInput","IO","module","props","MidiOutput","event","input","IOCollection","collectionType","module","props","io","PolyModule","AudioInput","AudioOutput","Module","PolyAudioInput","PolyAudioOutput","MidiInput","MidiOutput","assertNever","callback","id","name","sortBy","InputCollection","OutputCollection","frequencyTable","frequencyTable_default","Notes","MIDI_OCTAVE_SYTSTEM","Note","_Note","frequency","noteName","note","freq","frequencyTable_default","message","dataByte","name","octave","noteOn","statusByte","string","matches","props","Message","data","statusByte","MidiEvent","_MidiEvent","noteName","noteOn","triggeredAt","note","Note","Message","cc","value","message","voiceNo","newEvent","Module","engineId","params","id","name","moduleType","voiceNo","audioNodeConstructor","props","uuidv4","InputCollection","OutputCollection","value","updatedValue","key","propValue","result","hookType","hookName","upperFirst","hook","audioModule","from","to","output","input","callback","_time","note","_triggeredAt","n","_event","midiEvent","triggeredAt","requestAnimationFrame","Engine","uuidv4","Routes","engine","props","id","route","_","sourceIO","destinationIO","source","destination","MidiPortState","MidiDevice","input","context","id","name","state","callback","c","event","message","Message","midiEvent","MidiEvent","MAP_KEYS","Note","computerKeyboardData","ComputerKeyboardInput","context","id","name","state","callback","c","noteOn","event","note","midiEvent","MidiEvent","isNode","isNode","NodeMidiInputPort","portIndex","name","input","state","callback","_deltaTime","message","event","cb","err","NodeMidiAccess","MidiModule","portCount","i","portName","id","portInput","port","_event","_callback","NodeMidiAdapter","midi","midiModule","WebMidiInputPort","input","callback","e","event","cb","WebMidiAccess","midiAccess","port","WebMidiAdapter","err","createMidiAdapter","isNode","NodeMidiAdapter","WebMidiAdapter","normalizeDeviceName","name","normalized","parts","longest","current","extractCoreTokens","tokens","genericWords","token","levenshteinDistance","str1","str2","len1","len2","matrix","i","j","cost","prevRow","currRow","prevCell","diagCell","prevCellInRow","calculateSimilarity","name1","name2","normalized1","normalized2","tokens1","tokens2","maxLen","intersection","x","union","jaccardScore","stringScore","substringScore","findBestMatch","targetName","candidateNames","threshold","bestMatch","candidateName","score","MidiDeviceManager","createMidiAdapter","context","id","name","d","targetName","threshold","deviceEntries","candidateNames","match","findBestMatch","device","callback","input","MidiDevice","err","computerKeyboardDevice","ComputerKeyboardInput","port","listener","assertNever","voiceSchedulerPropSchema","DEFAULT_PROPS","Voice","Module","engineId","params","props","midiEvent","triggeredAt","note","type","noteName","VoiceScheduler","PolyModule","monoModuleConstructor","voice","v","a","b","ConstantSourceNode","constantPropSchema","DEFAULT_PROPS","Constant","Module","engineId","params","props","audioNodeConstructor","context","ConstantSourceNode","value","time","note","triggeredAt","cancelAndHoldAtTime","GainNode","DEFAULT_PROPS","envelopePropSchema","MonoEnvelope","Module","engineId","params","props","audioNodeConstructor","context","audioNode","GainNode","note","triggeredAt","attack","decay","sustain","cancelAndHoldAtTime","release","currentGainValue","Envelope","PolyModule","monoModuleConstructor","BiquadFilterNode","GainNode","gainPropSchema","DEFAULT_PROPS","MonoGain","Module","engineId","params","props","audioNodeConstructor","context","GainNode","value","Gain","PolyModule","monoModuleConstructor","MIN_FREQ","MAX_FREQ","DEFAULT_PROPS","filterPropSchema","MonoFilter","Module","engineId","params","props","audioNodeConstructor","context","BiquadFilterNode","MonoGain","createModule","value","Filter","PolyModule","monoModuleConstructor","AnalyserNode","inspectorPropSchema","DEFAULT_PROPS","Inspector","Module","engineId","params","props","audioNodeConstructor","context","AnalyserNode","value","DEFAULT_PROPS","masterPropSchema","Master","Module","engineId","params","props","audioNodeConstructor","context","MidiMappingMode","midiMapperPropSchema","DEFAULT_PROPS","getMidiFromMappedValue","value","midiValue","propSchema","mapping","min","max","exp","threshold","mode","curvedValue","newMidiValue","MidiMapper","Module","engineId","params","props","event","triggeredAt","activePage","m","_triggeredAt","propName","mappedModule","moduleSchemas","mappedValue","currentValue","normalizedMidi","steps","optionIndex","clampedIndex","hasGlobalAutoAssign","autoAssign","hasPageAutoAssign","updatedGlobalMappings","updatedPageMappings","updatedPages","page","index","midiSelectorPropSchema","DEFAULT_PROPS","MidiSelector","Module","engineId","params","props","midiDevice","fuzzyMatch","value","midiEvent","dbToGain","GainNode","OscillatorNode","LOW_GAIN","OscillatorWave","oscillatorPropSchema","DEFAULT_PROPS","MonoOscillator","Module","engineId","params","props","audioNodeConstructor","context","OscillatorNode","GainNode","dbToGain","value","lowGain","time","note","triggeredAt","lastNote","frequency","coarse","octave","fine","actionAt","Oscillator","PolyModule","monoModuleConstructor","audioModule","assertNever","filterProcessorURL","FilterProcessor","inputs","outputs","parameters","input","output","cutoff","resonance","channelNum","inputChannel","outputChannel","i","s","cutoffHz","clampedHz","normalizedCutoff","c","resonanceValue","mrc","scaleProcessorURL","ScaleProcessor","inputs","outputs","parameters","input","output","minValues","maxValues","currentValues","firstInput","outputChannel","current","channel","inputChannel","i","x","min","max","loadProcessors","context","scaleProcessorURL","filterProcessorURL","newAudioWorklet","worklet","assertNever","scalePropSchema","DEFAULT_PROPS","Scale","Module","engineId","params","props","audioNodeConstructor","context","newAudioWorklet","value","stepSequencerPropSchema","DEFAULT_PROPS","StepSequencer","Module","engineId","params","props","StereoPannerNode","stereoPannerPropSchema","DEFAULT_PROPS","MonoStereoPanner","Module","engineId","params","props","audioNodeConstructor","context","StereoPannerNode","value","StereoPanner","PolyModule","monoModuleConstructor","virtualMidiPropSchema","DEFAULT_PROPS","VirtualMidi","Module","engineId","params","props","midiEvent","note","triggerAttack","MidiEvent","name","ModuleType","moduleSchemas","oscillatorPropSchema","gainPropSchema","masterPropSchema","midiSelectorPropSchema","envelopePropSchema","filterPropSchema","scalePropSchema","stereoPannerPropSchema","inspectorPropSchema","constantPropSchema","midiMapperPropSchema","virtualMidiPropSchema","stepSequencerPropSchema","voiceSchedulerPropSchema","createModule","engineId","params","Oscillator","Gain","Master","MidiSelector","Envelope","Filter","Scale","StereoPanner","Inspector","Constant","MidiMapper","VirtualMidi","StepSequencer","VoiceScheduler","assertNever","Engine","_Engine","id","engine","assertDefined","data","bpm","timeSignature","modules","routes","context","Context","m","r","uuidv4","Transport","_start","_end","_event","_ticks","_actionAt","Routes","MidiDeviceManager","loadProcessors","params","module","createModule","updates","pick","PolyModule","props","source","destination","output","input","value","moduleId","ioName","type","name","threshold","callback","noteName","virtualMidi","MidiEvent","actionAt","TransportState","Context"]}
|