@blibliki/engine 0.5.2 → 0.9.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/README.md +22 -2
- package/dist/index.d.ts +501 -107
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/Engine.ts +46 -29
- package/src/core/index.ts +11 -2
- package/src/core/midi/BaseMidiDevice.ts +47 -0
- package/src/core/midi/ComputerKeyboardDevice.ts +2 -1
- package/src/core/midi/MidiDeviceManager.ts +125 -31
- package/src/core/midi/{MidiDevice.ts → MidiInputDevice.ts} +6 -30
- package/src/core/midi/MidiOutputDevice.ts +23 -0
- package/src/core/midi/adapters/NodeMidiAdapter.ts +99 -13
- package/src/core/midi/adapters/WebMidiAdapter.ts +68 -10
- package/src/core/midi/adapters/types.ts +13 -4
- package/src/core/midi/controllers/BaseController.ts +14 -0
- package/src/core/module/Module.ts +121 -13
- package/src/core/module/PolyModule.ts +36 -0
- package/src/core/module/VoiceScheduler.ts +150 -10
- package/src/core/module/index.ts +9 -4
- package/src/index.ts +27 -3
- package/src/modules/Chorus.ts +222 -0
- package/src/modules/Constant.ts +2 -2
- package/src/modules/Delay.ts +347 -0
- package/src/modules/Distortion.ts +182 -0
- package/src/modules/Envelope.ts +158 -92
- package/src/modules/Filter.ts +7 -7
- package/src/modules/Gain.ts +2 -2
- package/src/modules/LFO.ts +287 -0
- package/src/modules/LegacyEnvelope.ts +146 -0
- package/src/modules/{MidiSelector.ts → MidiInput.ts} +26 -19
- package/src/modules/MidiMapper.ts +59 -4
- package/src/modules/MidiOutput.ts +121 -0
- package/src/modules/Noise.ts +259 -0
- package/src/modules/Oscillator.ts +9 -3
- package/src/modules/Reverb.ts +379 -0
- package/src/modules/Scale.ts +49 -4
- package/src/modules/StepSequencer.ts +410 -22
- package/src/modules/StereoPanner.ts +1 -1
- package/src/modules/index.ts +142 -29
- package/src/processors/custom-envelope-processor.ts +125 -0
- package/src/processors/index.ts +10 -0
- package/src/processors/lfo-processor.ts +123 -0
- package/src/processors/scale-processor.ts +42 -5
- package/src/utils/WetDryMixer.ts +123 -0
- package/src/utils/expandPatternSequence.ts +18 -0
- package/src/utils/index.ts +2 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { Context } from "@blibliki/utils";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* WetDryMixer - Reusable wet/dry signal mixer for audio effects
|
|
5
|
+
*
|
|
6
|
+
* Provides equal-power crossfading between dry (unprocessed) and wet (processed) signals.
|
|
7
|
+
* Used by effects modules to blend the original signal with the effect output.
|
|
8
|
+
*
|
|
9
|
+
* Audio Graph:
|
|
10
|
+
* ```
|
|
11
|
+
* INPUT
|
|
12
|
+
* |
|
|
13
|
+
* +------------+------------+
|
|
14
|
+
* | |
|
|
15
|
+
* [DryGainNode] [WetGainNode]
|
|
16
|
+
* (cos(mix*π/2)) (sin(mix*π/2))
|
|
17
|
+
* | |
|
|
18
|
+
* +------------+------------+
|
|
19
|
+
* |
|
|
20
|
+
* [OutputNode]
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* Usage:
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const mixer = new WetDryMixer(context);
|
|
26
|
+
*
|
|
27
|
+
* // Connect input to mixer
|
|
28
|
+
* mixer.connectInput(sourceNode);
|
|
29
|
+
*
|
|
30
|
+
* // Get wet input node and connect effect chain
|
|
31
|
+
* const wetInput = mixer.getWetInput();
|
|
32
|
+
* sourceNode.connect(effectNode);
|
|
33
|
+
* effectNode.connect(wetInput);
|
|
34
|
+
*
|
|
35
|
+
* // Set mix amount
|
|
36
|
+
* mixer.setMix(0.5); // 50/50 blend
|
|
37
|
+
*
|
|
38
|
+
* // Connect output
|
|
39
|
+
* const output = mixer.getOutput();
|
|
40
|
+
* output.connect(destination);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export class WetDryMixer {
|
|
44
|
+
private dryGainNode: GainNode;
|
|
45
|
+
private wetGainNode: GainNode;
|
|
46
|
+
private outputNode: GainNode;
|
|
47
|
+
|
|
48
|
+
constructor(context: Context) {
|
|
49
|
+
const audioContext = context.audioContext;
|
|
50
|
+
|
|
51
|
+
// Create nodes
|
|
52
|
+
this.dryGainNode = audioContext.createGain();
|
|
53
|
+
this.wetGainNode = audioContext.createGain();
|
|
54
|
+
this.outputNode = audioContext.createGain();
|
|
55
|
+
|
|
56
|
+
// Initialize gains
|
|
57
|
+
this.dryGainNode.gain.value = 1; // Full dry initially
|
|
58
|
+
this.wetGainNode.gain.value = 0; // No wet initially
|
|
59
|
+
this.outputNode.gain.value = 1; // Unity output
|
|
60
|
+
|
|
61
|
+
// Connect to output
|
|
62
|
+
this.dryGainNode.connect(this.outputNode);
|
|
63
|
+
this.wetGainNode.connect(this.outputNode);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Connect an audio source to the dry path.
|
|
68
|
+
* The source should also be connected separately to the wet path processing.
|
|
69
|
+
*/
|
|
70
|
+
connectInput(source: AudioNode): void {
|
|
71
|
+
source.connect(this.dryGainNode);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get the wet input node to connect your effect chain to.
|
|
76
|
+
* Connect your effect output to this node.
|
|
77
|
+
*/
|
|
78
|
+
getWetInput(): GainNode {
|
|
79
|
+
return this.wetGainNode;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get the dry input node (for special routing needs).
|
|
84
|
+
*/
|
|
85
|
+
getDryInput(): GainNode {
|
|
86
|
+
return this.dryGainNode;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get the output node to connect to destination.
|
|
91
|
+
*/
|
|
92
|
+
getOutput(): GainNode {
|
|
93
|
+
return this.outputNode;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Set the mix amount between dry and wet signals.
|
|
98
|
+
* Uses equal-power crossfade to maintain constant perceived loudness.
|
|
99
|
+
*
|
|
100
|
+
* @param mix - Mix amount (0-1)
|
|
101
|
+
* - 0 = 100% dry (no effect)
|
|
102
|
+
* - 0.5 = 50/50 blend
|
|
103
|
+
* - 1 = 100% wet (full effect)
|
|
104
|
+
*/
|
|
105
|
+
setMix(mix: number): void {
|
|
106
|
+
// Equal-power crossfade
|
|
107
|
+
// This maintains constant perceived loudness across all mix values
|
|
108
|
+
const dryGain = Math.cos((mix * Math.PI) / 2);
|
|
109
|
+
const wetGain = Math.sin((mix * Math.PI) / 2);
|
|
110
|
+
|
|
111
|
+
this.dryGainNode.gain.value = dryGain;
|
|
112
|
+
this.wetGainNode.gain.value = wetGain;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Disconnect all nodes (cleanup).
|
|
117
|
+
*/
|
|
118
|
+
disconnect(): void {
|
|
119
|
+
this.dryGainNode.disconnect();
|
|
120
|
+
this.wetGainNode.disconnect();
|
|
121
|
+
this.outputNode.disconnect();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function expandPatternSequence(input: string): string[] {
|
|
2
|
+
const result: string[] = [];
|
|
3
|
+
let num = "";
|
|
4
|
+
|
|
5
|
+
for (const ch of input) {
|
|
6
|
+
if (ch >= "0" && ch <= "9") {
|
|
7
|
+
num += ch;
|
|
8
|
+
} else {
|
|
9
|
+
const count = Number(num);
|
|
10
|
+
for (let i = 0; i < count; i++) {
|
|
11
|
+
result.push(ch);
|
|
12
|
+
}
|
|
13
|
+
num = "";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return result.map((v) => v.toUpperCase());
|
|
18
|
+
}
|