@blibliki/engine 0.1.17 → 0.1.19

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 (161) hide show
  1. package/README.md +13 -1
  2. package/{build → dist/build}/Engine.d.ts +14 -22
  3. package/dist/build/core/IO/AudioNode.d.ts +35 -0
  4. package/dist/build/core/IO/Collection.d.ts +13 -0
  5. package/dist/build/core/IO/ForwardNode.d.ts +38 -0
  6. package/dist/build/core/IO/MidiNode.d.ts +30 -0
  7. package/dist/build/core/IO/Node.d.ts +36 -0
  8. package/dist/build/core/IO/index.d.ts +12 -0
  9. package/dist/build/core/Module/MonoModule.d.ts +67 -0
  10. package/dist/build/core/Module/PolyModule.d.ts +57 -0
  11. package/dist/build/core/Module/index.d.ts +6 -0
  12. package/{build → dist/build/core}/Note/index.d.ts +3 -0
  13. package/{build → dist/build/core/midi}/MidiDevice.d.ts +1 -1
  14. package/dist/build/core/midi/MidiEvent.d.ts +21 -0
  15. package/dist/build/core/midi/index.d.ts +5 -0
  16. package/dist/build/index.d.ts +9 -0
  17. package/{build/Module → dist/build/modules}/BitCrusher.d.ts +5 -1
  18. package/{build/Module → dist/build/modules}/Delay.d.ts +5 -1
  19. package/{build/Module → dist/build/modules}/Distortion.d.ts +5 -1
  20. package/{build/Module → dist/build/modules}/Effect.d.ts +7 -2
  21. package/{build/Module → dist/build/modules}/Envelope/AmpEnvelope.d.ts +10 -2
  22. package/{build/Module → dist/build/modules}/Envelope/Base.d.ts +30 -11
  23. package/{build/Module → dist/build/modules}/Envelope/FreqEnvelope.d.ts +10 -3
  24. package/{build/Module → dist/build/modules}/Filter.d.ts +13 -13
  25. package/{build/Module → dist/build/modules}/Master.d.ts +5 -2
  26. package/{build/Module → dist/build/modules}/MidiSelector.d.ts +9 -5
  27. package/{build/Module → dist/build/modules}/Oscillator.d.ts +15 -9
  28. package/{build/Module → dist/build/modules}/Reverb.d.ts +5 -1
  29. package/{build/Module → dist/build/modules}/Sequencer.d.ts +9 -5
  30. package/{build/Module → dist/build/modules}/VirtualMidi.d.ts +12 -8
  31. package/dist/build/modules/VoiceScheduler.d.ts +43 -0
  32. package/dist/build/modules/Volume.d.ts +26 -0
  33. package/dist/build/modules/index.d.ts +16 -0
  34. package/{build → dist/build}/routes.d.ts +6 -5
  35. package/dist/build/types.d.ts +5 -0
  36. package/dist/build/utils.d.ts +1 -0
  37. package/dist/main.cjs.js +33 -0
  38. package/dist/main.cjs.js.map +1 -0
  39. package/dist/main.esm.js +33 -0
  40. package/dist/main.esm.js.map +1 -0
  41. package/package.json +26 -22
  42. package/src/Engine.ts +27 -36
  43. package/src/core/IO/AudioNode.ts +77 -0
  44. package/src/core/IO/Collection.ts +76 -0
  45. package/src/core/IO/ForwardNode.ts +192 -0
  46. package/src/core/IO/MidiNode.ts +67 -0
  47. package/src/core/IO/Node.ts +117 -0
  48. package/src/core/IO/index.ts +47 -0
  49. package/src/core/Module/MonoModule.ts +219 -0
  50. package/src/core/Module/PolyModule.ts +206 -0
  51. package/src/core/Module/index.ts +15 -0
  52. package/src/{Note → core/Note}/index.ts +19 -4
  53. package/src/{MidiDeviceManager.ts → core/midi/MidiDeviceManager.ts} +20 -15
  54. package/src/core/midi/MidiEvent.ts +91 -0
  55. package/src/core/midi/index.ts +5 -0
  56. package/src/index.ts +8 -12
  57. package/src/{Module → modules}/BitCrusher.ts +15 -4
  58. package/src/{Module → modules}/Delay.ts +15 -4
  59. package/src/{Module → modules}/Distortion.ts +15 -4
  60. package/src/{Module → modules}/Effect.ts +10 -6
  61. package/src/modules/Envelope/AmpEnvelope.ts +23 -0
  62. package/src/{Module → modules}/Envelope/Base.ts +50 -31
  63. package/src/{Module → modules}/Envelope/FreqEnvelope.ts +18 -23
  64. package/src/{Module → modules}/Filter.ts +18 -46
  65. package/src/{Module → modules}/Master.ts +8 -2
  66. package/src/{Module → modules}/MidiSelector.ts +18 -14
  67. package/src/{Module → modules}/Oscillator.ts +27 -16
  68. package/src/{Module → modules}/Reverb.ts +15 -4
  69. package/src/{Module → modules}/Sequencer.ts +17 -13
  70. package/src/{Module → modules}/VirtualMidi.ts +16 -12
  71. package/src/modules/VoiceScheduler.ts +145 -0
  72. package/src/{Module → modules}/Volume.ts +23 -15
  73. package/src/{Module → modules}/index.ts +14 -21
  74. package/src/routes.ts +19 -18
  75. package/src/types.ts +3 -0
  76. package/src/utils.ts +18 -0
  77. package/build/Engine.js +0 -165
  78. package/build/Engine.js.map +0 -1
  79. package/build/MidiDevice.js +0 -45
  80. package/build/MidiDevice.js.map +0 -1
  81. package/build/MidiDeviceManager.js +0 -59
  82. package/build/MidiDeviceManager.js.map +0 -1
  83. package/build/MidiEvent.d.ts +0 -18
  84. package/build/MidiEvent.js +0 -64
  85. package/build/MidiEvent.js.map +0 -1
  86. package/build/Module/Base.d.ts +0 -63
  87. package/build/Module/Base.js +0 -138
  88. package/build/Module/Base.js.map +0 -1
  89. package/build/Module/BitCrusher.js +0 -22
  90. package/build/Module/BitCrusher.js.map +0 -1
  91. package/build/Module/DataSequencer.d.ts +0 -26
  92. package/build/Module/DataSequencer.js +0 -91
  93. package/build/Module/DataSequencer.js.map +0 -1
  94. package/build/Module/Delay.js +0 -30
  95. package/build/Module/Delay.js.map +0 -1
  96. package/build/Module/Distortion.js +0 -22
  97. package/build/Module/Distortion.js.map +0 -1
  98. package/build/Module/Effect.js +0 -22
  99. package/build/Module/Effect.js.map +0 -1
  100. package/build/Module/Envelope/AmpEnvelope.js +0 -14
  101. package/build/Module/Envelope/AmpEnvelope.js.map +0 -1
  102. package/build/Module/Envelope/Base.js +0 -106
  103. package/build/Module/Envelope/Base.js.map +0 -1
  104. package/build/Module/Envelope/FreqEnvelope.js +0 -50
  105. package/build/Module/Envelope/FreqEnvelope.js.map +0 -1
  106. package/build/Module/Envelope/index.js +0 -4
  107. package/build/Module/Envelope/index.js.map +0 -1
  108. package/build/Module/Filter.js +0 -100
  109. package/build/Module/Filter.js.map +0 -1
  110. package/build/Module/IO.d.ts +0 -39
  111. package/build/Module/IO.js +0 -59
  112. package/build/Module/IO.js.map +0 -1
  113. package/build/Module/Master.js +0 -12
  114. package/build/Module/Master.js.map +0 -1
  115. package/build/Module/MidiSelector.js +0 -50
  116. package/build/Module/MidiSelector.js.map +0 -1
  117. package/build/Module/Oscillator.js +0 -136
  118. package/build/Module/Oscillator.js.map +0 -1
  119. package/build/Module/PolyModule.d.ts +0 -49
  120. package/build/Module/PolyModule.js +0 -175
  121. package/build/Module/PolyModule.js.map +0 -1
  122. package/build/Module/Reverb.js +0 -30
  123. package/build/Module/Reverb.js.map +0 -1
  124. package/build/Module/Sequencer.js +0 -131
  125. package/build/Module/Sequencer.js.map +0 -1
  126. package/build/Module/VirtualMidi.js +0 -53
  127. package/build/Module/VirtualMidi.js.map +0 -1
  128. package/build/Module/VoiceScheduler.d.ts +0 -38
  129. package/build/Module/VoiceScheduler.js +0 -130
  130. package/build/Module/VoiceScheduler.js.map +0 -1
  131. package/build/Module/Volume.d.ts +0 -20
  132. package/build/Module/Volume.js +0 -48
  133. package/build/Module/Volume.js.map +0 -1
  134. package/build/Module/index.d.ts +0 -14
  135. package/build/Module/index.js +0 -66
  136. package/build/Module/index.js.map +0 -1
  137. package/build/Note/frequencyTable.js +0 -146
  138. package/build/Note/frequencyTable.js.map +0 -1
  139. package/build/Note/index.js +0 -81
  140. package/build/Note/index.js.map +0 -1
  141. package/build/index.d.ts +0 -8
  142. package/build/index.js +0 -5
  143. package/build/index.js.map +0 -1
  144. package/build/routes.js +0 -31
  145. package/build/routes.js.map +0 -1
  146. package/jest.config.js +0 -19
  147. package/src/MidiEvent.ts +0 -93
  148. package/src/Module/Base.ts +0 -223
  149. package/src/Module/DataSequencer.ts +0 -121
  150. package/src/Module/Envelope/AmpEnvelope.ts +0 -17
  151. package/src/Module/IO.ts +0 -85
  152. package/src/Module/PolyModule.ts +0 -234
  153. package/src/Module/VoiceScheduler.ts +0 -161
  154. package/test/Module/Oscillator.test.ts +0 -9
  155. package/tsconfig.json +0 -22
  156. /package/{build → dist/build/core}/Note/frequencyTable.d.ts +0 -0
  157. /package/{build → dist/build/core/midi}/MidiDeviceManager.d.ts +0 -0
  158. /package/{build/Module → dist/build/modules}/Envelope/index.d.ts +0 -0
  159. /package/src/{Note → core/Note}/frequencyTable.ts +0 -0
  160. /package/src/{MidiDevice.ts → core/midi/MidiDevice.ts} +0 -0
  161. /package/src/{Module → modules}/Envelope/index.ts +0 -0
