@blibliki/engine 0.1.16 → 0.1.18
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/.eslintrc.js +14 -0
- package/.parcerc +6 -0
- package/README.md +122 -0
- package/dist/main.cjs.js +33 -0
- package/package.json +21 -22
- package/rollup.config.mjs +21 -0
- package/src/Engine.ts +43 -42
- package/src/core/IO/AudioNode.ts +77 -0
- package/src/core/IO/Collection.ts +76 -0
- package/src/core/IO/ForwardNode.ts +192 -0
- package/src/core/IO/MidiNode.ts +67 -0
- package/src/core/IO/Node.ts +117 -0
- package/src/core/IO/index.ts +47 -0
- package/src/core/Module/MonoModule.ts +219 -0
- package/src/core/Module/PolyModule.ts +206 -0
- package/src/core/Module/index.ts +15 -0
- package/src/{Note → core/Note}/index.ts +19 -4
- package/src/{MidiDeviceManager.ts → core/midi/MidiDeviceManager.ts} +20 -15
- package/src/core/midi/MidiEvent.ts +91 -0
- package/src/core/midi/index.ts +5 -0
- package/src/index.ts +8 -12
- package/src/{Module → modules}/BitCrusher.ts +15 -4
- package/src/{Module → modules}/Delay.ts +15 -4
- package/src/{Module → modules}/Distortion.ts +15 -4
- package/src/{Module → modules}/Effect.ts +11 -7
- package/src/modules/Envelope/AmpEnvelope.ts +23 -0
- package/src/{Module → modules}/Envelope/Base.ts +50 -31
- package/src/{Module → modules}/Envelope/FreqEnvelope.ts +18 -23
- package/src/{Module → modules}/Filter.ts +18 -46
- package/src/{Module → modules}/Master.ts +8 -2
- package/src/{Module → modules}/MidiSelector.ts +18 -14
- package/src/{Module → modules}/Oscillator.ts +27 -16
- package/src/{Module → modules}/Reverb.ts +15 -4
- package/src/{Module → modules}/Sequencer.ts +17 -13
- package/src/{Module → modules}/VirtualMidi.ts +16 -12
- package/src/modules/VoiceScheduler.ts +145 -0
- package/src/{Module → modules}/Volume.ts +23 -15
- package/src/{Module → modules}/index.ts +14 -21
- package/src/routes.ts +19 -18
- package/src/types.ts +3 -0
- package/src/utils.ts +18 -0
- package/test/MockingModules.ts +27 -0
- package/test/Module/Oscillator.test.ts +1 -1
- package/test/core/IO.test.ts +172 -0
- package/build/Engine.d.ts +0 -94
- package/build/Engine.js +0 -158
- package/build/Engine.js.map +0 -1
- package/build/MidiDevice.d.ts +0 -25
- package/build/MidiDevice.js +0 -45
- package/build/MidiDevice.js.map +0 -1
- package/build/MidiDeviceManager.d.ts +0 -13
- package/build/MidiDeviceManager.js +0 -59
- package/build/MidiDeviceManager.js.map +0 -1
- package/build/MidiEvent.d.ts +0 -18
- package/build/MidiEvent.js +0 -64
- package/build/MidiEvent.js.map +0 -1
- package/build/Module/Base.d.ts +0 -65
- package/build/Module/Base.js +0 -138
- package/build/Module/Base.js.map +0 -1
- package/build/Module/BitCrusher.d.ts +0 -12
- package/build/Module/BitCrusher.js +0 -22
- package/build/Module/BitCrusher.js.map +0 -1
- package/build/Module/DataSequencer.d.ts +0 -25
- package/build/Module/DataSequencer.js +0 -72
- package/build/Module/DataSequencer.js.map +0 -1
- package/build/Module/Delay.d.ts +0 -15
- package/build/Module/Delay.js +0 -30
- package/build/Module/Delay.js.map +0 -1
- package/build/Module/Distortion.d.ts +0 -12
- package/build/Module/Distortion.js +0 -22
- package/build/Module/Distortion.js.map +0 -1
- package/build/Module/Effect.d.ts +0 -14
- package/build/Module/Effect.js +0 -22
- package/build/Module/Effect.js.map +0 -1
- package/build/Module/Envelope/AmpEnvelope.d.ts +0 -10
- package/build/Module/Envelope/AmpEnvelope.js +0 -14
- package/build/Module/Envelope/AmpEnvelope.js.map +0 -1
- package/build/Module/Envelope/Base.d.ts +0 -47
- package/build/Module/Envelope/Base.js +0 -106
- package/build/Module/Envelope/Base.js.map +0 -1
- package/build/Module/Envelope/FreqEnvelope.d.ts +0 -18
- package/build/Module/Envelope/FreqEnvelope.js +0 -50
- package/build/Module/Envelope/FreqEnvelope.js.map +0 -1
- package/build/Module/Envelope/index.d.ts +0 -3
- package/build/Module/Envelope/index.js +0 -4
- package/build/Module/Envelope/index.js.map +0 -1
- package/build/Module/Filter.d.ts +0 -37
- package/build/Module/Filter.js +0 -100
- package/build/Module/Filter.js.map +0 -1
- package/build/Module/IO.d.ts +0 -39
- package/build/Module/IO.js +0 -59
- package/build/Module/IO.js.map +0 -1
- package/build/Module/Master.d.ts +0 -8
- package/build/Module/Master.js +0 -12
- package/build/Module/Master.js.map +0 -1
- package/build/Module/MidiSelector.d.ts +0 -17
- package/build/Module/MidiSelector.js +0 -50
- package/build/Module/MidiSelector.js.map +0 -1
- package/build/Module/Oscillator.d.ts +0 -45
- package/build/Module/Oscillator.js +0 -136
- package/build/Module/Oscillator.js.map +0 -1
- package/build/Module/PolyModule.d.ts +0 -49
- package/build/Module/PolyModule.js +0 -175
- package/build/Module/PolyModule.js.map +0 -1
- package/build/Module/Reverb.d.ts +0 -15
- package/build/Module/Reverb.js +0 -30
- package/build/Module/Reverb.js.map +0 -1
- package/build/Module/Sequencer.d.ts +0 -38
- package/build/Module/Sequencer.js +0 -131
- package/build/Module/Sequencer.js.map +0 -1
- package/build/Module/VirtualMidi.d.ts +0 -28
- package/build/Module/VirtualMidi.js +0 -53
- package/build/Module/VirtualMidi.js.map +0 -1
- package/build/Module/VoiceScheduler.d.ts +0 -38
- package/build/Module/VoiceScheduler.js +0 -130
- package/build/Module/VoiceScheduler.js.map +0 -1
- package/build/Module/Volume.d.ts +0 -20
- package/build/Module/Volume.js +0 -48
- package/build/Module/Volume.js.map +0 -1
- package/build/Module/index.d.ts +0 -14
- package/build/Module/index.js +0 -66
- package/build/Module/index.js.map +0 -1
- package/build/Note/frequencyTable.d.ts +0 -4
- package/build/Note/frequencyTable.js +0 -146
- package/build/Note/frequencyTable.js.map +0 -1
- package/build/Note/index.d.ts +0 -25
- package/build/Note/index.js +0 -81
- package/build/Note/index.js.map +0 -1
- package/build/index.d.ts +0 -8
- package/build/index.js +0 -5
- package/build/index.js.map +0 -1
- package/build/routes.d.ts +0 -17
- package/build/routes.js +0 -31
- package/build/routes.js.map +0 -1
- package/src/MidiEvent.ts +0 -93
- package/src/Module/Base.ts +0 -220
- package/src/Module/DataSequencer.ts +0 -101
- package/src/Module/Envelope/AmpEnvelope.ts +0 -17
- package/src/Module/IO.ts +0 -85
- package/src/Module/PolyModule.ts +0 -234
- package/src/Module/VoiceScheduler.ts +0 -161
- /package/src/{Note → core/Note}/frequencyTable.ts +0 -0
- /package/src/{MidiDevice.ts → core/midi/MidiDevice.ts} +0 -0
- /package/src/{Module → modules}/Envelope/index.ts +0 -0
package/package.json
CHANGED
|
@@ -1,42 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blibliki/engine",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.18",
|
|
4
|
+
"source": "src/index.ts",
|
|
5
|
+
"main": "dist/main.cjs.js",
|
|
6
|
+
"module": "dist/main.esm.js",
|
|
7
|
+
"types": "dist/build/index.d.ts",
|
|
6
8
|
"dependencies": {
|
|
7
9
|
"@types/lodash": "^4.14.186",
|
|
10
|
+
"crypto-js": "^4.2.0",
|
|
8
11
|
"lodash": "^4.17.21",
|
|
9
12
|
"tone": "^14.7.77",
|
|
10
13
|
"uuid": "^8.3.2"
|
|
11
14
|
},
|
|
12
15
|
"scripts": {
|
|
13
16
|
"start": "tsc -w -p tsconfig.json",
|
|
14
|
-
"build": "
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
},
|
|
19
|
-
"browserslist": {
|
|
20
|
-
"production": [
|
|
21
|
-
">0.2%",
|
|
22
|
-
"not dead",
|
|
23
|
-
"not op_mini all"
|
|
24
|
-
],
|
|
25
|
-
"development": [
|
|
26
|
-
"last 1 chrome version",
|
|
27
|
-
"last 1 firefox version",
|
|
28
|
-
"last 1 safari version"
|
|
29
|
-
]
|
|
17
|
+
"build": "rollup -c",
|
|
18
|
+
"lint": "eslint src",
|
|
19
|
+
"ts:check": "tsc --noEmit",
|
|
20
|
+
"test": "jest"
|
|
30
21
|
},
|
|
31
22
|
"devDependencies": {
|
|
23
|
+
"@rollup/plugin-commonjs": "^25.0.7",
|
|
24
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
25
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
26
|
+
"@rollup/plugin-typescript": "^11.1.6",
|
|
27
|
+
"@types/crypto-js": "^4.2.2",
|
|
32
28
|
"@types/jest": "^29.2.0",
|
|
33
29
|
"@types/node": "^16.7.13",
|
|
34
30
|
"@types/uuid": "^8.3.4",
|
|
35
|
-
"eslint": "^
|
|
31
|
+
"@typescript-eslint/eslint-plugin": "^6.9.0",
|
|
32
|
+
"@typescript-eslint/parser": "^6.9.0",
|
|
33
|
+
"eslint": "^8.52.0",
|
|
36
34
|
"jest": "^29.2.2",
|
|
37
35
|
"prettier": "^2.7.1",
|
|
36
|
+
"rollup": "^4.10.0",
|
|
38
37
|
"ts-jest": "^29.0.3",
|
|
39
|
-
"typescript": "^
|
|
40
|
-
"typescript-language-server": "^0.
|
|
38
|
+
"typescript": "^5.2.2",
|
|
39
|
+
"typescript-language-server": "^4.0.0"
|
|
41
40
|
}
|
|
42
41
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import typescript from "@rollup/plugin-typescript";
|
|
2
|
+
import { nodeResolve } from "@rollup/plugin-node-resolve";
|
|
3
|
+
import commonjs from "@rollup/plugin-commonjs";
|
|
4
|
+
import terser from "@rollup/plugin-terser";
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
input: "src/index.ts", // Entry point
|
|
8
|
+
output: [
|
|
9
|
+
{
|
|
10
|
+
file: "dist/main.cjs.js",
|
|
11
|
+
format: "cjs", // CommonJS
|
|
12
|
+
sourcemap: true,
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
file: "dist/main.esm.js",
|
|
16
|
+
format: "esm", // ES Modules
|
|
17
|
+
sourcemap: true,
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
plugins: [typescript(), nodeResolve(), commonjs(), terser()],
|
|
21
|
+
};
|
package/src/Engine.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { Context, now, setContext } from "tone";
|
|
2
|
-
import MidiDeviceManager from "./
|
|
3
|
-
import MidiEvent, { EType } from "./MidiEvent";
|
|
2
|
+
import { MidiEvent, MidiDeviceManager } from "./core/midi";
|
|
4
3
|
|
|
5
|
-
import { AudioModule,
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import { applyRoutes, createRoute, RouteInterface, RouteProps } from "./routes";
|
|
4
|
+
import { AudioModule, Startable } from "./core/Module";
|
|
5
|
+
import { createModule, VirtualMidi, VoiceScheduler } from "./modules";
|
|
6
|
+
import { applyRoutes, createRoute, RouteInterface } from "./routes";
|
|
7
|
+
import { AnyObject, Optional } from "./types";
|
|
10
8
|
|
|
11
9
|
type LatencyHint = "interactive" | "playback" | "balanced";
|
|
12
10
|
|
|
@@ -22,10 +20,9 @@ interface InitializeInterface {
|
|
|
22
20
|
class Engine {
|
|
23
21
|
midiDeviceManager: MidiDeviceManager;
|
|
24
22
|
private static instance: Engine;
|
|
25
|
-
private _master: Master;
|
|
26
23
|
private context: Context;
|
|
27
|
-
private propsUpdateCallbacks: { (id: string, props:
|
|
28
|
-
private _isStarted
|
|
24
|
+
private propsUpdateCallbacks: { (id: string, props: AnyObject): void }[];
|
|
25
|
+
private _isStarted = false;
|
|
29
26
|
|
|
30
27
|
modules: {
|
|
31
28
|
[Identifier: string]: AudioModule;
|
|
@@ -50,19 +47,30 @@ class Engine {
|
|
|
50
47
|
}
|
|
51
48
|
|
|
52
49
|
initialize(props: InitializeInterface) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
this.context.transport.start();
|
|
50
|
+
return new Promise((resolve) => {
|
|
51
|
+
if (this.context) return resolve({});
|
|
56
52
|
|
|
57
|
-
|
|
53
|
+
this.context = new Context(props.context);
|
|
54
|
+
setContext(this.context);
|
|
55
|
+
this.context.transport.start();
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
this.midiDeviceManager = new MidiDeviceManager();
|
|
58
|
+
|
|
59
|
+
setTimeout(() => {
|
|
60
|
+
resolve({});
|
|
61
|
+
}, 0);
|
|
62
|
+
});
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
addModule(params: {
|
|
66
|
+
id?: string;
|
|
67
|
+
name: string;
|
|
68
|
+
type: string;
|
|
69
|
+
props?: AnyObject;
|
|
70
|
+
}) {
|
|
71
|
+
const { id, name, type, props = {} } = params;
|
|
72
|
+
|
|
73
|
+
const audioModule = createModule({ id, name, type, props: {} });
|
|
66
74
|
audioModule.props = props;
|
|
67
75
|
this.modules[audioModule.id] = audioModule;
|
|
68
76
|
|
|
@@ -71,7 +79,7 @@ class Engine {
|
|
|
71
79
|
return audioModule.serialize();
|
|
72
80
|
}
|
|
73
81
|
|
|
74
|
-
|
|
82
|
+
removeModule(id: string) {
|
|
75
83
|
this.modules[id].dispose();
|
|
76
84
|
const moduleRouteIds = this.moduleRouteIds(id);
|
|
77
85
|
|
|
@@ -89,15 +97,15 @@ class Engine {
|
|
|
89
97
|
return audioModule.serialize();
|
|
90
98
|
}
|
|
91
99
|
|
|
92
|
-
onPropsUpdate(callback: (id: string, props:
|
|
100
|
+
onPropsUpdate(callback: (id: string, props: AnyObject) => void) {
|
|
93
101
|
this.propsUpdateCallbacks.push(callback);
|
|
94
102
|
}
|
|
95
103
|
|
|
96
|
-
_triggerPropsUpdate(id: string, props:
|
|
104
|
+
_triggerPropsUpdate(id: string, props: AnyObject) {
|
|
97
105
|
this.propsUpdateCallbacks.forEach((callback) => callback(id, props));
|
|
98
106
|
}
|
|
99
107
|
|
|
100
|
-
updatePropsModule(id: string, props:
|
|
108
|
+
updatePropsModule(id: string, props: AnyObject) {
|
|
101
109
|
const audioModule = this.findById(id);
|
|
102
110
|
|
|
103
111
|
const applyRoutesRequired = this.applyRoutesRequired(audioModule, props);
|
|
@@ -107,7 +115,7 @@ class Engine {
|
|
|
107
115
|
return audioModule.serialize();
|
|
108
116
|
}
|
|
109
117
|
|
|
110
|
-
addRoute(props:
|
|
118
|
+
addRoute(props: Optional<RouteInterface, "id">) {
|
|
111
119
|
const route = createRoute(props);
|
|
112
120
|
const newRoutes = { ...this.routes, [route.id]: route };
|
|
113
121
|
|
|
@@ -122,29 +130,18 @@ class Engine {
|
|
|
122
130
|
this.updateRoutes();
|
|
123
131
|
}
|
|
124
132
|
|
|
125
|
-
|
|
126
|
-
if (this._master) return this._master.serialize();
|
|
127
|
-
|
|
128
|
-
const masterProps = this.registerModule("Master", "Master");
|
|
129
|
-
this._master = this.modules[masterProps.id] as Master;
|
|
130
|
-
|
|
131
|
-
return masterProps;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
triggerVirtualMidi(id: string, noteName: string, type: EType) {
|
|
133
|
+
triggerVirtualMidi(id: string, noteName: string, type: "noteOn" | "noteOff") {
|
|
135
134
|
const virtualMidi = this.findById(id) as VirtualMidi;
|
|
136
135
|
|
|
137
|
-
virtualMidi.sendMidi(MidiEvent.fromNote(noteName, type));
|
|
136
|
+
virtualMidi.sendMidi(MidiEvent.fromNote(noteName, type === "noteOn"));
|
|
138
137
|
}
|
|
139
138
|
|
|
140
139
|
dispose() {
|
|
141
140
|
Object.values(this.modules).forEach((m) => {
|
|
142
|
-
if (m instanceof Master) return;
|
|
143
|
-
|
|
144
141
|
m.dispose();
|
|
145
142
|
});
|
|
146
143
|
|
|
147
|
-
this.modules = {
|
|
144
|
+
this.modules = {};
|
|
148
145
|
this.routes = {};
|
|
149
146
|
}
|
|
150
147
|
|
|
@@ -157,7 +154,11 @@ class Engine {
|
|
|
157
154
|
}
|
|
158
155
|
|
|
159
156
|
get isStarted() {
|
|
160
|
-
return
|
|
157
|
+
return (
|
|
158
|
+
this.context !== undefined &&
|
|
159
|
+
this.context.transport.state === "started" &&
|
|
160
|
+
this._isStarted
|
|
161
|
+
);
|
|
161
162
|
}
|
|
162
163
|
|
|
163
164
|
start() {
|
|
@@ -166,7 +167,7 @@ class Engine {
|
|
|
166
167
|
this.updateRoutes();
|
|
167
168
|
|
|
168
169
|
Object.values(this.modules).forEach((audioModule) => {
|
|
169
|
-
const am = audioModule as
|
|
170
|
+
const am = audioModule as unknown as Startable;
|
|
170
171
|
if (!am.start) return;
|
|
171
172
|
|
|
172
173
|
am.start(startTime);
|
|
@@ -176,7 +177,7 @@ class Engine {
|
|
|
176
177
|
stop() {
|
|
177
178
|
const startTime = now();
|
|
178
179
|
Object.values(this.modules).forEach((audioModule) => {
|
|
179
|
-
const am = audioModule as
|
|
180
|
+
const am = audioModule as unknown as Startable;
|
|
180
181
|
if (!am.stop) return;
|
|
181
182
|
|
|
182
183
|
am.stop(startTime);
|
|
@@ -197,7 +198,7 @@ class Engine {
|
|
|
197
198
|
applyRoutes(Object.values(this.routes));
|
|
198
199
|
}
|
|
199
200
|
|
|
200
|
-
private applyRoutesRequired(audioModule: AudioModule, props:
|
|
201
|
+
private applyRoutesRequired(audioModule: AudioModule, props: AnyObject) {
|
|
201
202
|
if (!props.polyNumber) return false;
|
|
202
203
|
if (!(audioModule instanceof VoiceScheduler)) return false;
|
|
203
204
|
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { InputNode } from "tone";
|
|
2
|
+
import IONode, { IOType, IIONode } from "./Node";
|
|
3
|
+
import MonoModule, { Connectable } from "../Module/index";
|
|
4
|
+
import { AnyObject } from "../../types";
|
|
5
|
+
import { ForwardInput, ForwardOutput } from "./ForwardNode";
|
|
6
|
+
|
|
7
|
+
export type AudioIO = AudioInput | AudioOutput;
|
|
8
|
+
|
|
9
|
+
export interface IAudioInput extends IIONode {
|
|
10
|
+
ioType: IOType.AudioInput;
|
|
11
|
+
internalModule: InputNode;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface IAudioOutput extends IIONode {
|
|
15
|
+
ioType: IOType.AudioOutput;
|
|
16
|
+
internalModule: IInternalModule;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface IInternalModule extends Connectable {}
|
|
20
|
+
|
|
21
|
+
export class AudioInput extends IONode implements IAudioInput {
|
|
22
|
+
declare ioType: IOType.AudioInput;
|
|
23
|
+
internalModule!: InputNode;
|
|
24
|
+
declare connections: AudioOutput[];
|
|
25
|
+
|
|
26
|
+
constructor(
|
|
27
|
+
plugableModule: MonoModule<Connectable, AnyObject>,
|
|
28
|
+
props: IAudioInput
|
|
29
|
+
) {
|
|
30
|
+
super(plugableModule, props);
|
|
31
|
+
this.internalModule = props.internalModule;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
plug(io: AudioOutput | ForwardOutput, plugOther: boolean = true) {
|
|
35
|
+
super.plug(io, plugOther);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
unPlug(io: AudioOutput | ForwardOutput, plugOther: boolean = true) {
|
|
39
|
+
super.unPlug(io, plugOther);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
unPlugAll() {
|
|
43
|
+
IONode.unPlugAll(this);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class AudioOutput extends IONode implements IAudioOutput {
|
|
48
|
+
declare ioType: IOType.AudioOutput;
|
|
49
|
+
internalModule!: IInternalModule;
|
|
50
|
+
declare connections: AudioInput[];
|
|
51
|
+
|
|
52
|
+
constructor(
|
|
53
|
+
plugableModule: MonoModule<Connectable, AnyObject>,
|
|
54
|
+
props: IAudioOutput
|
|
55
|
+
) {
|
|
56
|
+
super(plugableModule, props);
|
|
57
|
+
this.internalModule = props.internalModule;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
plug(io: AudioInput | ForwardInput, plugOther: boolean = true) {
|
|
61
|
+
super.plug(io, plugOther);
|
|
62
|
+
if (io instanceof ForwardInput) return;
|
|
63
|
+
|
|
64
|
+
this.internalModule.connect(io.internalModule);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
unPlug(io: AudioInput | ForwardInput, plugOther: boolean = true) {
|
|
68
|
+
super.unPlug(io, plugOther);
|
|
69
|
+
if (io instanceof ForwardInput) return;
|
|
70
|
+
|
|
71
|
+
this.internalModule.disconnect(io.internalModule);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
unPlugAll() {
|
|
75
|
+
IONode.unPlugAll(this);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import MonoModule, { AudioModule, PolyModule } from "../Module";
|
|
2
|
+
import IO, { IOType } from "./Node";
|
|
3
|
+
import { AudioInput, AudioOutput } from "./AudioNode";
|
|
4
|
+
import { MidiInput, MidiOutput } from "./MidiNode";
|
|
5
|
+
import { IAnyIO } from ".";
|
|
6
|
+
import { ForwardInput, ForwardOutput } from "./ForwardNode";
|
|
7
|
+
|
|
8
|
+
export default class IOCollection<AnyIO extends IO> {
|
|
9
|
+
plugableModule: AudioModule;
|
|
10
|
+
collection: AnyIO[] = [];
|
|
11
|
+
|
|
12
|
+
constructor(plugableModule: AudioModule) {
|
|
13
|
+
this.plugableModule = plugableModule;
|
|
14
|
+
}
|
|
15
|
+
add<CurrentIO extends AnyIO>(props: IAnyIO): CurrentIO {
|
|
16
|
+
let io;
|
|
17
|
+
|
|
18
|
+
switch (props.ioType) {
|
|
19
|
+
case IOType.AudioInput:
|
|
20
|
+
if (this.plugableModule instanceof PolyModule) {
|
|
21
|
+
throw Error("PolyModule is not supported");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
io = new AudioInput(this.plugableModule, props);
|
|
25
|
+
break;
|
|
26
|
+
case IOType.AudioOutput:
|
|
27
|
+
if (this.plugableModule instanceof PolyModule) {
|
|
28
|
+
throw Error("PolyModule is not supported");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
io = new AudioOutput(this.plugableModule, props);
|
|
32
|
+
break;
|
|
33
|
+
case IOType.ForwardInput:
|
|
34
|
+
if (this.plugableModule instanceof MonoModule) {
|
|
35
|
+
throw Error("MonoModule is not supported");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
io = new ForwardInput(this.plugableModule, props);
|
|
39
|
+
break;
|
|
40
|
+
case IOType.ForwardOutput:
|
|
41
|
+
if (this.plugableModule instanceof MonoModule) {
|
|
42
|
+
throw Error("MonoModule is not supported");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
io = new ForwardOutput(this.plugableModule, props);
|
|
46
|
+
break;
|
|
47
|
+
case IOType.MidiInput:
|
|
48
|
+
io = new MidiInput(this.plugableModule, props);
|
|
49
|
+
break;
|
|
50
|
+
case IOType.MidiOutput:
|
|
51
|
+
io = new MidiOutput(this.plugableModule, props);
|
|
52
|
+
break;
|
|
53
|
+
default:
|
|
54
|
+
throw Error("Unknown IOType");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.collection.push(io as unknown as CurrentIO);
|
|
58
|
+
return io as unknown as CurrentIO;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
unPlugAll() {
|
|
62
|
+
this.collection.forEach((io) => io.unPlugAll());
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
find(id: string) {
|
|
66
|
+
return this.collection.find((io) => io.id === id);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
findByName(name: string) {
|
|
70
|
+
return this.collection.find((io) => io.name === name);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
serialize() {
|
|
74
|
+
return this.collection.map((io) => io.serialize());
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import IONode, {
|
|
2
|
+
IOType,
|
|
3
|
+
IIONode,
|
|
4
|
+
plugCompatibleIO,
|
|
5
|
+
unPlugCompatibleIO,
|
|
6
|
+
} from "./Node";
|
|
7
|
+
import Module, { Connectable, PolyModule } from "../Module";
|
|
8
|
+
import { AnyObject } from "../../types";
|
|
9
|
+
import { AnyInput, AnyOuput } from ".";
|
|
10
|
+
|
|
11
|
+
export interface IForwardInput extends IIONode {
|
|
12
|
+
ioType: IOType.ForwardInput;
|
|
13
|
+
}
|
|
14
|
+
export interface IForwardOutput extends IIONode {
|
|
15
|
+
ioType: IOType.ForwardOutput;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class ForwardInput extends IONode implements IForwardInput {
|
|
19
|
+
declare plugableModule: PolyModule<Module<Connectable, AnyObject>, AnyObject>;
|
|
20
|
+
declare ioType: IOType.ForwardInput;
|
|
21
|
+
declare connections: ForwardOutput[];
|
|
22
|
+
|
|
23
|
+
constructor(
|
|
24
|
+
plugableModule: PolyModule<Module<Connectable, AnyObject>, AnyObject>,
|
|
25
|
+
props: IForwardInput
|
|
26
|
+
) {
|
|
27
|
+
super(plugableModule, props);
|
|
28
|
+
this.checkNameValidity();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get subInputs() {
|
|
32
|
+
return this.plugableModule.audioModules.map((am) => {
|
|
33
|
+
const input = am.inputs.findByName(this.name);
|
|
34
|
+
if (!input) throw Error(`Could not forward input ${this.name}`);
|
|
35
|
+
|
|
36
|
+
return input;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get subModules() {
|
|
41
|
+
return this.plugableModule.audioModules;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
subModule(voiceNo: number) {
|
|
45
|
+
const mod = this.subModules.find((m) => m.voiceNo === voiceNo);
|
|
46
|
+
if (!mod) throw Error(`Submodule with voiceNo ${voiceNo} not found`);
|
|
47
|
+
|
|
48
|
+
return mod;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
subInput(voiceNo: number) {
|
|
52
|
+
const input = this.subModule(voiceNo).inputs.findByName(this.name);
|
|
53
|
+
if (!input) throw Error(`Could not forward input ${this.name}`);
|
|
54
|
+
|
|
55
|
+
return input;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
plug(io: AnyOuput, plugOther: boolean = true) {
|
|
59
|
+
super.plug(io, plugOther);
|
|
60
|
+
if (!plugOther && io instanceof ForwardOutput) return;
|
|
61
|
+
|
|
62
|
+
if (io instanceof ForwardOutput) {
|
|
63
|
+
this.subModules.forEach((am) => {
|
|
64
|
+
const input = am.inputs.findByName(this.name);
|
|
65
|
+
if (!input) throw Error(`Could not forward input ${this.name}`);
|
|
66
|
+
|
|
67
|
+
const output = io.subOutput(am.voiceNo as number);
|
|
68
|
+
plugCompatibleIO(input, output);
|
|
69
|
+
});
|
|
70
|
+
} else {
|
|
71
|
+
this.subInputs.forEach((input) => plugCompatibleIO(input, io));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
unPlug(io: AnyOuput, plugOther: boolean = true) {
|
|
76
|
+
super.unPlug(io, plugOther);
|
|
77
|
+
if (!plugOther && io instanceof ForwardOutput) return;
|
|
78
|
+
|
|
79
|
+
if (io instanceof ForwardOutput) {
|
|
80
|
+
this.subModules.forEach((am) => {
|
|
81
|
+
const input = am.inputs.findByName(this.name);
|
|
82
|
+
if (!input) throw Error(`Could not forward input ${this.name}`);
|
|
83
|
+
|
|
84
|
+
const output = io.subOutput(am.voiceNo as number);
|
|
85
|
+
unPlugCompatibleIO(input, output);
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
this.subInputs.forEach((input) => unPlugCompatibleIO(input, io));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
unPlugAll() {
|
|
93
|
+
IONode.unPlugAll(this);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private checkNameValidity() {
|
|
97
|
+
const input = this.plugableModule.audioModules[0].inputs.findByName(
|
|
98
|
+
this.name
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
if (!input) throw Error("You should forward to existing input");
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export class ForwardOutput extends IONode implements IForwardOutput {
|
|
106
|
+
declare plugableModule: PolyModule<Module<Connectable, AnyObject>, AnyObject>;
|
|
107
|
+
declare ioType: IOType.ForwardOutput;
|
|
108
|
+
declare connections: ForwardInput[];
|
|
109
|
+
|
|
110
|
+
constructor(
|
|
111
|
+
plugableModule: PolyModule<Module<Connectable, AnyObject>, AnyObject>,
|
|
112
|
+
props: IForwardOutput
|
|
113
|
+
) {
|
|
114
|
+
super(plugableModule, props);
|
|
115
|
+
this.checkNameValidity();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
get subOutputs() {
|
|
119
|
+
return this.subModules.map((am) => {
|
|
120
|
+
const output = am.outputs.findByName(this.name);
|
|
121
|
+
if (!output) throw Error(`Could not forward input ${this.name}`);
|
|
122
|
+
|
|
123
|
+
return output;
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
get subModules() {
|
|
128
|
+
return this.plugableModule.audioModules;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
subModule(voiceNo: number) {
|
|
132
|
+
const mod = this.subModules.find((m) => m.voiceNo === voiceNo);
|
|
133
|
+
if (!mod) throw Error(`Submodule with voiceNo ${voiceNo} not found`);
|
|
134
|
+
|
|
135
|
+
return mod;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
subOutput(voiceNo: number) {
|
|
139
|
+
const output = this.subModule(voiceNo).outputs.findByName(this.name);
|
|
140
|
+
if (!output) throw Error(`Could not forward input ${this.name}`);
|
|
141
|
+
|
|
142
|
+
return output;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
plug(io: AnyInput, plugOther: boolean = true) {
|
|
146
|
+
super.plug(io, plugOther);
|
|
147
|
+
if (!plugOther && io instanceof ForwardInput) return;
|
|
148
|
+
|
|
149
|
+
if (io instanceof ForwardInput) {
|
|
150
|
+
this.subModules.forEach((am) => {
|
|
151
|
+
const output = am.outputs.findByName(this.name);
|
|
152
|
+
if (!output) throw Error(`Could not forward output ${this.name}`);
|
|
153
|
+
|
|
154
|
+
const input = io.subInput(am.voiceNo as number);
|
|
155
|
+
|
|
156
|
+
plugCompatibleIO(input, output);
|
|
157
|
+
});
|
|
158
|
+
} else {
|
|
159
|
+
this.subOutputs.forEach((output) => plugCompatibleIO(io, output));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
unPlug(io: AnyInput, plugOther: boolean = true) {
|
|
164
|
+
super.unPlug(io, plugOther);
|
|
165
|
+
if (!plugOther && io instanceof ForwardInput) return;
|
|
166
|
+
|
|
167
|
+
if (io instanceof ForwardInput) {
|
|
168
|
+
this.subModules.forEach((am) => {
|
|
169
|
+
const output = am.outputs.findByName(this.name);
|
|
170
|
+
if (!output) throw Error(`Could not forward output ${this.name}`);
|
|
171
|
+
|
|
172
|
+
const input = io.subInput(am.voiceNo as number);
|
|
173
|
+
|
|
174
|
+
unPlugCompatibleIO(input, output);
|
|
175
|
+
});
|
|
176
|
+
} else {
|
|
177
|
+
this.subOutputs.forEach((output) => unPlugCompatibleIO(io, output));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
unPlugAll() {
|
|
182
|
+
IONode.unPlugAll(this);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private checkNameValidity() {
|
|
186
|
+
const output = this.plugableModule.audioModules[0].outputs.findByName(
|
|
187
|
+
this.name
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
if (!output) throw Error("You should forward to existing output");
|
|
191
|
+
}
|
|
192
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { AudioModule } from "../Module";
|
|
2
|
+
import { MidiEvent } from "../midi";
|
|
3
|
+
import { ForwardInput, ForwardOutput } from "./ForwardNode";
|
|
4
|
+
import IONode, { IOType, IIONode } from "./Node";
|
|
5
|
+
|
|
6
|
+
export interface IMidiInput extends IIONode {
|
|
7
|
+
ioType: IOType.MidiInput;
|
|
8
|
+
onMidiEvent: (event: MidiEvent) => void;
|
|
9
|
+
}
|
|
10
|
+
export interface IMidiOutput extends IIONode {
|
|
11
|
+
ioType: IOType.MidiOutput;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class MidiInput extends IONode implements IMidiInput {
|
|
15
|
+
declare ioType: IOType.MidiInput;
|
|
16
|
+
declare connections: MidiOutput[];
|
|
17
|
+
onMidiEvent: (event: MidiEvent) => void;
|
|
18
|
+
|
|
19
|
+
constructor(plugableModule: AudioModule, props: IMidiInput) {
|
|
20
|
+
super(plugableModule, props);
|
|
21
|
+
|
|
22
|
+
this.onMidiEvent = props.onMidiEvent;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
plug(io: MidiOutput | ForwardOutput, plugOther: boolean = true) {
|
|
26
|
+
super.plug(io, plugOther);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
unPlug(io: MidiOutput | ForwardOutput, plugOther: boolean = true) {
|
|
30
|
+
super.unPlug(io, plugOther);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
unPlugAll() {
|
|
34
|
+
IONode.unPlugAll(this);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class MidiOutput extends IONode implements IMidiOutput {
|
|
39
|
+
declare ioType: IOType.MidiOutput;
|
|
40
|
+
declare connections: MidiInput[];
|
|
41
|
+
|
|
42
|
+
constructor(plugableModule: AudioModule, props: IIONode) {
|
|
43
|
+
super(plugableModule, props);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
plug(io: MidiInput | ForwardInput, plugOther: boolean = true) {
|
|
47
|
+
super.plug(io, plugOther);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
unPlug(io: MidiInput | ForwardOutput, plugOther: boolean = true) {
|
|
51
|
+
super.unPlug(io, plugOther);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
unPlugAll() {
|
|
55
|
+
IONode.unPlugAll(this);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
onMidiEvent = (event: MidiEvent) => {
|
|
59
|
+
this.midiConnections.forEach((input) => {
|
|
60
|
+
input.onMidiEvent(event);
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
private get midiConnections() {
|
|
65
|
+
return this.connections.filter((input) => input instanceof MidiInput);
|
|
66
|
+
}
|
|
67
|
+
}
|