@blibliki/engine 0.1.27 → 0.3.2
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 +252 -76
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +765 -0
- package/dist/index.d.ts +765 -0
- package/dist/index.js +2 -19484
- package/dist/index.js.map +1 -0
- package/package.json +19 -28
- package/src/Engine.ts +158 -177
- package/src/core/IO/AudioIO.ts +72 -0
- package/src/core/IO/Base.ts +118 -0
- package/src/core/IO/Collection.ts +123 -47
- package/src/core/IO/MidiIO.ts +43 -0
- package/src/core/IO/PolyAudioIO.ts +115 -0
- package/src/core/IO/index.ts +7 -61
- package/src/core/Note/frequencyTable.ts +144 -144
- package/src/core/Note/index.ts +49 -59
- package/src/core/Route.ts +79 -0
- package/src/core/Timing/Scheduler.ts +37 -0
- package/src/core/Timing/Time.ts +103 -0
- package/src/core/Timing/Transport.ts +104 -0
- package/src/core/Timing/index.ts +16 -0
- package/src/core/index.ts +36 -0
- package/src/core/midi/{ComputerKeyboardInput.ts → ComputerKeyboardDevice.ts} +31 -11
- package/src/core/midi/MidiDevice.ts +38 -31
- package/src/core/midi/MidiDeviceManager.ts +54 -55
- package/src/core/midi/MidiEvent.ts +36 -60
- package/src/core/module/Module.ts +233 -0
- package/src/core/module/PolyModule.ts +246 -0
- package/src/core/module/VoiceScheduler.ts +121 -0
- package/src/core/module/index.ts +3 -0
- package/src/core/schema.ts +41 -0
- package/src/index.ts +31 -9
- package/src/modules/BiquadFilter.ts +162 -0
- package/src/modules/Constant.ts +72 -0
- package/src/modules/Envelope.ts +178 -0
- package/src/modules/Filter.ts +109 -104
- package/src/modules/Gain.ts +78 -0
- package/src/modules/Inspector.ts +59 -0
- package/src/modules/Master.ts +18 -21
- package/src/modules/MidiSelector.ts +50 -50
- package/src/modules/Oscillator.ts +203 -158
- package/src/modules/Scale.ts +79 -0
- package/src/modules/StepSequencer.ts +61 -0
- package/src/modules/VirtualMidi.ts +33 -49
- package/src/modules/index.ts +159 -74
- package/src/nodePolyfill.ts +25 -0
- package/src/processors/filter-processor.ts +82 -0
- package/src/processors/index.ts +28 -0
- package/src/processors/scale-processor.ts +81 -0
- package/dist/index.umd.cjs +0 -227
- package/dist/src/Engine.d.ts +0 -83
- package/dist/src/core/IO/AudioNode.d.ts +0 -36
- package/dist/src/core/IO/Collection.d.ts +0 -14
- package/dist/src/core/IO/ForwardNode/Base.d.ts +0 -19
- package/dist/src/core/IO/ForwardNode/index.d.ts +0 -28
- package/dist/src/core/IO/MidiNode.d.ts +0 -31
- package/dist/src/core/IO/Node.d.ts +0 -41
- package/dist/src/core/IO/index.d.ts +0 -22
- package/dist/src/core/Module/MonoModule.d.ts +0 -68
- package/dist/src/core/Module/PolyModule.d.ts +0 -62
- package/dist/src/core/Module/index.d.ts +0 -7
- package/dist/src/core/Note/frequencyTable.d.ts +0 -4
- package/dist/src/core/Note/index.d.ts +0 -28
- package/dist/src/core/midi/ComputerKeyboardInput.d.ts +0 -12
- package/dist/src/core/midi/MidiDevice.d.ts +0 -30
- package/dist/src/core/midi/MidiDeviceManager.d.ts +0 -15
- package/dist/src/core/midi/MidiEvent.d.ts +0 -22
- package/dist/src/core/midi/index.d.ts +0 -5
- package/dist/src/index.d.ts +0 -9
- package/dist/src/main.d.ts +0 -0
- package/dist/src/modules/BitCrusher.d.ts +0 -17
- package/dist/src/modules/Delay.d.ts +0 -20
- package/dist/src/modules/Distortion.d.ts +0 -17
- package/dist/src/modules/Effect.d.ts +0 -20
- package/dist/src/modules/Envelope/AmpEnvelope.d.ts +0 -19
- package/dist/src/modules/Envelope/Base.d.ts +0 -67
- package/dist/src/modules/Envelope/FreqEnvelope.d.ts +0 -26
- package/dist/src/modules/Envelope/index.d.ts +0 -3
- package/dist/src/modules/Filter.d.ts +0 -43
- package/dist/src/modules/LFO.d.ts +0 -45
- package/dist/src/modules/Master.d.ts +0 -12
- package/dist/src/modules/MidiSelector.d.ts +0 -22
- package/dist/src/modules/Oscillator.d.ts +0 -56
- package/dist/src/modules/Reverb.d.ts +0 -20
- package/dist/src/modules/Sequencer.d.ts +0 -43
- package/dist/src/modules/VirtualMidi.d.ts +0 -33
- package/dist/src/modules/VoiceScheduler.d.ts +0 -45
- package/dist/src/modules/Volume.d.ts +0 -27
- package/dist/src/modules/index.d.ts +0 -18
- package/dist/src/routes.d.ts +0 -19
- package/dist/src/types.d.ts +0 -5
- package/dist/src/utils.d.ts +0 -1
- package/dist/test/MockingModules.d.ts +0 -22
- package/dist/test/Module/Oscillator.test.d.ts +0 -1
- package/dist/test/core/IO.test.d.ts +0 -1
- package/src/core/IO/AudioNode.ts +0 -82
- package/src/core/IO/ForwardNode/Base.ts +0 -99
- package/src/core/IO/ForwardNode/index.ts +0 -60
- package/src/core/IO/MidiNode.ts +0 -67
- package/src/core/IO/Node.ts +0 -118
- package/src/core/Module/MonoModule.ts +0 -219
- package/src/core/Module/PolyModule.ts +0 -218
- package/src/core/Module/index.ts +0 -15
- package/src/core/midi/index.ts +0 -5
- package/src/main.ts +0 -1
- package/src/modules/BitCrusher.ts +0 -45
- package/src/modules/Delay.ts +0 -53
- package/src/modules/Distortion.ts +0 -45
- package/src/modules/Effect.ts +0 -46
- package/src/modules/Envelope/AmpEnvelope.ts +0 -23
- package/src/modules/Envelope/Base.ts +0 -176
- package/src/modules/Envelope/FreqEnvelope.ts +0 -64
- package/src/modules/Envelope/index.ts +0 -3
- package/src/modules/LFO.ts +0 -149
- package/src/modules/Reverb.ts +0 -53
- package/src/modules/Sequencer.ts +0 -178
- package/src/modules/VoiceScheduler.ts +0 -145
- package/src/modules/Volume.ts +0 -72
- package/src/routes.ts +0 -49
- package/src/types.ts +0 -3
- package/src/utils.ts +0 -18
- package/src/vite-env.d.ts +0 -1
|
@@ -1,146 +1,146 @@
|
|
|
1
|
-
const frequencyTable
|
|
2
|
-
C0
|
|
3
|
-
"C#0"
|
|
4
|
-
Db0
|
|
5
|
-
D0
|
|
6
|
-
"D#0"
|
|
7
|
-
Eb0
|
|
8
|
-
E0
|
|
9
|
-
F0
|
|
10
|
-
"F#0"
|
|
11
|
-
Gb0
|
|
12
|
-
G0
|
|
13
|
-
"G#0"
|
|
14
|
-
Ab0
|
|
15
|
-
A0
|
|
16
|
-
"A#0"
|
|
17
|
-
Bb0
|
|
18
|
-
B0
|
|
19
|
-
C1
|
|
20
|
-
"C#1"
|
|
21
|
-
Db1
|
|
22
|
-
D1
|
|
23
|
-
"D#1"
|
|
24
|
-
Eb1
|
|
25
|
-
E1
|
|
26
|
-
F1
|
|
27
|
-
"F#1"
|
|
28
|
-
Gb1
|
|
29
|
-
G1
|
|
30
|
-
"G#1"
|
|
31
|
-
Ab1
|
|
32
|
-
A1
|
|
33
|
-
"A#1"
|
|
34
|
-
Bb1
|
|
35
|
-
B1
|
|
36
|
-
C2
|
|
37
|
-
"C#2"
|
|
38
|
-
Db2
|
|
39
|
-
D2
|
|
40
|
-
"D#2"
|
|
41
|
-
Eb2
|
|
42
|
-
E2
|
|
43
|
-
F2
|
|
44
|
-
"F#2"
|
|
45
|
-
Gb2
|
|
46
|
-
G2
|
|
47
|
-
"G#2"
|
|
48
|
-
Ab2
|
|
49
|
-
A2
|
|
50
|
-
"A#2"
|
|
51
|
-
Bb2
|
|
52
|
-
B2
|
|
53
|
-
C3
|
|
54
|
-
"C#3"
|
|
55
|
-
Db3
|
|
56
|
-
D3
|
|
57
|
-
"D#3"
|
|
58
|
-
Eb3
|
|
59
|
-
E3
|
|
60
|
-
F3
|
|
61
|
-
"F#3"
|
|
62
|
-
Gb3
|
|
63
|
-
G3
|
|
64
|
-
"G#3"
|
|
65
|
-
Ab3
|
|
66
|
-
A3
|
|
67
|
-
"A#3"
|
|
68
|
-
Bb3
|
|
69
|
-
B3
|
|
70
|
-
C4
|
|
71
|
-
"C#4"
|
|
72
|
-
Db4
|
|
73
|
-
D4
|
|
74
|
-
"D#4"
|
|
75
|
-
Eb4
|
|
76
|
-
E4
|
|
77
|
-
F4
|
|
78
|
-
"F#4"
|
|
79
|
-
Gb4
|
|
80
|
-
G4
|
|
81
|
-
"G#4"
|
|
82
|
-
Ab4
|
|
83
|
-
A4
|
|
84
|
-
"A#4"
|
|
85
|
-
Bb4
|
|
86
|
-
B4
|
|
87
|
-
C5
|
|
88
|
-
"C#5"
|
|
89
|
-
Db5
|
|
90
|
-
D5
|
|
91
|
-
"D#5"
|
|
92
|
-
Eb5
|
|
93
|
-
E5
|
|
94
|
-
F5
|
|
95
|
-
"F#5"
|
|
96
|
-
Gb5
|
|
97
|
-
G5
|
|
98
|
-
"G#5"
|
|
99
|
-
Ab5
|
|
100
|
-
A5
|
|
101
|
-
"A#5"
|
|
102
|
-
Bb5
|
|
103
|
-
B5
|
|
104
|
-
C6
|
|
105
|
-
"C#6"
|
|
106
|
-
Db6
|
|
107
|
-
D6
|
|
108
|
-
"D#6"
|
|
109
|
-
Eb6
|
|
110
|
-
E6
|
|
111
|
-
F6
|
|
112
|
-
"F#6"
|
|
113
|
-
Gb6
|
|
114
|
-
G6
|
|
115
|
-
"G#6"
|
|
116
|
-
Ab6
|
|
117
|
-
A6
|
|
118
|
-
"A#6"
|
|
119
|
-
Bb6
|
|
120
|
-
B6
|
|
121
|
-
C7
|
|
122
|
-
"C#7"
|
|
123
|
-
Db7
|
|
124
|
-
D7
|
|
125
|
-
"D#7"
|
|
126
|
-
Eb7
|
|
127
|
-
E7
|
|
128
|
-
F7
|
|
129
|
-
"F#7"
|
|
130
|
-
Gb7
|
|
131
|
-
G7
|
|
132
|
-
"G#7"
|
|
133
|
-
Ab7
|
|
134
|
-
A7
|
|
135
|
-
"A#7"
|
|
136
|
-
Bb7
|
|
137
|
-
B7
|
|
138
|
-
C8
|
|
139
|
-
"C#8"
|
|
140
|
-
Db8
|
|
141
|
-
D8
|
|
142
|
-
"D#8"
|
|
143
|
-
Eb8
|
|
144
|
-
|
|
1
|
+
const frequencyTable = new Map<string, number>([
|
|
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
145
|
|
|
146
146
|
export default frequencyTable;
|
package/src/core/Note/index.ts
CHANGED
|
@@ -1,55 +1,75 @@
|
|
|
1
|
+
import { Message } from "webmidi";
|
|
2
|
+
import { TTime } from "../Timing/Time";
|
|
1
3
|
import frequencyTable from "./frequencyTable";
|
|
2
4
|
|
|
3
5
|
const Notes = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
|
|
4
6
|
|
|
5
|
-
const NotesLength = Notes.length;
|
|
6
|
-
|
|
7
7
|
const MIDI_OCTAVE_SYTSTEM = 2;
|
|
8
8
|
|
|
9
|
-
export
|
|
10
|
-
|
|
9
|
+
export type INote = {
|
|
10
|
+
name: string;
|
|
11
|
+
octave: number;
|
|
11
12
|
frequency: number;
|
|
12
|
-
duration
|
|
13
|
+
duration?: TTime;
|
|
13
14
|
velocity?: number;
|
|
14
|
-
}
|
|
15
|
+
};
|
|
15
16
|
|
|
16
|
-
export default class Note {
|
|
17
|
+
export default class Note implements INote {
|
|
17
18
|
static _notes: Note[];
|
|
18
|
-
name
|
|
19
|
-
octave
|
|
19
|
+
name!: string;
|
|
20
|
+
octave!: number;
|
|
20
21
|
velocity = 1;
|
|
21
|
-
duration
|
|
22
|
-
frequency: number;
|
|
22
|
+
duration?: TTime;
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
this.fromEvent(eventOrString);
|
|
33
|
-
} else {
|
|
34
|
-
this.fromProps(eventOrString);
|
|
24
|
+
static fromFrequency(frequency: number) {
|
|
25
|
+
let noteName: string | undefined;
|
|
26
|
+
|
|
27
|
+
for (const [note, freq] of frequencyTable) {
|
|
28
|
+
if (freq !== frequency) continue;
|
|
29
|
+
|
|
30
|
+
noteName = note;
|
|
31
|
+
break;
|
|
35
32
|
}
|
|
33
|
+
|
|
34
|
+
if (!noteName) throw Error("Not matching frequency with a note");
|
|
35
|
+
|
|
36
|
+
return new Note(noteName);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static fromEvent(message: Message) {
|
|
40
|
+
const name = Notes[message.data[1] % 12];
|
|
41
|
+
const octave = Math.floor(message.data[1] / 12) - 2;
|
|
42
|
+
|
|
43
|
+
return new Note(`${name}${octave}`);
|
|
36
44
|
}
|
|
37
45
|
|
|
38
46
|
static notes(octave = 3) {
|
|
39
47
|
return Notes.map((note: string) => new Note(`${note}${octave}`));
|
|
40
48
|
}
|
|
41
49
|
|
|
50
|
+
constructor(note: Omit<INote, "frequency"> | string) {
|
|
51
|
+
if (typeof note === "string") {
|
|
52
|
+
this.fromString(note);
|
|
53
|
+
} else {
|
|
54
|
+
this.fromProps(note);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
42
58
|
get isSemi() {
|
|
43
|
-
return this.name.
|
|
59
|
+
return this.name.endsWith("#");
|
|
44
60
|
}
|
|
45
61
|
|
|
46
62
|
get fullName() {
|
|
47
63
|
return `${this.name}${this.octave}`;
|
|
48
64
|
}
|
|
49
65
|
|
|
50
|
-
|
|
66
|
+
get frequency(): number {
|
|
67
|
+
return frequencyTable.get(`${this.name}${this.octave}`)!;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
midiData(noteOn = true): Uint8Array {
|
|
51
71
|
const statusByte = noteOn ? 0x90 : 0x80;
|
|
52
|
-
return new Uint8Array([statusByte,
|
|
72
|
+
return new Uint8Array([statusByte, this.midiNumber, this.velocity * 100]);
|
|
53
73
|
}
|
|
54
74
|
|
|
55
75
|
get midiNumber(): number {
|
|
@@ -60,58 +80,28 @@ export default class Note {
|
|
|
60
80
|
return Notes.indexOf(this.name);
|
|
61
81
|
}
|
|
62
82
|
|
|
63
|
-
adjustFrequency(range = 0, coarse = 0) {
|
|
64
|
-
if (this.frequency) return this.frequency;
|
|
65
|
-
|
|
66
|
-
let newOctave = this.octave + range;
|
|
67
|
-
const coarseIndex = Notes.indexOf(this.name) + coarse;
|
|
68
|
-
let nameIndex = coarseIndex;
|
|
69
|
-
|
|
70
|
-
if (coarseIndex >= NotesLength) {
|
|
71
|
-
newOctave++;
|
|
72
|
-
nameIndex = coarseIndex % NotesLength;
|
|
73
|
-
} else if (coarseIndex < 0) {
|
|
74
|
-
newOctave--;
|
|
75
|
-
nameIndex = NotesLength + nameIndex;
|
|
76
|
-
}
|
|
77
|
-
const newName = Notes[nameIndex];
|
|
78
|
-
|
|
79
|
-
return frequencyTable[`${newName}${newOctave}`];
|
|
80
|
-
}
|
|
81
|
-
|
|
82
83
|
valueOf() {
|
|
83
84
|
return this.fullName;
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
serialize(): INote {
|
|
87
88
|
return {
|
|
88
|
-
|
|
89
|
+
name: this.name,
|
|
90
|
+
octave: this.octave,
|
|
89
91
|
frequency: this.frequency,
|
|
90
92
|
velocity: this.velocity,
|
|
91
93
|
duration: this.duration,
|
|
92
94
|
};
|
|
93
95
|
}
|
|
94
96
|
|
|
95
|
-
private fromFrequency(frequency: number) {
|
|
96
|
-
this.frequency = frequency;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
97
|
private fromString(string: string) {
|
|
100
|
-
const matches =
|
|
98
|
+
const matches = /(\w#?)(\d)?/.exec(string) ?? [];
|
|
101
99
|
|
|
102
100
|
this.name = matches[1];
|
|
103
101
|
this.octave = matches[2] ? parseInt(matches[2]) : 1;
|
|
104
102
|
}
|
|
105
103
|
|
|
106
|
-
private
|
|
107
|
-
this.name = Notes[event.data[1] % 12];
|
|
108
|
-
this.octave = Math.floor(event.data[1] / 12) - 2;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
private fromProps(props: Partial<INote>) {
|
|
104
|
+
private fromProps(props: Omit<INote, "frequency">) {
|
|
112
105
|
Object.assign(this, props);
|
|
113
|
-
if (!props.note) throw Error("note props is mandatory");
|
|
114
|
-
|
|
115
|
-
this.fromString(props.note);
|
|
116
106
|
}
|
|
117
107
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Optional, uuidv4 } from "@blibliki/utils";
|
|
2
|
+
import { Engine } from "@/Engine";
|
|
3
|
+
|
|
4
|
+
type IPlug = {
|
|
5
|
+
moduleId: string;
|
|
6
|
+
ioName: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type IRoute = {
|
|
10
|
+
id: string;
|
|
11
|
+
source: IPlug;
|
|
12
|
+
destination: IPlug;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export class Routes {
|
|
16
|
+
engine: Engine;
|
|
17
|
+
routes: Map<string, IRoute>;
|
|
18
|
+
|
|
19
|
+
constructor(engine: Engine) {
|
|
20
|
+
this.engine = engine;
|
|
21
|
+
this.routes = new Map();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
addRoute(props: Optional<IRoute, "id">): IRoute {
|
|
25
|
+
const id = props.id ?? uuidv4();
|
|
26
|
+
const route = { ...props, id };
|
|
27
|
+
this.routes.set(id, route);
|
|
28
|
+
|
|
29
|
+
this.plug(id);
|
|
30
|
+
|
|
31
|
+
return route;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
removeRoute(id: string) {
|
|
35
|
+
this.unPlug(id);
|
|
36
|
+
this.routes.delete(id);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
clear() {
|
|
40
|
+
for (const id in this.routes) {
|
|
41
|
+
this.removeRoute(id);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private plug(id: string) {
|
|
46
|
+
const { sourceIO, destinationIO } = this.getIOs(id);
|
|
47
|
+
sourceIO.plug(destinationIO);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private unPlug(id: string) {
|
|
51
|
+
const { sourceIO, destinationIO } = this.getIOs(id);
|
|
52
|
+
sourceIO.unPlug(destinationIO);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private find(id: string): IRoute {
|
|
56
|
+
const route = this.routes.get(id);
|
|
57
|
+
if (!route) throw Error(`Route with id ${id} not found`);
|
|
58
|
+
|
|
59
|
+
return route;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private getIOs(id: string) {
|
|
63
|
+
const route = this.find(id);
|
|
64
|
+
const { source, destination } = route;
|
|
65
|
+
|
|
66
|
+
const sourceIO = this.engine.findIO(
|
|
67
|
+
source.moduleId,
|
|
68
|
+
source.ioName,
|
|
69
|
+
"output",
|
|
70
|
+
);
|
|
71
|
+
const destinationIO = this.engine.findIO(
|
|
72
|
+
destination.moduleId,
|
|
73
|
+
destination.ioName,
|
|
74
|
+
"input",
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
return { sourceIO, destinationIO };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Scheduler as InternalScheduler } from "@ircam/sc-scheduling";
|
|
2
|
+
import { now } from ".";
|
|
3
|
+
import { nt, t, TTime } from "./Time";
|
|
4
|
+
import Transport from "./Transport";
|
|
5
|
+
|
|
6
|
+
export default class Scheduler {
|
|
7
|
+
transport: Transport;
|
|
8
|
+
internalScheduler: InternalScheduler;
|
|
9
|
+
|
|
10
|
+
constructor(transport: Transport) {
|
|
11
|
+
this.transport = transport;
|
|
12
|
+
this.internalScheduler = new InternalScheduler(now, {
|
|
13
|
+
currentTimeToProcessorTimeFunction: () => this.transport.playhead,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
start(actionAt: TTime, callback: () => void) {
|
|
18
|
+
this.internalScheduler.add(this.processor, nt(actionAt));
|
|
19
|
+
this.defer(callback, actionAt);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
stop(actionAt: TTime, callback: () => void) {
|
|
23
|
+
this.defer(() => {
|
|
24
|
+
this.internalScheduler.remove(this.processor);
|
|
25
|
+
callback();
|
|
26
|
+
}, actionAt);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
defer(callback: () => void, actionAt: TTime) {
|
|
30
|
+
this.internalScheduler.defer(callback, nt(actionAt));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private processor = (currentTime: number, playhead: TTime) => {
|
|
34
|
+
console.log(`playhead: ${t(playhead).toNotation()}`);
|
|
35
|
+
return currentTime + 0.5;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { isNumber } from "@blibliki/utils";
|
|
2
|
+
import { Engine } from "@/Engine";
|
|
3
|
+
import { now } from ".";
|
|
4
|
+
|
|
5
|
+
export type BarsBeatsSixteenths = `${number}:${number}:${number}`;
|
|
6
|
+
export type TTime = number | BarsBeatsSixteenths | Time;
|
|
7
|
+
|
|
8
|
+
export const t = (value?: TTime): Time => {
|
|
9
|
+
value ??= now();
|
|
10
|
+
|
|
11
|
+
if (value instanceof Time) return value;
|
|
12
|
+
|
|
13
|
+
return new Time(value);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const nt = (value?: TTime): number => {
|
|
17
|
+
value ??= now();
|
|
18
|
+
|
|
19
|
+
if (typeof value === "number") return value;
|
|
20
|
+
|
|
21
|
+
return t(value).toNumber();
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default class Time {
|
|
25
|
+
private value: number | BarsBeatsSixteenths;
|
|
26
|
+
private _notation?: BarsBeatsSixteenths;
|
|
27
|
+
private _number?: number;
|
|
28
|
+
|
|
29
|
+
constructor(value: TTime) {
|
|
30
|
+
this.value = value instanceof Time ? value.value : value;
|
|
31
|
+
|
|
32
|
+
if (isNumber(this.value)) {
|
|
33
|
+
this._number = this.value;
|
|
34
|
+
} else {
|
|
35
|
+
this._notation = this.value;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
add(value: TTime): Time {
|
|
40
|
+
return t(this.toNumber() + t(value).toNumber());
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
subtrack(value: TTime): Time {
|
|
44
|
+
return t(this.toNumber() - nt(value));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
isBefore(value: TTime): boolean {
|
|
48
|
+
return this.toNumber() < nt(value);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
isAfter(value: TTime): boolean {
|
|
52
|
+
return this.toNumber() > nt(value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
isEqual(value: TTime): boolean {
|
|
56
|
+
return this.toNumber() > nt(value);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
toNotation(): BarsBeatsSixteenths {
|
|
60
|
+
if (this._notation) return this._notation;
|
|
61
|
+
|
|
62
|
+
const [count, factor] = this.transport.timeSignature;
|
|
63
|
+
const divisionsPerBeat = 16 / factor;
|
|
64
|
+
const divisionsPerBar = count * divisionsPerBeat;
|
|
65
|
+
const secondsPerBeat = 60 / this.transport.bpm;
|
|
66
|
+
|
|
67
|
+
const totalDivisions = Math.floor(
|
|
68
|
+
((this.value as number) / secondsPerBeat) * divisionsPerBeat,
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const bars = Math.floor(totalDivisions / divisionsPerBar);
|
|
72
|
+
const beats = Math.floor(
|
|
73
|
+
(totalDivisions % divisionsPerBar) / divisionsPerBeat,
|
|
74
|
+
);
|
|
75
|
+
const divisions = totalDivisions % divisionsPerBeat;
|
|
76
|
+
|
|
77
|
+
this._notation = `${bars}:${beats}:${divisions}`;
|
|
78
|
+
|
|
79
|
+
return this._notation;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
toNumber(): number {
|
|
83
|
+
if (isNumber(this._number)) return this._number;
|
|
84
|
+
|
|
85
|
+
const [beatsPerBar, sixteenths] = this.transport.timeSignature;
|
|
86
|
+
const secondsPerBeat = 60 / this.transport.bpm;
|
|
87
|
+
|
|
88
|
+
const [bars, beats, divisions] = (this.value as BarsBeatsSixteenths)
|
|
89
|
+
.split(":")
|
|
90
|
+
.map(Number);
|
|
91
|
+
|
|
92
|
+
const totalBeats =
|
|
93
|
+
bars * beatsPerBar + beats + divisions / (sixteenths / 4);
|
|
94
|
+
|
|
95
|
+
this._number = totalBeats * secondsPerBeat;
|
|
96
|
+
|
|
97
|
+
return this._number;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private get transport() {
|
|
101
|
+
return Engine.current.transport;
|
|
102
|
+
}
|
|
103
|
+
}
|