package/package.json CHANGED
@@ -1,42 +1,46 @@
1
1
  {
2
2
  "name": "@blibliki/engine",
3
- "version": "0.1.17",
4
- "main": "build/index.js",
5
- "types": "build/index.d.ts",
3
+ "version": "0.1.19",
4
+ "main": "dist/main.cjs.js",
5
+ "module": "dist/main.esm.js",
6
+ "types": "dist/build/index.d.ts",
7
+ "files": [
8
+ "README.md",
9
+ "src",
10
+ "dist"
11
+ ],
6
12
  "dependencies": {
7
13
  "@types/lodash": "^4.14.186",
14
+ "crypto-js": "^4.2.0",
8
15
  "lodash": "^4.17.21",
9
16
  "tone": "^14.7.77",
10
17
  "uuid": "^8.3.2"
11
18
  },
12
19
  "scripts": {
13
20
  "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
- ]
21
+ "build": "rollup -c",
22
+ "lint": "eslint src",
23
+ "ts:check": "tsc --noEmit",
24
+ "test": "jest"
30
25
  },
31
26
  "devDependencies": {
27
+ "@rollup/plugin-commonjs": "^25.0.7",
28
+ "@rollup/plugin-node-resolve": "^15.2.3",
29
+ "@rollup/plugin-terser": "^0.4.4",
30
+ "@rollup/plugin-typescript": "^11.1.6",
31
+ "@types/crypto-js": "^4.2.2",
32
32
  "@types/jest": "^29.2.0",
33
33
  "@types/node": "^16.7.13",
34
34
  "@types/uuid": "^8.3.4",
35
- "eslint": "^8.18.0",
35
+ "@typescript-eslint/eslint-plugin": "^6.9.0",
36
+ "@typescript-eslint/parser": "^6.9.0",
37
+ "eslint": "^8.52.0",
36
38
  "jest": "^29.2.2",
37
39
  "prettier": "^2.7.1",
40
+ "rollup": "^4.10.0",
41
+ "rollup-plugin-dts": "^6.1.0",
38
42
  "ts-jest": "^29.0.3",
39
- "typescript": "^4.7.4",
40
- "typescript-language-server": "^0.11.1"
43
+ "typescript": "^5.2.2",
44
+ "typescript-language-server": "^4.0.0"
41
45
  }
