@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.
Files changed (144) hide show
  1. package/.eslintrc.js +14 -0
  2. package/.parcerc +6 -0
  3. package/README.md +122 -0
  4. package/dist/main.cjs.js +33 -0
  5. package/package.json +21 -22
  6. package/rollup.config.mjs +21 -0
  7. package/src/Engine.ts +43 -42
  8. package/src/core/IO/AudioNode.ts +77 -0
  9. package/src/core/IO/Collection.ts +76 -0
  10. package/src/core/IO/ForwardNode.ts +192 -0
  11. package/src/core/IO/MidiNode.ts +67 -0
  12. package/src/core/IO/Node.ts +117 -0
  13. package/src/core/IO/index.ts +47 -0
  14. package/src/core/Module/MonoModule.ts +219 -0
  15. package/src/core/Module/PolyModule.ts +206 -0
  16. package/src/core/Module/index.ts +15 -0
  17. package/src/{Note → core/Note}/index.ts +19 -4
  18. package/src/{MidiDeviceManager.ts → core/midi/MidiDeviceManager.ts} +20 -15
  19. package/src/core/midi/MidiEvent.ts +91 -0
  20. package/src/core/midi/index.ts +5 -0
  21. package/src/index.ts +8 -12
  22. package/src/{Module → modules}/BitCrusher.ts +15 -4
  23. package/src/{Module → modules}/Delay.ts +15 -4
  24. package/src/{Module → modules}/Distortion.ts +15 -4
  25. package/src/{Module → modules}/Effect.ts +11 -7
  26. package/src/modules/Envelope/AmpEnvelope.ts +23 -0
  27. package/src/{Module → modules}/Envelope/Base.ts +50 -31
  28. package/src/{Module → modules}/Envelope/FreqEnvelope.ts +18 -23
  29. package/src/{Module → modules}/Filter.ts +18 -46
  30. package/src/{Module → modules}/Master.ts +8 -2
  31. package/src/{Module → modules}/MidiSelector.ts +18 -14
  32. package/src/{Module → modules}/Oscillator.ts +27 -16
  33. package/src/{Module → modules}/Reverb.ts +15 -4
  34. package/src/{Module → modules}/Sequencer.ts +17 -13
  35. package/src/{Module → modules}/VirtualMidi.ts +16 -12
  36. package/src/modules/VoiceScheduler.ts +145 -0
  37. package/src/{Module → modules}/Volume.ts +23 -15
  38. package/src/{Module → modules}/index.ts +14 -21
  39. package/src/routes.ts +19 -18
  40. package/src/types.ts +3 -0
  41. package/src/utils.ts +18 -0
  42. package/test/MockingModules.ts +27 -0
  43. package/test/Module/Oscillator.test.ts +1 -1
  44. package/test/core/IO.test.ts +172 -0
  45. package/build/Engine.d.ts +0 -94
  46. package/build/Engine.js +0 -158
  47. package/build/Engine.js.map +0 -1
  48. package/build/MidiDevice.d.ts +0 -25
  49. package/build/MidiDevice.js +0 -45
  50. package/build/MidiDevice.js.map +0 -1
  51. package/build/MidiDeviceManager.d.ts +0 -13
  52. package/build/MidiDeviceManager.js +0 -59
  53. package/build/MidiDeviceManager.js.map +0 -1
  54. package/build/MidiEvent.d.ts +0 -18
  55. package/build/MidiEvent.js +0 -64
  56. package/build/MidiEvent.js.map +0 -1
  57. package/build/Module/Base.d.ts +0 -65
  58. package/build/Module/Base.js +0 -138
  59. package/build/Module/Base.js.map +0 -1
  60. package/build/Module/BitCrusher.d.ts +0 -12
  61. package/build/Module/BitCrusher.js +0 -22
  62. package/build/Module/BitCrusher.js.map +0 -1
  63. package/build/Module/DataSequencer.d.ts +0 -25
  64. package/build/Module/DataSequencer.js +0 -72
  65. package/build/Module/DataSequencer.js.map +0 -1
  66. package/build/Module/Delay.d.ts +0 -15
  67. package/build/Module/Delay.js +0 -30
  68. package/build/Module/Delay.js.map +0 -1
  69. package/build/Module/Distortion.d.ts +0 -12
  70. package/build/Module/Distortion.js +0 -22
  71. package/build/Module/Distortion.js.map +0 -1
  72. package/build/Module/Effect.d.ts +0 -14
  73. package/build/Module/Effect.js +0 -22
  74. package/build/Module/Effect.js.map +0 -1
  75. package/build/Module/Envelope/AmpEnvelope.d.ts +0 -10
  76. package/build/Module/Envelope/AmpEnvelope.js +0 -14
  77. package/build/Module/Envelope/AmpEnvelope.js.map +0 -1
  78. package/build/Module/Envelope/Base.d.ts +0 -47
  79. package/build/Module/Envelope/Base.js +0 -106
  80. package/build/Module/Envelope/Base.js.map +0 -1
  81. package/build/Module/Envelope/FreqEnvelope.d.ts +0 -18
  82. package/build/Module/Envelope/FreqEnvelope.js +0 -50
  83. package/build/Module/Envelope/FreqEnvelope.js.map +0 -1
  84. package/build/Module/Envelope/index.d.ts +0 -3
  85. package/build/Module/Envelope/index.js +0 -4
  86. package/build/Module/Envelope/index.js.map +0 -1
  87. package/build/Module/Filter.d.ts +0 -37
  88. package/build/Module/Filter.js +0 -100
  89. package/build/Module/Filter.js.map +0 -1
  90. package/build/Module/IO.d.ts +0 -39
  91. package/build/Module/IO.js +0 -59
  92. package/build/Module/IO.js.map +0 -1
  93. package/build/Module/Master.d.ts +0 -8
  94. package/build/Module/Master.js +0 -12
  95. package/build/Module/Master.js.map +0 -1
  96. package/build/Module/MidiSelector.d.ts +0 -17
  97. package/build/Module/MidiSelector.js +0 -50
  98. package/build/Module/MidiSelector.js.map +0 -1
  99. package/build/Module/Oscillator.d.ts +0 -45
  100. package/build/Module/Oscillator.js +0 -136
  101. package/build/Module/Oscillator.js.map +0 -1
  102. package/build/Module/PolyModule.d.ts +0 -49
  103. package/build/Module/PolyModule.js +0 -175
  104. package/build/Module/PolyModule.js.map +0 -1
  105. package/build/Module/Reverb.d.ts +0 -15
  106. package/build/Module/Reverb.js +0 -30
  107. package/build/Module/Reverb.js.map +0 -1
  108. package/build/Module/Sequencer.d.ts +0 -38
  109. package/build/Module/Sequencer.js +0 -131
  110. package/build/Module/Sequencer.js.map +0 -1
  111. package/build/Module/VirtualMidi.d.ts +0 -28
  112. package/build/Module/VirtualMidi.js +0 -53
  113. package/build/Module/VirtualMidi.js.map +0 -1
  114. package/build/Module/VoiceScheduler.d.ts +0 -38
  115. package/build/Module/VoiceScheduler.js +0 -130
  116. package/build/Module/VoiceScheduler.js.map +0 -1
  117. package/build/Module/Volume.d.ts +0 -20
  118. package/build/Module/Volume.js +0 -48
  119. package/build/Module/Volume.js.map +0 -1
  120. package/build/Module/index.d.ts +0 -14
  121. package/build/Module/index.js +0 -66
  122. package/build/Module/index.js.map +0 -1
  123. package/build/Note/frequencyTable.d.ts +0 -4
  124. package/build/Note/frequencyTable.js +0 -146
  125. package/build/Note/frequencyTable.js.map +0 -1
  126. package/build/Note/index.d.ts +0 -25
  127. package/build/Note/index.js +0 -81
  128. package/build/Note/index.js.map +0 -1
  129. package/build/index.d.ts +0 -8
  130. package/build/index.js +0 -5
  131. package/build/index.js.map +0 -1
  132. package/build/routes.d.ts +0 -17
  133. package/build/routes.js +0 -31
  134. package/build/routes.js.map +0 -1
  135. package/src/MidiEvent.ts +0 -93
  136. package/src/Module/Base.ts +0 -220
  137. package/src/Module/DataSequencer.ts +0 -101
  138. package/src/Module/Envelope/AmpEnvelope.ts +0 -17
  139. package/src/Module/IO.ts +0 -85
  140. package/src/Module/PolyModule.ts +0 -234
  141. package/src/Module/VoiceScheduler.ts +0 -161
  142. /package/src/{Note → core/Note}/frequencyTable.ts +0 -0
  143. /package/src/{MidiDevice.ts → core/midi/MidiDevice.ts} +0 -0
  144. /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.16",
