@blibliki/engine 0.1.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 +4 -0
- package/build/Engine.d.ts +114 -0
- package/build/Engine.js +81 -0
- package/build/Engine.js.map +1 -0
- package/build/MidiDevice.d.ts +25 -0
- package/build/MidiDevice.js +45 -0
- package/build/MidiDevice.js.map +1 -0
- package/build/MidiDeviceManager.d.ts +12 -0
- package/build/MidiDeviceManager.js +45 -0
- package/build/MidiDeviceManager.js.map +1 -0
- package/build/MidiEvent.d.ts +12 -0
- package/build/MidiEvent.js +37 -0
- package/build/MidiEvent.js.map +1 -0
- package/build/Module/Base.d.ts +72 -0
- package/build/Module/Base.js +139 -0
- package/build/Module/Base.js.map +1 -0
- package/build/Module/Envelope/AmpEnvelope.d.ts +8 -0
- package/build/Module/Envelope/AmpEnvelope.js +15 -0
- package/build/Module/Envelope/AmpEnvelope.js.map +1 -0
- package/build/Module/Envelope/Base.d.ts +45 -0
- package/build/Module/Envelope/Base.js +110 -0
- package/build/Module/Envelope/Base.js.map +1 -0
- package/build/Module/Envelope/FreqEnvelope.d.ts +17 -0
- package/build/Module/Envelope/FreqEnvelope.js +51 -0
- package/build/Module/Envelope/FreqEnvelope.js.map +1 -0
- package/build/Module/Envelope/index.d.ts +3 -0
- package/build/Module/Envelope/index.js +4 -0
- package/build/Module/Envelope/index.js.map +1 -0
- package/build/Module/Filter.d.ts +31 -0
- package/build/Module/Filter.js +83 -0
- package/build/Module/Filter.js.map +1 -0
- package/build/Module/IO.d.ts +39 -0
- package/build/Module/IO.js +59 -0
- package/build/Module/IO.js.map +1 -0
- package/build/Module/Master.d.ts +7 -0
- package/build/Module/Master.js +12 -0
- package/build/Module/Master.js.map +1 -0
- package/build/Module/MidiSelector.d.ts +16 -0
- package/build/Module/MidiSelector.js +44 -0
- package/build/Module/MidiSelector.js.map +1 -0
- package/build/Module/Oscillator.d.ts +42 -0
- package/build/Module/Oscillator.js +123 -0
- package/build/Module/Oscillator.js.map +1 -0
- package/build/Module/PolyModule.d.ts +57 -0
- package/build/Module/PolyModule.js +191 -0
- package/build/Module/PolyModule.js.map +1 -0
- package/build/Module/VoiceScheduler.d.ts +37 -0
- package/build/Module/VoiceScheduler.js +117 -0
- package/build/Module/VoiceScheduler.js.map +1 -0
- package/build/Module/Volume.d.ts +15 -0
- package/build/Module/Volume.js +34 -0
- package/build/Module/Volume.js.map +1 -0
- package/build/Module/index.d.ts +20 -0
- package/build/Module/index.js +60 -0
- package/build/Module/index.js.map +1 -0
- package/build/Note/frequencyTable.d.ts +4 -0
- package/build/Note/frequencyTable.js +146 -0
- package/build/Note/frequencyTable.js.map +1 -0
- package/build/Note/index.d.ts +13 -0
- package/build/Note/index.js +53 -0
- package/build/Note/index.js.map +1 -0
- package/build/index.d.ts +8 -0
- package/build/index.js +6 -0
- package/build/index.js.map +1 -0
- package/build/routes.d.ts +17 -0
- package/build/routes.js +23 -0
- package/build/routes.js.map +1 -0
- package/package.json +37 -0
- package/src/Engine.ts +129 -0
- package/src/MidiDevice.ts +67 -0
- package/src/MidiDeviceManager.ts +61 -0
- package/src/MidiEvent.ts +44 -0
- package/src/Module/Base.ts +200 -0
- package/src/Module/Envelope/AmpEnvelope.ts +17 -0
- package/src/Module/Envelope/Base.ts +159 -0
- package/src/Module/Envelope/FreqEnvelope.ts +69 -0
- package/src/Module/Envelope/index.ts +3 -0
- package/src/Module/Filter.ts +111 -0
- package/src/Module/IO.ts +85 -0
- package/src/Module/Master.ts +18 -0
- package/src/Module/MidiSelector.ts +64 -0
- package/src/Module/Oscillator.ts +166 -0
- package/src/Module/PolyModule.ts +243 -0
- package/src/Module/VoiceScheduler.ts +153 -0
- package/src/Module/Volume.ts +46 -0
- package/src/Module/index.ts +78 -0
- package/src/Note/frequencyTable.ts +146 -0
- package/src/Note/index.ts +65 -0
- package/src/index.ts +10 -0
- package/src/routes.ts +41 -0
- package/tsconfig.json +22 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ModuleType } from "./Base";
|
|
2
|
+
import { PolyModuleType } from "./PolyModule";
|
|
3
|
+
import Oscillator, { PolyOscillator } from "./Oscillator";
|
|
4
|
+
import { Envelope, AmpEnvelope, FreqEnvelope } from "./Envelope";
|
|
5
|
+
import Filter, { PolyFilter } from "./Filter";
|
|
6
|
+
import Master from "./Master";
|
|
7
|
+
import VoiceScheduler, { Voice } from "./VoiceScheduler";
|
|
8
|
+
import MidiSelector from "./MidiSelector";
|
|
9
|
+
import { PolyAmpEnvelope } from "./Envelope/AmpEnvelope";
|
|
10
|
+
import { PolyFreqEnvelope } from "./Envelope/FreqEnvelope";
|
|
11
|
+
import { PolyEnvelope } from "./Envelope/Base";
|
|
12
|
+
import Volume, { PolyVolume } from "./Volume";
|
|
13
|
+
export { default, ModuleType } from "./Base";
|
|
14
|
+
export { default as PolyModule, PolyModuleType } from "./PolyModule";
|
|
15
|
+
export { default as Filter } from "./Filter";
|
|
16
|
+
export { default as Oscillator } from "./Oscillator";
|
|
17
|
+
export { Envelope, AmpEnvelope, FreqEnvelope, EnvelopeStages, } from "./Envelope";
|
|
18
|
+
export function createModule(name, type, props) {
|
|
19
|
+
const klass = moduleClassFromType(type);
|
|
20
|
+
return new klass(name, props);
|
|
21
|
+
}
|
|
22
|
+
export function moduleClassFromType(type) {
|
|
23
|
+
switch (type) {
|
|
24
|
+
case ModuleType.Oscillator:
|
|
25
|
+
return Oscillator;
|
|
26
|
+
case ModuleType.Envelope:
|
|
27
|
+
return Envelope;
|
|
28
|
+
case ModuleType.AmpEnvelope:
|
|
29
|
+
return AmpEnvelope;
|
|
30
|
+
case ModuleType.FreqEnvelope:
|
|
31
|
+
return FreqEnvelope;
|
|
32
|
+
case ModuleType.Filter:
|
|
33
|
+
return Filter;
|
|
34
|
+
case ModuleType.Volume:
|
|
35
|
+
return Volume;
|
|
36
|
+
case PolyModuleType.Oscillator:
|
|
37
|
+
return PolyOscillator;
|
|
38
|
+
case PolyModuleType.Envelope:
|
|
39
|
+
return PolyEnvelope;
|
|
40
|
+
case PolyModuleType.AmpEnvelope:
|
|
41
|
+
return PolyAmpEnvelope;
|
|
42
|
+
case PolyModuleType.FreqEnvelope:
|
|
43
|
+
return PolyFreqEnvelope;
|
|
44
|
+
case PolyModuleType.Filter:
|
|
45
|
+
return PolyFilter;
|
|
46
|
+
case PolyModuleType.Volume:
|
|
47
|
+
return PolyVolume;
|
|
48
|
+
case ModuleType.Master:
|
|
49
|
+
return Master;
|
|
50
|
+
case ModuleType.Voice:
|
|
51
|
+
return Voice;
|
|
52
|
+
case PolyModuleType.VoiceScheduler:
|
|
53
|
+
return VoiceScheduler;
|
|
54
|
+
case ModuleType.MidiSelector:
|
|
55
|
+
return MidiSelector;
|
|
56
|
+
default:
|
|
57
|
+
throw Error("Unknown module type");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/Module/index.ts"],"names":[],"mappings":"AAAA,OAAe,EAAe,UAAU,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAmB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,UAAU,EAAE,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,MAAM,MAAM,UAAU,CAAC;AAC9B,OAAO,cAAc,EAAE,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE9C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGrE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EACL,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,cAAc,GACf,MAAM,YAAY,CAAC;AAMpB,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,IAAY,EACZ,KAAU;IAEV,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAExC,OAAO,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,QAAQ,IAAI,EAAE;QACZ,KAAK,UAAU,CAAC,UAAU;YACxB,OAAO,UAAU,CAAC;QACpB,KAAK,UAAU,CAAC,QAAQ;YACtB,OAAO,QAAQ,CAAC;QAClB,KAAK,UAAU,CAAC,WAAW;YACzB,OAAO,WAAW,CAAC;QACrB,KAAK,UAAU,CAAC,YAAY;YAC1B,OAAO,YAAY,CAAC;QACtB,KAAK,UAAU,CAAC,MAAM;YACpB,OAAO,MAAM,CAAC;QAChB,KAAK,UAAU,CAAC,MAAM;YACpB,OAAO,MAAM,CAAC;QAChB,KAAK,cAAc,CAAC,UAAU;YAC5B,OAAO,cAAc,CAAC;QACxB,KAAK,cAAc,CAAC,QAAQ;YAC1B,OAAO,YAAY,CAAC;QACtB,KAAK,cAAc,CAAC,WAAW;YAC7B,OAAO,eAAe,CAAC;QACzB,KAAK,cAAc,CAAC,YAAY;YAC9B,OAAO,gBAAgB,CAAC;QAC1B,KAAK,cAAc,CAAC,MAAM;YACxB,OAAO,UAAU,CAAC;QACpB,KAAK,cAAc,CAAC,MAAM;YACxB,OAAO,UAAU,CAAC;QACpB,KAAK,UAAU,CAAC,MAAM;YACpB,OAAO,MAAM,CAAC;QAChB,KAAK,UAAU,CAAC,KAAK;YACnB,OAAO,KAAK,CAAC;QACf,KAAK,cAAc,CAAC,cAAc;YAChC,OAAO,cAAc,CAAC;QACxB,KAAK,UAAU,CAAC,YAAY;YAC1B,OAAO,YAAY,CAAC;QACtB;YACE,MAAM,KAAK,CAAC,qBAAqB,CAAC,CAAC;KACtC;AACH,CAAC"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
const frequencyTable = {
|
|
2
|
+
C0: 16.35,
|
|
3
|
+
"C#0": 17.32,
|
|
4
|
+
Db0: 17.32,
|
|
5
|
+
D0: 18.35,
|
|
6
|
+
"D#0": 19.45,
|
|
7
|
+
Eb0: 19.45,
|
|
8
|
+
E0: 20.6,
|
|
9
|
+
F0: 21.83,
|
|
10
|
+
"F#0": 23.12,
|
|
11
|
+
Gb0: 23.12,
|
|
12
|
+
G0: 24.5,
|
|
13
|
+
"G#0": 25.96,
|
|
14
|
+
Ab0: 25.96,
|
|
15
|
+
A0: 27.5,
|
|
16
|
+
"A#0": 29.14,
|
|
17
|
+
Bb0: 29.14,
|
|
18
|
+
B0: 30.87,
|
|
19
|
+
C1: 32.7,
|
|
20
|
+
"C#1": 34.65,
|
|
21
|
+
Db1: 34.65,
|
|
22
|
+
D1: 36.71,
|
|
23
|
+
"D#1": 38.89,
|
|
24
|
+
Eb1: 38.89,
|
|
25
|
+
E1: 41.2,
|
|
26
|
+
F1: 43.65,
|
|
27
|
+
"F#1": 46.25,
|
|
28
|
+
Gb1: 46.25,
|
|
29
|
+
G1: 49.0,
|
|
30
|
+
"G#1": 51.91,
|
|
31
|
+
Ab1: 51.91,
|
|
32
|
+
A1: 55.0,
|
|
33
|
+
"A#1": 58.27,
|
|
34
|
+
Bb1: 58.27,
|
|
35
|
+
B1: 61.74,
|
|
36
|
+
C2: 65.41,
|
|
37
|
+
"C#2": 69.3,
|
|
38
|
+
Db2: 69.3,
|
|
39
|
+
D2: 73.42,
|
|
40
|
+
"D#2": 77.78,
|
|
41
|
+
Eb2: 77.78,
|
|
42
|
+
E2: 82.41,
|
|
43
|
+
F2: 87.31,
|
|
44
|
+
"F#2": 92.5,
|
|
45
|
+
Gb2: 92.5,
|
|
46
|
+
G2: 98.0,
|
|
47
|
+
"G#2": 103.83,
|
|
48
|
+
Ab2: 103.83,
|
|
49
|
+
A2: 110.0,
|
|
50
|
+
"A#2": 116.54,
|
|
51
|
+
Bb2: 116.54,
|
|
52
|
+
B2: 123.47,
|
|
53
|
+
C3: 130.81,
|
|
54
|
+
"C#3": 138.59,
|
|
55
|
+
Db3: 138.59,
|
|
56
|
+
D3: 146.83,
|
|
57
|
+
"D#3": 155.56,
|
|
58
|
+
Eb3: 155.56,
|
|
59
|
+
E3: 164.81,
|
|
60
|
+
F3: 174.61,
|
|
61
|
+
"F#3": 185.0,
|
|
62
|
+
Gb3: 185.0,
|
|
63
|
+
G3: 196.0,
|
|
64
|
+
"G#3": 207.65,
|
|
65
|
+
Ab3: 207.65,
|
|
66
|
+
A3: 220.0,
|
|
67
|
+
"A#3": 233.08,
|
|
68
|
+
Bb3: 233.08,
|
|
69
|
+
B3: 246.94,
|
|
70
|
+
C4: 261.63,
|
|
71
|
+
"C#4": 277.18,
|
|
72
|
+
Db4: 277.18,
|
|
73
|
+
D4: 293.66,
|
|
74
|
+
"D#4": 311.13,
|
|
75
|
+
Eb4: 311.13,
|
|
76
|
+
E4: 329.63,
|
|
77
|
+
F4: 349.23,
|
|
78
|
+
"F#4": 369.99,
|
|
79
|
+
Gb4: 369.99,
|
|
80
|
+
G4: 392.0,
|
|
81
|
+
"G#4": 415.3,
|
|
82
|
+
Ab4: 415.3,
|
|
83
|
+
A4: 440.0,
|
|
84
|
+
"A#4": 466.16,
|
|
85
|
+
Bb4: 466.16,
|
|
86
|
+
B4: 493.88,
|
|
87
|
+
C5: 523.25,
|
|
88
|
+
"C#5": 554.37,
|
|
89
|
+
Db5: 554.37,
|
|
90
|
+
D5: 587.33,
|
|
91
|
+
"D#5": 622.25,
|
|
92
|
+
Eb5: 622.25,
|
|
93
|
+
E5: 659.26,
|
|
94
|
+
F5: 698.46,
|
|
95
|
+
"F#5": 739.99,
|
|
96
|
+
Gb5: 739.99,
|
|
97
|
+
G5: 783.99,
|
|
98
|
+
"G#5": 830.61,
|
|
99
|
+
Ab5: 830.61,
|
|
100
|
+
A5: 880.0,
|
|
101
|
+
"A#5": 932.33,
|
|
102
|
+
Bb5: 932.33,
|
|
103
|
+
B5: 987.77,
|
|
104
|
+
C6: 1046.5,
|
|
105
|
+
"C#6": 1108.73,
|
|
106
|
+
Db6: 1108.73,
|
|
107
|
+
D6: 1174.66,
|
|
108
|
+
"D#6": 1244.51,
|
|
109
|
+
Eb6: 1244.51,
|
|
110
|
+
E6: 1318.51,
|
|
111
|
+
F6: 1396.91,
|
|
112
|
+
"F#6": 1479.98,
|
|
113
|
+
Gb6: 1479.98,
|
|
114
|
+
G6: 1567.98,
|
|
115
|
+
"G#6": 1661.22,
|
|
116
|
+
Ab6: 1661.22,
|
|
117
|
+
A6: 1760.0,
|
|
118
|
+
"A#6": 1864.66,
|
|
119
|
+
Bb6: 1864.66,
|
|
120
|
+
B6: 1975.53,
|
|
121
|
+
C7: 2093.0,
|
|
122
|
+
"C#7": 2217.46,
|
|
123
|
+
Db7: 2217.46,
|
|
124
|
+
D7: 2349.32,
|
|
125
|
+
"D#7": 2489.02,
|
|
126
|
+
Eb7: 2489.02,
|
|
127
|
+
E7: 2637.02,
|
|
128
|
+
F7: 2793.83,
|
|
129
|
+
"F#7": 2959.96,
|
|
130
|
+
Gb7: 2959.96,
|
|
131
|
+
G7: 3135.96,
|
|
132
|
+
"G#7": 3322.44,
|
|
133
|
+
Ab7: 3322.44,
|
|
134
|
+
A7: 3520.0,
|
|
135
|
+
"A#7": 3729.31,
|
|
136
|
+
Bb7: 3729.31,
|
|
137
|
+
B7: 3951.07,
|
|
138
|
+
C8: 4186.01,
|
|
139
|
+
"C#8": 4434.92,
|
|
140
|
+
Db8: 4434.92,
|
|
141
|
+
D8: 4698.64,
|
|
142
|
+
"D#8": 4978.03,
|
|
143
|
+
Eb8: 4978.03,
|
|
144
|
+
};
|
|
145
|
+
export default frequencyTable;
|
|
146
|
+
//# sourceMappingURL=frequencyTable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frequencyTable.js","sourceRoot":"","sources":["../../src/Note/frequencyTable.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default class Note {
|
|
2
|
+
static _notes: Note[];
|
|
3
|
+
name: string;
|
|
4
|
+
octave: number;
|
|
5
|
+
constructor(eventOrString: MIDIMessageEvent | string);
|
|
6
|
+
static notes(octave?: number): Note[];
|
|
7
|
+
get isSemi(): boolean;
|
|
8
|
+
get fullName(): string;
|
|
9
|
+
frequency(range?: number, coarse?: number): number;
|
|
10
|
+
valueOf(): string;
|
|
11
|
+
private fromString;
|
|
12
|
+
private fromEvent;
|
|
13
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import frequencyTable from "./frequencyTable";
|
|
2
|
+
const Notes = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
|
|
3
|
+
const NotesLength = Notes.length;
|
|
4
|
+
export default class Note {
|
|
5
|
+
static _notes;
|
|
6
|
+
name;
|
|
7
|
+
octave;
|
|
8
|
+
constructor(eventOrString) {
|
|
9
|
+
if (typeof eventOrString === "string") {
|
|
10
|
+
this.fromString(eventOrString);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
this.fromEvent(eventOrString);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
static notes(octave = 3) {
|
|
17
|
+
return Notes.map((note) => new Note(`${note}${octave}`));
|
|
18
|
+
}
|
|
19
|
+
get isSemi() {
|
|
20
|
+
return this.name.slice(-1) === "#";
|
|
21
|
+
}
|
|
22
|
+
get fullName() {
|
|
23
|
+
return `${this.name}${this.octave}`;
|
|
24
|
+
}
|
|
25
|
+
frequency(range = 0, coarse = 0) {
|
|
26
|
+
let newOctave = this.octave + range;
|
|
27
|
+
let coarseIndex = Notes.indexOf(this.name) + coarse;
|
|
28
|
+
let nameIndex = coarseIndex;
|
|
29
|
+
if (coarseIndex >= NotesLength) {
|
|
30
|
+
newOctave++;
|
|
31
|
+
nameIndex = coarseIndex % NotesLength;
|
|
32
|
+
}
|
|
33
|
+
else if (coarseIndex < 0) {
|
|
34
|
+
newOctave--;
|
|
35
|
+
nameIndex = NotesLength + nameIndex;
|
|
36
|
+
}
|
|
37
|
+
const newName = Notes[nameIndex];
|
|
38
|
+
return frequencyTable[`${newName}${newOctave}`];
|
|
39
|
+
}
|
|
40
|
+
valueOf() {
|
|
41
|
+
return this.fullName;
|
|
42
|
+
}
|
|
43
|
+
fromString(string) {
|
|
44
|
+
const matches = string.match(/(\w#?)(\d)?/) || [];
|
|
45
|
+
this.name = matches[1];
|
|
46
|
+
this.octave = matches[2] ? parseInt(matches[2]) : 1;
|
|
47
|
+
}
|
|
48
|
+
fromEvent(event) {
|
|
49
|
+
this.name = Notes[event.data[1] % 12];
|
|
50
|
+
this.octave = Math.floor(event.data[1] / 12) - 2;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/Note/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAE9C,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;AAEhF,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC;AAEjC,MAAM,CAAC,OAAO,OAAO,IAAI;IACvB,MAAM,CAAC,MAAM,CAAS;IACtB,IAAI,CAAS;IACb,MAAM,CAAS;IAEf,YAAY,aAAwC;QAClD,IAAI,OAAO,aAAa,KAAK,QAAQ,EAAE;YACrC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;SAChC;aAAM;YACL,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;SAC/B;IACH,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,SAAiB,CAAC;QAC7B,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC;IACnE,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;IACrC,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;IACtC,CAAC;IAED,SAAS,CAAC,QAAgB,CAAC,EAAE,SAAiB,CAAC;QAC7C,IAAI,SAAS,GAAG,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpC,IAAI,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;QACpD,IAAI,SAAS,GAAG,WAAW,CAAC;QAE5B,IAAI,WAAW,IAAI,WAAW,EAAE;YAC9B,SAAS,EAAE,CAAC;YACZ,SAAS,GAAG,WAAW,GAAG,WAAW,CAAC;SACvC;aAAM,IAAI,WAAW,GAAG,CAAC,EAAE;YAC1B,SAAS,EAAE,CAAC;YACZ,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;SACrC;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;QAEjC,OAAO,cAAc,CAAC,GAAG,OAAO,GAAG,SAAS,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAEO,UAAU,CAAC,MAAc;QAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;QAElD,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC;IAEO,SAAS,CAAC,KAAuB;QACvC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;IACnD,CAAC;CACF"}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { default } from "./Engine";
|
|
2
|
+
export { ModuleType, PolyModuleType } from "./Module";
|
|
3
|
+
export { default as MidiDevice } from "./MidiDevice";
|
|
4
|
+
export { default as MidiDeviceManager } from "./MidiDeviceManager";
|
|
5
|
+
export { default as Note } from "./Note";
|
|
6
|
+
export type { MidiDeviceInterface } from "./MidiDevice";
|
|
7
|
+
export type { ModuleInterface, AudioModule } from "./Module";
|
|
8
|
+
export type { SerializeInterface as IOProps } from "./Module/IO";
|
package/build/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { default } from "./Engine";
|
|
2
|
+
export { ModuleType, PolyModuleType } from "./Module";
|
|
3
|
+
export { default as MidiDevice } from "./MidiDevice";
|
|
4
|
+
export { default as MidiDeviceManager } from "./MidiDeviceManager";
|
|
5
|
+
export { default as Note } from "./Note";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface RouteProps {
|
|
2
|
+
sourceId: string;
|
|
3
|
+
outputName: string;
|
|
4
|
+
destinationId: string;
|
|
5
|
+
inputName: string;
|
|
6
|
+
}
|
|
7
|
+
export interface RouteInterface extends RouteProps {
|
|
8
|
+
id: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function createRoute(props: RouteProps): {
|
|
11
|
+
id: string;
|
|
12
|
+
sourceId: string;
|
|
13
|
+
outputName: string;
|
|
14
|
+
destinationId: string;
|
|
15
|
+
inputName: string;
|
|
16
|
+
};
|
|
17
|
+
export declare function applyRoutes(routes: RouteInterface[]): void;
|
package/build/routes.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from "uuid";
|
|
2
|
+
import Engine from "./";
|
|
3
|
+
export function createRoute(props) {
|
|
4
|
+
const id = uuidv4();
|
|
5
|
+
return { ...props, id };
|
|
6
|
+
}
|
|
7
|
+
export function applyRoutes(routes) {
|
|
8
|
+
Object.values(Engine.modules).forEach((m) => m.unplugAll());
|
|
9
|
+
const succesedConnections = routes.map((route) => {
|
|
10
|
+
const { sourceId, outputName, destinationId, inputName } = route;
|
|
11
|
+
const source = Engine.findById(sourceId);
|
|
12
|
+
const destination = Engine.findById(destinationId);
|
|
13
|
+
source.plug(destination, outputName, inputName);
|
|
14
|
+
return true;
|
|
15
|
+
});
|
|
16
|
+
if (succesedConnections.every((v) => v)) {
|
|
17
|
+
console.log("######## Routes succesfully applied");
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
console.log("######## Routes partialy applied");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,MAAM,MAAM,IAAI,CAAC;AAaxB,MAAM,UAAU,WAAW,CAAC,KAAiB;IAC3C,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IAEpB,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAwB;IAClD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;IAE5D,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAC/C,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;QAEjE,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QAEnD,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;QAEhD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,IAAI,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE;QACvC,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;KACpD;SAAM;QACL,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;KACjD;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@blibliki/engine",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"main": "build/index.js",
|
|
5
|
+
"types": "build/index.d.ts",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"tone": "^14.7.77",
|
|
8
|
+
"uuid": "^8.3.2"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "tsc -w -p tsconfig.json",
|
|
12
|
+
"build": "rm -rf build && tsc"
|
|
13
|
+
},
|
|
14
|
+
"eslintConfig": {
|
|
15
|
+
"extends": []
|
|
16
|
+
},
|
|
17
|
+
"browserslist": {
|
|
18
|
+
"production": [
|
|
19
|
+
">0.2%",
|
|
20
|
+
"not dead",
|
|
21
|
+
"not op_mini all"
|
|
22
|
+
],
|
|
23
|
+
"development": [
|
|
24
|
+
"last 1 chrome version",
|
|
25
|
+
"last 1 firefox version",
|
|
26
|
+
"last 1 safari version"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^16.7.13",
|
|
31
|
+
"@types/uuid": "^8.3.4",
|
|
32
|
+
"eslint": "^8.18.0",
|
|
33
|
+
"prettier": "^2.7.1",
|
|
34
|
+
"typescript": "^4.7.4",
|
|
35
|
+
"typescript-language-server": "^0.11.1"
|
|
36
|
+
}
|
|
37
|
+
}
|
package/src/Engine.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { Context, setContext } from "tone";
|
|
2
|
+
|
|
3
|
+
import { ModuleType, PolyModule } from "./Module";
|
|
4
|
+
import { AudioModule, createModule } from "./Module";
|
|
5
|
+
import Master from "./Module/Master";
|
|
6
|
+
import VoiceScheduler from "./Module/VoiceScheduler";
|
|
7
|
+
import { applyRoutes, createRoute, RouteInterface, RouteProps } from "./routes";
|
|
8
|
+
|
|
9
|
+
type LatencyHint = "interactive" | "playback" | "balanced";
|
|
10
|
+
|
|
11
|
+
interface ContextInterface {
|
|
12
|
+
latencyHint: LatencyHint;
|
|
13
|
+
lookAhead: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface InitializeInterface {
|
|
17
|
+
context?: Partial<ContextInterface>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class Engine {
|
|
21
|
+
private static instance: Engine;
|
|
22
|
+
private _master: Master;
|
|
23
|
+
private context: Context;
|
|
24
|
+
|
|
25
|
+
modules: {
|
|
26
|
+
[Identifier: string]: AudioModule;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
routes: {
|
|
30
|
+
[Identifier: string]: RouteInterface;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
private constructor() {
|
|
34
|
+
this.modules = {};
|
|
35
|
+
this.routes = {};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public static getInstance(): Engine {
|
|
39
|
+
if (!Engine.instance) {
|
|
40
|
+
Engine.instance = new Engine();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return Engine.instance;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
initialize(props: InitializeInterface) {
|
|
47
|
+
this.context = new Context(props.context);
|
|
48
|
+
setContext(this.context);
|
|
49
|
+
this.context.transport.start();
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
master: this.master,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
registerModule(name: string, type: string, props: any = {}) {
|
|
57
|
+
const audioModule = createModule(name, type, props);
|
|
58
|
+
this.modules[audioModule.id] = audioModule;
|
|
59
|
+
|
|
60
|
+
applyRoutes(Object.values(this.routes));
|
|
61
|
+
|
|
62
|
+
return audioModule.serialize();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
updateNameModule(id: string, name: string) {
|
|
66
|
+
const audioModule = this.findById(id);
|
|
67
|
+
audioModule.name = name;
|
|
68
|
+
|
|
69
|
+
return audioModule.serialize();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
updatePropsModule(id: string, props: any) {
|
|
73
|
+
const audioModule = this.findById(id);
|
|
74
|
+
|
|
75
|
+
const polyNumber =
|
|
76
|
+
audioModule instanceof VoiceScheduler && audioModule.polyNumber;
|
|
77
|
+
audioModule.props = props;
|
|
78
|
+
const { polyNumber: newPolyNumber } = props;
|
|
79
|
+
|
|
80
|
+
if (polyNumber !== newPolyNumber) applyRoutes(Object.values(this.routes));
|
|
81
|
+
|
|
82
|
+
return audioModule.serialize();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
addRoute(props: RouteProps) {
|
|
86
|
+
const route = createRoute(props);
|
|
87
|
+
const newRoutes = { ...this.routes, [route.id]: route };
|
|
88
|
+
|
|
89
|
+
applyRoutes(Object.values(newRoutes));
|
|
90
|
+
this.routes = newRoutes;
|
|
91
|
+
|
|
92
|
+
return route;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
removeRoute(route: RouteInterface) {
|
|
96
|
+
delete this.routes[route.id];
|
|
97
|
+
applyRoutes(Object.values(this.routes));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
get master() {
|
|
101
|
+
if (this._master) return this._master.serialize();
|
|
102
|
+
|
|
103
|
+
const masterProps = this.registerModule(
|
|
104
|
+
"Master",
|
|
105
|
+
"master",
|
|
106
|
+
ModuleType.Master
|
|
107
|
+
);
|
|
108
|
+
this._master = this.modules[masterProps.id] as Master;
|
|
109
|
+
|
|
110
|
+
return masterProps;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
triggerKey(noteName: string, type: string) {}
|
|
114
|
+
|
|
115
|
+
dispose() {
|
|
116
|
+
Object.values(this.modules).forEach((m) => m.dispose());
|
|
117
|
+
this.modules = {};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
findById(id: string): AudioModule {
|
|
121
|
+
const audioModule = this.modules[id];
|
|
122
|
+
|
|
123
|
+
if (!audioModule) throw Error(`Audio module with id ${id} not exists`);
|
|
124
|
+
|
|
125
|
+
return audioModule;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export default Engine.getInstance();
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import MidiEvent from "./MidiEvent";
|
|
2
|
+
|
|
3
|
+
export interface MidiDeviceInterface {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
state: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type EventListerCallback = (event: MidiEvent) => void;
|
|
10
|
+
|
|
11
|
+
export default class MidiDevice implements MidiDeviceInterface {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
state: string;
|
|
15
|
+
eventListerCallbacks: EventListerCallback[] = [];
|
|
16
|
+
|
|
17
|
+
private _midi: MIDIInput;
|
|
18
|
+
|
|
19
|
+
constructor(midi: MIDIInput) {
|
|
20
|
+
this.id = midi.id;
|
|
21
|
+
this.name = midi.name || `Device ${midi.id}`;
|
|
22
|
+
this.state = midi.state;
|
|
23
|
+
this._midi = midi;
|
|
24
|
+
|
|
25
|
+
this.connect();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
connect() {
|
|
29
|
+
this._midi.onmidimessage = (e) => {
|
|
30
|
+
const isMidiEvent = e instanceof MIDIMessageEvent;
|
|
31
|
+
|
|
32
|
+
if (!isMidiEvent) return;
|
|
33
|
+
|
|
34
|
+
this._processEvent(e);
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
disconnect() {
|
|
39
|
+
this._midi.onmidimessage = null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
serialize() {
|
|
43
|
+
const { id, name, state } = this;
|
|
44
|
+
|
|
45
|
+
return { id, name, state };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
addEventListener(callback: EventListerCallback) {
|
|
49
|
+
this.eventListerCallbacks.push(callback);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
removeEventListener(callback: EventListerCallback) {
|
|
53
|
+
this.eventListerCallbacks = this.eventListerCallbacks.filter(
|
|
54
|
+
(c) => c === callback
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
_processEvent(e: MIDIMessageEvent) {
|
|
59
|
+
const event = new MidiEvent(e);
|
|
60
|
+
|
|
61
|
+
switch (event.type) {
|
|
62
|
+
case "noteOn":
|
|
63
|
+
case "noteOff":
|
|
64
|
+
this.eventListerCallbacks.forEach((callback) => callback(event));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import MidiDevice from "./MidiDevice";
|
|
2
|
+
|
|
3
|
+
class MidiDeviceManager {
|
|
4
|
+
private devices: Array<MidiDevice>;
|
|
5
|
+
private static instance: MidiDeviceManager;
|
|
6
|
+
|
|
7
|
+
public static getInstance(): MidiDeviceManager {
|
|
8
|
+
if (!MidiDeviceManager.instance) {
|
|
9
|
+
MidiDeviceManager.instance = new MidiDeviceManager();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return MidiDeviceManager.instance;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async fetchDevices(): Promise<MidiDevice[]> {
|
|
16
|
+
if (this.devices) return this.devices;
|
|
17
|
+
|
|
18
|
+
this.devices = (await this._inputs()).map((input) => new MidiDevice(input));
|
|
19
|
+
|
|
20
|
+
return this.devices;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async find(id: string): Promise<MidiDevice> {
|
|
24
|
+
const device = (await this.fetchDevices()).find(
|
|
25
|
+
(dev: MidiDevice) => dev.id === id
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
if (!device) throw Error(`Midie device with id ${id} not found`);
|
|
29
|
+
|
|
30
|
+
return device;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async _inputs() {
|
|
34
|
+
const inputs: Array<MIDIInput> = [];
|
|
35
|
+
|
|
36
|
+
const access = await navigator.requestMIDIAccess();
|
|
37
|
+
access.inputs.forEach((input) => inputs.push(input));
|
|
38
|
+
|
|
39
|
+
return inputs;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async onStateChange(callback: Function) {
|
|
43
|
+
const access: MIDIAccess = await navigator.requestMIDIAccess();
|
|
44
|
+
await this.fetchDevices();
|
|
45
|
+
|
|
46
|
+
access.onstatechange = (e) => {
|
|
47
|
+
const isMidiEvent = e instanceof MIDIConnectionEvent;
|
|
48
|
+
|
|
49
|
+
if (!isMidiEvent) return;
|
|
50
|
+
if (e.port instanceof MIDIOutput) return;
|
|
51
|
+
|
|
52
|
+
const input = e.port as MIDIInput;
|
|
53
|
+
|
|
54
|
+
const midi = new MidiDevice(input);
|
|
55
|
+
|
|
56
|
+
callback(midi);
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export default MidiDeviceManager.getInstance();
|