42
46
  }
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;
@@ -51,7 +48,7 @@ class Engine {
51
48
 
52
49
  initialize(props: InitializeInterface) {
53
50
  return new Promise((resolve) => {
54
- if (this.context) return resolve({ master: this.master });
51
+ if (this.context) return resolve({});
55
52
 
56
53
  this.context = new Context(props.context);
57
54
  setContext(this.context);
@@ -60,15 +57,20 @@ class Engine {
60
57
  this.midiDeviceManager = new MidiDeviceManager();
61
58
 
62
59
  setTimeout(() => {
63
- resolve({ master: this.master });
60
+ resolve({});
64
61
  }, 0);
65
62
  });
66
63
  }
67
64
 
68
- addModule(params: { name: string; type: string; props?: any }) {
69
- const { name, type, props = {} } = params;
65
+ addModule(params: {
66
+ id?: string;
67
+ name: string;
68
+ type: string;
69
+ props?: AnyObject;
70
+ }) {
71
+ const { id, name, type, props = {} } = params;
70
72
 
71
- const audioModule = createModule(name, type, {});
73
+ const audioModule = createModule({ id, name, type, props: {} });
72
74
  audioModule.props = props;
73
75
  this.modules[audioModule.id] = audioModule;
74
76
 
@@ -95,15 +97,15 @@ class Engine {
95
97
  return audioModule.serialize();
96
98
  }
97
99
 
98
- onPropsUpdate(callback: (id: string, props: any) => void) {
100
+ onPropsUpdate(callback: (id: string, props: AnyObject) => void) {
99
101
  this.propsUpdateCallbacks.push(callback);
100
102
  }
101
103
 
102
- _triggerPropsUpdate(id: string, props: any) {
104
+ _triggerPropsUpdate(id: string, props: AnyObject) {
103
105
  this.propsUpdateCallbacks.forEach((callback) => callback(id, props));
104
106
  }
105
107
 
106
- updatePropsModule(id: string, props: any) {
108
+ updatePropsModule(id: string, props: AnyObject) {
107
109
  const audioModule = this.findById(id);
108
110
 
109
111
  const applyRoutesRequired = this.applyRoutesRequired(audioModule, props);
@@ -113,7 +115,7 @@ class Engine {
113
115
  return audioModule.serialize();
114
116
  }
115
117
 
116
- addRoute(props: RouteProps) {
118
+ addRoute(props: Optional<RouteInterface, "id">) {
117
119
  const route = createRoute(props);
118
120
  const newRoutes = { ...this.routes, [route.id]: route };
119
121
 
@@ -128,29 +130,18 @@ class Engine {
128
130
  this.updateRoutes();
129
131
  }
130
132
 
131
- get master() {
132
- if (this._master) return this._master.serialize();
133
-
134
- const masterProps = this.addModule({ name: "Master", type: "Master" });
135
- this._master = this.modules[masterProps.id] as Master;
136
-
137
- return masterProps;
138
- }
139
-
140
- triggerVirtualMidi(id: string, noteName: string, type: EType) {
133
+ triggerVirtualMidi(id: string, noteName: string, type: "noteOn" | "noteOff") {
141
134
  const virtualMidi = this.findById(id) as VirtualMidi;
142
135
 
143
- virtualMidi.sendMidi(MidiEvent.fromNote(noteName, type));
136
+ virtualMidi.sendMidi(MidiEvent.fromNote(noteName, type === "noteOn"));
144
137
  }
145
138
 
146
139
  dispose() {
147
140
  Object.values(this.modules).forEach((m) => {
148
- if (m instanceof Master) return;
149
-
150
141
  m.dispose();
151
142
  });
152
143
 
153
- this.modules = this._master ? { [this._master.id]: this._master } : {};
144
+ this.modules = {};
154
145
  this.routes = {};
155
146
  }
156
147
 
@@ -176,7 +167,7 @@ class Engine {
176
167
  this.updateRoutes();
177
168
 
178
169
  Object.values(this.modules).forEach((audioModule) => {
179
- const am = audioModule as any;
170
+ const am = audioModule as unknown as Startable;
180
171
  if (!am.start) return;
181
172
 
182
173
  am.start(startTime);
@@ -186,7 +177,7 @@ class Engine {
186
177
  stop() {
187
178
  const startTime = now();
188
179
  Object.values(this.modules).forEach((audioModule) => {
189
- const am = audioModule as any;
180
+ const am = audioModule as unknown as Startable;
190
181
  if (!am.stop) return;
191
182
 
192
183
  am.stop(startTime);
@@ -207,7 +198,7 @@ class Engine {
207
198
  applyRoutes(Object.values(this.routes));
208
199
  }
209
200
 
210
- private applyRoutesRequired(audioModule: AudioModule, props: any) {
201
+ private applyRoutesRequired(audioModule: AudioModule, props: AnyObject) {
211
202
  if (!props.polyNumber) return false;
212
203
  if (!(audioModule instanceof VoiceScheduler)) return false;
213
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
+ }