4
- "main": "build/index.js",
5
- "types": "build/index.d.ts",
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": "rm -rf build && tsc"
15
- },
16
- "eslintConfig": {
17
- "extends": []
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": "^8.18.0",
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": "^4.7.4",
40
- "typescript-language-server": "^0.11.1"
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 "./MidiDeviceManager";
3
- import MidiEvent, { EType } from "./MidiEvent";
2
+ import { MidiEvent, MidiDeviceManager } from "./core/midi";
4
3
 
5
- import { AudioModule, createModule } from "./Module";
6
- import Master from "./Module/Master";
7
- import VirtualMidi from "./Module/VirtualMidi";
8
- import VoiceScheduler from "./Module/VoiceScheduler";
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: any): void }[];
28
- private _isStarted: boolean = false;
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
- this.context = new Context(props.context);
54
- setContext(this.context);
55
- this.context.transport.start();
50
+ return new Promise((resolve) => {
51
+ if (this.context) return resolve({});
56
52
 
57
- this.midiDeviceManager = new MidiDeviceManager();
53
+ this.context = new Context(props.context);
54
+ setContext(this.context);
55
+ this.context.transport.start();
58
56
 
59
- return {
60
- master: this.master,
61
- };
57
+ this.midiDeviceManager = new MidiDeviceManager();
58
+
59
+ setTimeout(() => {
60
+ resolve({});
61
+ }, 0);
62
+ });
62
63
  }
63
64
 
64
- registerModule(name: string, type: string, props: any = {}) {
65
- const audioModule = createModule(name, type, {});
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
- unregisterModule(id: string) {
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: any) => void) {
100
+ onPropsUpdate(callback: (id: string, props: AnyObject) => void) {
93
101
  this.propsUpdateCallbacks.push(callback);
94
102
  }
95
103
 
96
- _triggerPropsUpdate(id: string, props: any) {
104
+ _triggerPropsUpdate(id: string, props: AnyObject) {
97
105
  this.propsUpdateCallbacks.forEach((callback) => callback(id, props));
98
106
  }
99
107
 
100
- updatePropsModule(id: string, props: any) {
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: RouteProps) {
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
- get master() {
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 = { [this._master.id]: this._master };
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 this.context.transport.state === "started" && this._isStarted;
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 any;
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 any;
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: any) {
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
+ }