@blibliki/engine 0.1.27 → 0.3.1
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/README.md +252 -76
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +765 -0
- package/dist/index.d.ts +765 -0
- package/dist/index.js +2 -19484
- package/dist/index.js.map +1 -0
- package/package.json +16 -27
- package/src/Engine.ts +158 -177
- package/src/core/IO/AudioIO.ts +72 -0
- package/src/core/IO/Base.ts +118 -0
- package/src/core/IO/Collection.ts +123 -47
- package/src/core/IO/MidiIO.ts +43 -0
- package/src/core/IO/PolyAudioIO.ts +115 -0
- package/src/core/IO/index.ts +7 -61
- package/src/core/Note/frequencyTable.ts +144 -144
- package/src/core/Note/index.ts +49 -59
- package/src/core/Route.ts +79 -0
- package/src/core/Timing/Scheduler.ts +37 -0
- package/src/core/Timing/Time.ts +103 -0
- package/src/core/Timing/Transport.ts +104 -0
- package/src/core/Timing/index.ts +16 -0
- package/src/core/index.ts +36 -0
- package/src/core/midi/{ComputerKeyboardInput.ts → ComputerKeyboardDevice.ts} +31 -11
- package/src/core/midi/MidiDevice.ts +38 -31
- package/src/core/midi/MidiDeviceManager.ts +54 -55
- package/src/core/midi/MidiEvent.ts +36 -60
- package/src/core/module/Module.ts +233 -0
- package/src/core/module/PolyModule.ts +246 -0
- package/src/core/module/VoiceScheduler.ts +121 -0
- package/src/core/module/index.ts +3 -0
- package/src/core/schema.ts +41 -0
- package/src/index.ts +31 -9
- package/src/modules/BiquadFilter.ts +162 -0
- package/src/modules/Constant.ts +72 -0
- package/src/modules/Envelope.ts +178 -0
- package/src/modules/Filter.ts +109 -104
- package/src/modules/Gain.ts +78 -0
- package/src/modules/Inspector.ts +59 -0
- package/src/modules/Master.ts +18 -21
- package/src/modules/MidiSelector.ts +50 -50
- package/src/modules/Oscillator.ts +203 -158
- package/src/modules/Scale.ts +79 -0
- package/src/modules/StepSequencer.ts +61 -0
- package/src/modules/VirtualMidi.ts +33 -49
- package/src/modules/index.ts +159 -74
- package/src/nodePolyfill.ts +25 -0
- package/src/processors/filter-processor.ts +82 -0
- package/src/processors/index.ts +28 -0
- package/src/processors/scale-processor.ts +81 -0
- package/dist/index.umd.cjs +0 -227
- package/dist/src/Engine.d.ts +0 -83
- package/dist/src/core/IO/AudioNode.d.ts +0 -36
- package/dist/src/core/IO/Collection.d.ts +0 -14
- package/dist/src/core/IO/ForwardNode/Base.d.ts +0 -19
- package/dist/src/core/IO/ForwardNode/index.d.ts +0 -28
- package/dist/src/core/IO/MidiNode.d.ts +0 -31
- package/dist/src/core/IO/Node.d.ts +0 -41
- package/dist/src/core/IO/index.d.ts +0 -22
- package/dist/src/core/Module/MonoModule.d.ts +0 -68
- package/dist/src/core/Module/PolyModule.d.ts +0 -62
- package/dist/src/core/Module/index.d.ts +0 -7
- package/dist/src/core/Note/frequencyTable.d.ts +0 -4
- package/dist/src/core/Note/index.d.ts +0 -28
- package/dist/src/core/midi/ComputerKeyboardInput.d.ts +0 -12
- package/dist/src/core/midi/MidiDevice.d.ts +0 -30
- package/dist/src/core/midi/MidiDeviceManager.d.ts +0 -15
- package/dist/src/core/midi/MidiEvent.d.ts +0 -22
- package/dist/src/core/midi/index.d.ts +0 -5
- package/dist/src/index.d.ts +0 -9
- package/dist/src/main.d.ts +0 -0
- package/dist/src/modules/BitCrusher.d.ts +0 -17
- package/dist/src/modules/Delay.d.ts +0 -20
- package/dist/src/modules/Distortion.d.ts +0 -17
- package/dist/src/modules/Effect.d.ts +0 -20
- package/dist/src/modules/Envelope/AmpEnvelope.d.ts +0 -19
- package/dist/src/modules/Envelope/Base.d.ts +0 -67
- package/dist/src/modules/Envelope/FreqEnvelope.d.ts +0 -26
- package/dist/src/modules/Envelope/index.d.ts +0 -3
- package/dist/src/modules/Filter.d.ts +0 -43
- package/dist/src/modules/LFO.d.ts +0 -45
- package/dist/src/modules/Master.d.ts +0 -12
- package/dist/src/modules/MidiSelector.d.ts +0 -22
- package/dist/src/modules/Oscillator.d.ts +0 -56
- package/dist/src/modules/Reverb.d.ts +0 -20
- package/dist/src/modules/Sequencer.d.ts +0 -43
- package/dist/src/modules/VirtualMidi.d.ts +0 -33
- package/dist/src/modules/VoiceScheduler.d.ts +0 -45
- package/dist/src/modules/Volume.d.ts +0 -27
- package/dist/src/modules/index.d.ts +0 -18
- package/dist/src/routes.d.ts +0 -19
- package/dist/src/types.d.ts +0 -5
- package/dist/src/utils.d.ts +0 -1
- package/dist/test/MockingModules.d.ts +0 -22
- package/dist/test/Module/Oscillator.test.d.ts +0 -1
- package/dist/test/core/IO.test.d.ts +0 -1
- package/src/core/IO/AudioNode.ts +0 -82
- package/src/core/IO/ForwardNode/Base.ts +0 -99
- package/src/core/IO/ForwardNode/index.ts +0 -60
- package/src/core/IO/MidiNode.ts +0 -67
- package/src/core/IO/Node.ts +0 -118
- package/src/core/Module/MonoModule.ts +0 -219
- package/src/core/Module/PolyModule.ts +0 -218
- package/src/core/Module/index.ts +0 -15
- package/src/core/midi/index.ts +0 -5
- package/src/main.ts +0 -1
- package/src/modules/BitCrusher.ts +0 -45
- package/src/modules/Delay.ts +0 -53
- package/src/modules/Distortion.ts +0 -45
- package/src/modules/Effect.ts +0 -46
- package/src/modules/Envelope/AmpEnvelope.ts +0 -23
- package/src/modules/Envelope/Base.ts +0 -176
- package/src/modules/Envelope/FreqEnvelope.ts +0 -64
- package/src/modules/Envelope/index.ts +0 -3
- package/src/modules/LFO.ts +0 -149
- package/src/modules/Reverb.ts +0 -53
- package/src/modules/Sequencer.ts +0 -178
- package/src/modules/VoiceScheduler.ts +0 -145
- package/src/modules/Volume.ts +0 -72
- package/src/routes.ts +0 -49
- package/src/types.ts +0 -3
- package/src/utils.ts +0 -18
- package/src/vite-env.d.ts +0 -1
package/src/modules/index.ts
CHANGED
|
@@ -1,84 +1,169 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import {
|
|
1
|
+
import { assertNever } from "@blibliki/utils";
|
|
2
|
+
import { IModule, Module, PropSchema } from "@/core";
|
|
3
|
+
import { IPolyModuleConstructor } from "@/core/module/PolyModule";
|
|
4
|
+
import VoiceScheduler, {
|
|
5
|
+
IVoiceSchedulerProps,
|
|
6
|
+
voiceSchedulerPropSchema,
|
|
7
|
+
} from "@/core/module/VoiceScheduler";
|
|
8
|
+
import BiquadFilter, {
|
|
9
|
+
biquadFilterPropSchema,
|
|
10
|
+
IBiquadFilterProps,
|
|
11
|
+
} from "./BiquadFilter";
|
|
12
|
+
import Constant, { constantPropSchema, IConstantProps } from "./Constant";
|
|
13
|
+
import Envelope, { envelopePropSchema, IEnvelopeProps } from "./Envelope";
|
|
14
|
+
import Filter, { filterPropSchema, IFilterProps } from "./Filter";
|
|
15
|
+
import Gain, { gainPropSchema, IGainProps } from "./Gain";
|
|
16
|
+
import Inspector, { IInspectorProps, inspectorPropSchema } from "./Inspector";
|
|
17
|
+
import Master, { IMasterProps, masterPropSchema } from "./Master";
|
|
18
|
+
import MidiSelector, {
|
|
19
|
+
IMidiSelectorProps,
|
|
20
|
+
midiSelectorPropSchema,
|
|
21
|
+
} from "./MidiSelector";
|
|
22
|
+
import Oscillator, {
|
|
23
|
+
IOscillatorProps,
|
|
24
|
+
oscillatorPropSchema,
|
|
25
|
+
} from "./Oscillator";
|
|
26
|
+
import Scale, { IScaleProps, scalePropSchema } from "./Scale";
|
|
27
|
+
import StepSequencer, {
|
|
28
|
+
IStepSequencerProps,
|
|
29
|
+
stepSequencerPropSchema,
|
|
30
|
+
} from "./StepSequencer";
|
|
31
|
+
import VirtualMidi, {
|
|
32
|
+
IVirtualMidiProps,
|
|
33
|
+
virtualMidiPropSchema,
|
|
34
|
+
} from "./VirtualMidi";
|
|
16
35
|
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
36
|
+
export enum ModuleType {
|
|
37
|
+
Master = "Master",
|
|
38
|
+
Oscillator = "Oscillator",
|
|
39
|
+
Gain = "Gain",
|
|
40
|
+
MidiSelector = "MidiSelector",
|
|
41
|
+
Envelope = "Envelope",
|
|
42
|
+
Filter = "Filter",
|
|
43
|
+
BiquadFilter = "BiquadFilter",
|
|
44
|
+
Scale = "Scale",
|
|
45
|
+
Inspector = "Inspector",
|
|
46
|
+
Constant = "Constant",
|
|
47
|
+
VirtualMidi = "VirtualMidi",
|
|
48
|
+
StepSequencer = "StepSequencer",
|
|
49
|
+
VoiceScheduler = "VoiceScheduler",
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type ModuleTypeToPropsMapping = {
|
|
53
|
+
[ModuleType.Oscillator]: IOscillatorProps;
|
|
54
|
+
[ModuleType.Gain]: IGainProps;
|
|
55
|
+
[ModuleType.Master]: IMasterProps;
|
|
56
|
+
[ModuleType.MidiSelector]: IMidiSelectorProps;
|
|
57
|
+
[ModuleType.Envelope]: IEnvelopeProps;
|
|
58
|
+
[ModuleType.Filter]: IFilterProps;
|
|
59
|
+
[ModuleType.BiquadFilter]: IBiquadFilterProps;
|
|
60
|
+
[ModuleType.Scale]: IScaleProps;
|
|
61
|
+
[ModuleType.Inspector]: IInspectorProps;
|
|
62
|
+
[ModuleType.Constant]: IConstantProps;
|
|
63
|
+
[ModuleType.VirtualMidi]: IVirtualMidiProps;
|
|
64
|
+
[ModuleType.StepSequencer]: IStepSequencerProps;
|
|
65
|
+
[ModuleType.VoiceScheduler]: IVoiceSchedulerProps;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export type ModuleTypeToModuleMapping = {
|
|
69
|
+
[ModuleType.Oscillator]: Oscillator;
|
|
70
|
+
[ModuleType.Gain]: Gain;
|
|
71
|
+
[ModuleType.Master]: Master;
|
|
72
|
+
[ModuleType.MidiSelector]: MidiSelector;
|
|
73
|
+
[ModuleType.Envelope]: Envelope;
|
|
74
|
+
[ModuleType.Filter]: Filter;
|
|
75
|
+
[ModuleType.BiquadFilter]: BiquadFilter;
|
|
76
|
+
[ModuleType.Scale]: Scale;
|
|
77
|
+
[ModuleType.Inspector]: Inspector;
|
|
78
|
+
[ModuleType.Constant]: Constant;
|
|
79
|
+
[ModuleType.VirtualMidi]: VirtualMidi;
|
|
80
|
+
[ModuleType.StepSequencer]: StepSequencer;
|
|
81
|
+
[ModuleType.VoiceScheduler]: VoiceScheduler;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const moduleSchemas: {
|
|
85
|
+
[K in ModuleType]: PropSchema<Partial<ModuleTypeToPropsMapping[K]>>;
|
|
86
|
+
} = {
|
|
87
|
+
[ModuleType.Oscillator]: oscillatorPropSchema,
|
|
88
|
+
[ModuleType.Gain]: gainPropSchema,
|
|
89
|
+
[ModuleType.Master]: masterPropSchema,
|
|
90
|
+
[ModuleType.MidiSelector]: midiSelectorPropSchema,
|
|
91
|
+
[ModuleType.Envelope]: envelopePropSchema,
|
|
92
|
+
[ModuleType.Filter]: filterPropSchema,
|
|
93
|
+
[ModuleType.BiquadFilter]: biquadFilterPropSchema,
|
|
94
|
+
[ModuleType.Scale]: scalePropSchema,
|
|
95
|
+
[ModuleType.Inspector]: inspectorPropSchema,
|
|
96
|
+
[ModuleType.Constant]: constantPropSchema,
|
|
97
|
+
[ModuleType.VirtualMidi]: virtualMidiPropSchema,
|
|
98
|
+
[ModuleType.StepSequencer]: stepSequencerPropSchema,
|
|
99
|
+
[ModuleType.VoiceScheduler]: voiceSchedulerPropSchema,
|
|
100
|
+
};
|
|
24
101
|
|
|
25
|
-
export {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
102
|
+
export type { IOscillator } from "./Oscillator";
|
|
103
|
+
export { OscillatorWave } from "./Oscillator";
|
|
104
|
+
export type { IGain } from "./Gain";
|
|
105
|
+
export type { IMaster } from "./Master";
|
|
106
|
+
export type { IMidiSelector } from "./MidiSelector";
|
|
107
|
+
export type {
|
|
108
|
+
IStepSequencer,
|
|
109
|
+
IStepSequencerProps,
|
|
110
|
+
ISequence,
|
|
111
|
+
} from "./StepSequencer";
|
|
31
112
|
|
|
32
|
-
export
|
|
113
|
+
export type AnyModule = Module<ModuleType>;
|
|
114
|
+
export type IAnyModule = IModule<ModuleType>;
|
|
115
|
+
|
|
116
|
+
export type ICreateModule<T extends ModuleType> = {
|
|
33
117
|
id?: string;
|
|
34
118
|
name: string;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
119
|
+
moduleType: T;
|
|
120
|
+
props: Partial<ModuleTypeToPropsMapping[T]>;
|
|
121
|
+
};
|
|
39
122
|
|
|
40
|
-
export
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
123
|
+
export type ModuleParams = {
|
|
124
|
+
[K in ModuleType]: K extends
|
|
125
|
+
| ModuleType.Oscillator
|
|
126
|
+
| ModuleType.Gain
|
|
127
|
+
| ModuleType.Envelope
|
|
128
|
+
| ModuleType.Filter
|
|
129
|
+
| ModuleType.BiquadFilter
|
|
130
|
+
| ModuleType.VoiceScheduler
|
|
131
|
+
? IPolyModuleConstructor<K>
|
|
132
|
+
: ICreateModule<K>;
|
|
133
|
+
}[ModuleType];
|
|
46
134
|
|
|
47
|
-
function
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return Sequencer;
|
|
79
|
-
case LFO.moduleName:
|
|
80
|
-
return LFO;
|
|
135
|
+
export function createModule(
|
|
136
|
+
engineId: string,
|
|
137
|
+
params: ModuleParams,
|
|
138
|
+
): ModuleTypeToModuleMapping[keyof ModuleTypeToModuleMapping] {
|
|
139
|
+
switch (params.moduleType) {
|
|
140
|
+
case ModuleType.Oscillator:
|
|
141
|
+
return new Oscillator(engineId, params);
|
|
142
|
+
case ModuleType.Gain:
|
|
143
|
+
return new Gain(engineId, params);
|
|
144
|
+
case ModuleType.Master:
|
|
145
|
+
return new Master(engineId, params);
|
|
146
|
+
case ModuleType.MidiSelector:
|
|
147
|
+
return new MidiSelector(engineId, params);
|
|
148
|
+
case ModuleType.Envelope:
|
|
149
|
+
return new Envelope(engineId, params);
|
|
150
|
+
case ModuleType.Filter:
|
|
151
|
+
return new Filter(engineId, params);
|
|
152
|
+
case ModuleType.BiquadFilter:
|
|
153
|
+
return new BiquadFilter(engineId, params);
|
|
154
|
+
case ModuleType.Scale:
|
|
155
|
+
return new Scale(engineId, params);
|
|
156
|
+
case ModuleType.Inspector:
|
|
157
|
+
return new Inspector(engineId, params);
|
|
158
|
+
case ModuleType.Constant:
|
|
159
|
+
return new Constant(engineId, params);
|
|
160
|
+
case ModuleType.VirtualMidi:
|
|
161
|
+
return new VirtualMidi(engineId, params);
|
|
162
|
+
case ModuleType.StepSequencer:
|
|
163
|
+
return new StepSequencer(engineId, params);
|
|
164
|
+
case ModuleType.VoiceScheduler:
|
|
165
|
+
return new VoiceScheduler(engineId, params);
|
|
81
166
|
default:
|
|
82
|
-
|
|
167
|
+
assertNever(params);
|
|
83
168
|
}
|
|
84
169
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AudioContext,
|
|
3
|
+
AnalyserNode,
|
|
4
|
+
AudioParam,
|
|
5
|
+
AudioNode,
|
|
6
|
+
AudioWorkletNode,
|
|
7
|
+
BiquadFilterNode,
|
|
8
|
+
GainNode,
|
|
9
|
+
OfflineAudioContext,
|
|
10
|
+
OscillatorNode,
|
|
11
|
+
ConstantSourceNode,
|
|
12
|
+
WaveShaperNode,
|
|
13
|
+
} from "node-web-audio-api";
|
|
14
|
+
|
|
15
|
+
globalThis.AudioContext = AudioContext;
|
|
16
|
+
globalThis.OfflineAudioContext = OfflineAudioContext;
|
|
17
|
+
globalThis.AudioParam = AudioParam;
|
|
18
|
+
globalThis.AudioNode = AudioNode;
|
|
19
|
+
globalThis.AudioWorkletNode = AudioWorkletNode;
|
|
20
|
+
globalThis.AnalyserNode = AnalyserNode;
|
|
21
|
+
globalThis.GainNode = GainNode;
|
|
22
|
+
globalThis.OscillatorNode = OscillatorNode;
|
|
23
|
+
globalThis.BiquadFilterNode = BiquadFilterNode;
|
|
24
|
+
globalThis.ConstantSourceNode = ConstantSourceNode;
|
|
25
|
+
globalThis.WaveShaperNode = WaveShaperNode;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export const filterProcessorURL = URL.createObjectURL(
|
|
2
|
+
new Blob(
|
|
3
|
+
[
|
|
4
|
+
"(",
|
|
5
|
+
(() => {
|
|
6
|
+
class FilterProcessor extends AudioWorkletProcessor {
|
|
7
|
+
s0: number;
|
|
8
|
+
s1: number;
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
super();
|
|
12
|
+
this.s0 = 0;
|
|
13
|
+
this.s1 = 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static get parameterDescriptors() {
|
|
17
|
+
return [
|
|
18
|
+
{
|
|
19
|
+
name: "cutoff",
|
|
20
|
+
defaultValue: 1000,
|
|
21
|
+
minValue: 20,
|
|
22
|
+
maxValue: 20000,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: "resonance",
|
|
26
|
+
defaultValue: 0.0,
|
|
27
|
+
minValue: 0.0,
|
|
28
|
+
maxValue: 4.0,
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
process(
|
|
34
|
+
inputs: Float32Array[][],
|
|
35
|
+
outputs: Float32Array[][],
|
|
36
|
+
parameters: Record<string, Float32Array>,
|
|
37
|
+
): boolean {
|
|
38
|
+
const input = inputs[0];
|
|
39
|
+
const output = outputs[0];
|
|
40
|
+
|
|
41
|
+
const cutoff = parameters.cutoff;
|
|
42
|
+
const resonance = parameters.resonance;
|
|
43
|
+
|
|
44
|
+
for (let channelNum = 0; channelNum < input.length; channelNum++) {
|
|
45
|
+
const inputChannel = input[channelNum];
|
|
46
|
+
const outputChannel = output[channelNum];
|
|
47
|
+
|
|
48
|
+
for (let i = 0; i < inputChannel.length; i++) {
|
|
49
|
+
const s = inputChannel[i];
|
|
50
|
+
// Convert Hz to normalized frequency using logarithmic scale
|
|
51
|
+
// This better matches human hearing perception
|
|
52
|
+
const cutoffHz = cutoff.length > 1 ? cutoff[i] : cutoff[0];
|
|
53
|
+
const clampedHz = Math.max(20, Math.min(20000, cutoffHz));
|
|
54
|
+
const normalizedCutoff =
|
|
55
|
+
Math.log(clampedHz / 20) / Math.log(20000 / 20);
|
|
56
|
+
const c = Math.pow(0.5, (1 - normalizedCutoff) / 0.125);
|
|
57
|
+
const r = Math.pow(
|
|
58
|
+
0.5,
|
|
59
|
+
((resonance.length > 1 ? resonance[i] : resonance[0]) +
|
|
60
|
+
0.125) /
|
|
61
|
+
0.125,
|
|
62
|
+
);
|
|
63
|
+
const mrc = 1 - r * c;
|
|
64
|
+
|
|
65
|
+
this.s0 = mrc * this.s0 - c * this.s1 + c * s;
|
|
66
|
+
this.s1 = mrc * this.s1 + c * this.s0;
|
|
67
|
+
|
|
68
|
+
outputChannel[i] = this.s1;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
registerProcessor("filter-processor", FilterProcessor);
|
|
77
|
+
}).toString(),
|
|
78
|
+
")()",
|
|
79
|
+
],
|
|
80
|
+
{ type: "application/javascript" },
|
|
81
|
+
),
|
|
82
|
+
);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { assertNever } from "@blibliki/utils";
|
|
2
|
+
import { IAnyAudioContext } from "@/core";
|
|
3
|
+
import { filterProcessorURL } from "./filter-processor";
|
|
4
|
+
import { scaleProcessorURL } from "./scale-processor";
|
|
5
|
+
|
|
6
|
+
export enum CustomWorklet {
|
|
7
|
+
ScaleProcessor = "ScaleProcessor",
|
|
8
|
+
FilterProcessor = "FilterProcessor",
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function loadProcessors(context: IAnyAudioContext) {
|
|
12
|
+
await context.audioWorklet.addModule(scaleProcessorURL);
|
|
13
|
+
await context.audioWorklet.addModule(filterProcessorURL);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function newAudioWorklet(
|
|
17
|
+
context: IAnyAudioContext,
|
|
18
|
+
worklet: CustomWorklet,
|
|
19
|
+
) {
|
|
20
|
+
switch (worklet) {
|
|
21
|
+
case CustomWorklet.ScaleProcessor:
|
|
22
|
+
return new AudioWorkletNode(context, "scale-processor");
|
|
23
|
+
case CustomWorklet.FilterProcessor:
|
|
24
|
+
return new AudioWorkletNode(context, "filter-processor");
|
|
25
|
+
default:
|
|
26
|
+
assertNever(worklet);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export const scaleProcessorURL = URL.createObjectURL(
|
|
2
|
+
new Blob(
|
|
3
|
+
[
|
|
4
|
+
"(",
|
|
5
|
+
(() => {
|
|
6
|
+
class ScaleProcessor extends AudioWorkletProcessor {
|
|
7
|
+
static get parameterDescriptors() {
|
|
8
|
+
return [
|
|
9
|
+
{
|
|
10
|
+
name: "min",
|
|
11
|
+
defaultValue: 1e-10,
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: "max",
|
|
15
|
+
defaultValue: 1,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: "current",
|
|
19
|
+
defaultValue: 0.5,
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
process(
|
|
25
|
+
inputs: Float32Array[][],
|
|
26
|
+
outputs: Float32Array[][],
|
|
27
|
+
parameters: Record<string, Float32Array>,
|
|
28
|
+
) {
|
|
29
|
+
const input = inputs[0];
|
|
30
|
+
const output = outputs[0];
|
|
31
|
+
|
|
32
|
+
const minValues = parameters.min;
|
|
33
|
+
const maxValues = parameters.max;
|
|
34
|
+
const currentValues = parameters.current;
|
|
35
|
+
|
|
36
|
+
if (!input.length || input[0].length === 0) {
|
|
37
|
+
for (const outputChannel of output) {
|
|
38
|
+
const current =
|
|
39
|
+
parameters.current.length > 1
|
|
40
|
+
? parameters.current[0]
|
|
41
|
+
: parameters.current[0];
|
|
42
|
+
|
|
43
|
+
outputChannel.fill(current);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (let channel = 0; channel < input.length; channel++) {
|
|
50
|
+
const inputChannel = input[channel];
|
|
51
|
+
const outputChannel = output[channel];
|
|
52
|
+
|
|
53
|
+
for (let i = 0; i < inputChannel.length; i++) {
|
|
54
|
+
const x = inputChannel[i];
|
|
55
|
+
|
|
56
|
+
const min = minValues.length > 1 ? minValues[i] : minValues[0];
|
|
57
|
+
const max = maxValues.length > 1 ? maxValues[i] : maxValues[0];
|
|
58
|
+
const current =
|
|
59
|
+
currentValues.length > 1
|
|
60
|
+
? currentValues[i]
|
|
61
|
+
: currentValues[0];
|
|
62
|
+
|
|
63
|
+
if (x < 0) {
|
|
64
|
+
outputChannel[i] = current * Math.pow(min / current, -x);
|
|
65
|
+
} else {
|
|
66
|
+
outputChannel[i] = current * Math.pow(max / current, x);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
registerProcessor("scale-processor", ScaleProcessor);
|
|
76
|
+
}).toString(),
|
|
77
|
+
")()",
|
|
78
|
+
],
|
|
79
|
+
{ type: "application/javascript" },
|
|
80
|
+
),
|
|
81
|
+
);
|