@marmooo/midy 0.0.4 → 0.0.5
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/esm/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.1 → soundfont-parser@0.0.2}/+esm.d.ts +13 -6
- package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.d.ts.map +1 -0
- package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.1 → soundfont-parser@0.0.2}/+esm.js +5 -5
- package/esm/midy-GM1.d.ts +24 -34
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +167 -106
- package/esm/midy-GM2.d.ts +123 -21
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +170 -116
- package/esm/midy-GMLite.d.ts +23 -35
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +156 -107
- package/esm/midy.d.ts +25 -23
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +191 -120
- package/package.json +1 -1
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.1 → soundfont-parser@0.0.2}/+esm.d.ts +13 -6
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.d.ts.map +1 -0
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.1 → soundfont-parser@0.0.2}/+esm.js +5 -5
- package/script/midy-GM1.d.ts +24 -34
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +167 -106
- package/script/midy-GM2.d.ts +123 -21
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +170 -116
- package/script/midy-GMLite.d.ts +23 -35
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +156 -107
- package/script/midy.d.ts +25 -23
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +191 -120
- package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.1/+esm.d.ts.map +0 -1
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.1/+esm.d.ts.map +0 -1
package/esm/midy-GMLite.d.ts
CHANGED
|
@@ -2,9 +2,6 @@ export class MidyGMLite {
|
|
|
2
2
|
static channelSettings: {
|
|
3
3
|
volume: number;
|
|
4
4
|
pan: number;
|
|
5
|
-
vibratoRate: number;
|
|
6
|
-
vibratoDepth: number;
|
|
7
|
-
vibratoDelay: number;
|
|
8
5
|
bank: number;
|
|
9
6
|
dataMSB: number;
|
|
10
7
|
dataLSB: number;
|
|
@@ -42,12 +39,8 @@ export class MidyGMLite {
|
|
|
42
39
|
masterGain: any;
|
|
43
40
|
channels: {
|
|
44
41
|
scheduledNotes: Map<any, any>;
|
|
45
|
-
sostenutoNotes: Map<any, any>;
|
|
46
42
|
gainNode: any;
|
|
47
43
|
pannerNode: any;
|
|
48
|
-
modulationEffect: {
|
|
49
|
-
lfo: any;
|
|
50
|
-
};
|
|
51
44
|
expression: number;
|
|
52
45
|
modulation: number;
|
|
53
46
|
sustainPedal: boolean;
|
|
@@ -56,9 +49,6 @@ export class MidyGMLite {
|
|
|
56
49
|
pitchBendRange: number;
|
|
57
50
|
volume: number;
|
|
58
51
|
pan: number;
|
|
59
|
-
vibratoRate: number;
|
|
60
|
-
vibratoDepth: number;
|
|
61
|
-
vibratoDelay: number;
|
|
62
52
|
bank: number;
|
|
63
53
|
dataMSB: number;
|
|
64
54
|
dataLSB: number;
|
|
@@ -73,18 +63,11 @@ export class MidyGMLite {
|
|
|
73
63
|
setChannelAudioNodes(audioContext: any): {
|
|
74
64
|
gainNode: any;
|
|
75
65
|
pannerNode: any;
|
|
76
|
-
modulationEffect: {
|
|
77
|
-
lfo: any;
|
|
78
|
-
};
|
|
79
66
|
};
|
|
80
67
|
createChannels(audioContext: any): {
|
|
81
68
|
scheduledNotes: Map<any, any>;
|
|
82
|
-
sostenutoNotes: Map<any, any>;
|
|
83
69
|
gainNode: any;
|
|
84
70
|
pannerNode: any;
|
|
85
|
-
modulationEffect: {
|
|
86
|
-
lfo: any;
|
|
87
|
-
};
|
|
88
71
|
expression: number;
|
|
89
72
|
modulation: number;
|
|
90
73
|
sustainPedal: boolean;
|
|
@@ -93,9 +76,6 @@ export class MidyGMLite {
|
|
|
93
76
|
pitchBendRange: number;
|
|
94
77
|
volume: number;
|
|
95
78
|
pan: number;
|
|
96
|
-
vibratoRate: number;
|
|
97
|
-
vibratoDepth: number;
|
|
98
|
-
vibratoDelay: number;
|
|
99
79
|
bank: number;
|
|
100
80
|
dataMSB: number;
|
|
101
81
|
dataLSB: number;
|
|
@@ -103,8 +83,8 @@ export class MidyGMLite {
|
|
|
103
83
|
pitchBend: number;
|
|
104
84
|
modulationDepthRange: number;
|
|
105
85
|
}[];
|
|
106
|
-
createNoteBuffer(
|
|
107
|
-
createNoteBufferNode(
|
|
86
|
+
createNoteBuffer(instrumentKey: any, isSF3: any): Promise<any>;
|
|
87
|
+
createNoteBufferNode(instrumentKey: any, isSF3: any): Promise<any>;
|
|
108
88
|
convertToFloat32Array(uint8Array: any): Float32Array;
|
|
109
89
|
scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
|
|
110
90
|
getQueueIndex(second: any): number;
|
|
@@ -123,22 +103,17 @@ export class MidyGMLite {
|
|
|
123
103
|
seekTo(second: any): void;
|
|
124
104
|
calcTotalTime(): number;
|
|
125
105
|
currentTime(): number;
|
|
126
|
-
getActiveNotes(channel: any): Map<any, any>;
|
|
127
|
-
|
|
128
|
-
createModulationEffect(audioContext: any): {
|
|
129
|
-
lfo: any;
|
|
130
|
-
};
|
|
106
|
+
getActiveNotes(channel: any, time: any): Map<any, any>;
|
|
107
|
+
getActiveNote(noteList: any, time: any): any;
|
|
131
108
|
connectNoteEffects(channel: any, gainNode: any): void;
|
|
132
109
|
cbToRatio(cb: any): number;
|
|
133
110
|
centToHz(cent: any): number;
|
|
134
|
-
calcSemitoneOffset(channel: any):
|
|
135
|
-
calcPlaybackRate(
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
lfoGain: any;
|
|
141
|
-
}>;
|
|
111
|
+
calcSemitoneOffset(channel: any): number;
|
|
112
|
+
calcPlaybackRate(instrumentKey: any, noteNumber: any, semitoneOffset: any): number;
|
|
113
|
+
setVolumeEnvelope(channel: any, note: any): void;
|
|
114
|
+
setFilterEnvelope(channel: any, note: any): void;
|
|
115
|
+
startModulation(channel: any, note: any, time: any): void;
|
|
116
|
+
createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
|
|
142
117
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
143
118
|
noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
|
|
144
119
|
scheduleNoteRelease(channelNumber: any, noteNumber: any, velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
|
|
@@ -170,4 +145,17 @@ export class MidyGMLite {
|
|
|
170
145
|
handleSysEx(data: any): void;
|
|
171
146
|
scheduleTask(callback: any, startTime: any): Promise<any>;
|
|
172
147
|
}
|
|
148
|
+
declare class Note {
|
|
149
|
+
constructor(noteNumber: any, velocity: any, startTime: any, instrumentKey: any);
|
|
150
|
+
bufferSource: any;
|
|
151
|
+
gainNode: any;
|
|
152
|
+
filterNode: any;
|
|
153
|
+
modLFO: any;
|
|
154
|
+
modLFOGain: any;
|
|
155
|
+
noteNumber: any;
|
|
156
|
+
velocity: any;
|
|
157
|
+
startTime: any;
|
|
158
|
+
instrumentKey: any;
|
|
159
|
+
}
|
|
160
|
+
export {};
|
|
173
161
|
//# sourceMappingURL=midy-GMLite.d.ts.map
|
package/esm/midy-GMLite.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAqBA;IAmBE;;;;;;;;;MASE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IA5CD,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAuBhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;MAaC;IAED;;;;;;;;;;;;;;;;;;QAUC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EA+CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAyEC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED,yCAEC;IAED,mFAGC;IAED,iDAmBC;IAED,iDAiCC;IAED,0DAmBC;IAED,wHA6BC;IAED,kGA6BC;IAED,0EAGC;IAED,sIAmDC;IAED,0FAGC;IAED,kEAeC;IAED,wFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,0DAiBC;IAED,mFA+BC;IAED,yDAiBC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,sCAKC;IAED,sDAMC;IAED,gDAEC;IAED,gDAEC;IAED,+DAcC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,sCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AA59BD;IAOE,gFAKC;IAXD,kBAAa;IACb,cAAS;IACT,gBAAW;IACX,YAAO;IACP,gBAAW;IAGT,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
|
package/esm/midy-GMLite.js
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
import { parseMidi } from "./deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js";
|
|
2
|
-
import { parse, SoundFont, } from "./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.
|
|
2
|
+
import { parse, SoundFont, } from "./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.js";
|
|
3
|
+
class Note {
|
|
4
|
+
constructor(noteNumber, velocity, startTime, instrumentKey) {
|
|
5
|
+
Object.defineProperty(this, "bufferSource", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
writable: true,
|
|
9
|
+
value: void 0
|
|
10
|
+
});
|
|
11
|
+
Object.defineProperty(this, "gainNode", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
configurable: true,
|
|
14
|
+
writable: true,
|
|
15
|
+
value: void 0
|
|
16
|
+
});
|
|
17
|
+
Object.defineProperty(this, "filterNode", {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
configurable: true,
|
|
20
|
+
writable: true,
|
|
21
|
+
value: void 0
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(this, "modLFO", {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
writable: true,
|
|
27
|
+
value: void 0
|
|
28
|
+
});
|
|
29
|
+
Object.defineProperty(this, "modLFOGain", {
|
|
30
|
+
enumerable: true,
|
|
31
|
+
configurable: true,
|
|
32
|
+
writable: true,
|
|
33
|
+
value: void 0
|
|
34
|
+
});
|
|
35
|
+
this.noteNumber = noteNumber;
|
|
36
|
+
this.velocity = velocity;
|
|
37
|
+
this.startTime = startTime;
|
|
38
|
+
this.instrumentKey = instrumentKey;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
3
41
|
export class MidyGMLite {
|
|
4
42
|
constructor(audioContext) {
|
|
5
43
|
Object.defineProperty(this, "ticksPerBeat", {
|
|
@@ -151,14 +189,11 @@ export class MidyGMLite {
|
|
|
151
189
|
const pannerNode = new StereoPannerNode(audioContext, {
|
|
152
190
|
pan: MidyGMLite.channelSettings.pan,
|
|
153
191
|
});
|
|
154
|
-
const modulationEffect = this.createModulationEffect(audioContext);
|
|
155
|
-
modulationEffect.lfo.start();
|
|
156
192
|
pannerNode.connect(gainNode);
|
|
157
193
|
gainNode.connect(this.masterGain);
|
|
158
194
|
return {
|
|
159
195
|
gainNode,
|
|
160
196
|
pannerNode,
|
|
161
|
-
modulationEffect,
|
|
162
197
|
};
|
|
163
198
|
}
|
|
164
199
|
createChannels(audioContext) {
|
|
@@ -168,16 +203,15 @@ export class MidyGMLite {
|
|
|
168
203
|
...MidyGMLite.effectSettings,
|
|
169
204
|
...this.setChannelAudioNodes(audioContext),
|
|
170
205
|
scheduledNotes: new Map(),
|
|
171
|
-
sostenutoNotes: new Map(),
|
|
172
206
|
};
|
|
173
207
|
});
|
|
174
208
|
return channels;
|
|
175
209
|
}
|
|
176
|
-
async createNoteBuffer(
|
|
177
|
-
const sampleEnd =
|
|
210
|
+
async createNoteBuffer(instrumentKey, isSF3) {
|
|
211
|
+
const sampleEnd = instrumentKey.sample.length + instrumentKey.end;
|
|
178
212
|
if (isSF3) {
|
|
179
|
-
const sample = new Uint8Array(
|
|
180
|
-
sample.set(
|
|
213
|
+
const sample = new Uint8Array(instrumentKey.sample.length);
|
|
214
|
+
sample.set(instrumentKey.sample);
|
|
181
215
|
const audioBuffer = await this.audioContext.decodeAudioData(sample.buffer);
|
|
182
216
|
for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) {
|
|
183
217
|
const channelData = audioBuffer.getChannelData(channel);
|
|
@@ -186,26 +220,27 @@ export class MidyGMLite {
|
|
|
186
220
|
return audioBuffer;
|
|
187
221
|
}
|
|
188
222
|
else {
|
|
189
|
-
const sample =
|
|
223
|
+
const sample = instrumentKey.sample.subarray(0, sampleEnd);
|
|
190
224
|
const floatSample = this.convertToFloat32Array(sample);
|
|
191
225
|
const audioBuffer = new AudioBuffer({
|
|
192
226
|
numberOfChannels: 1,
|
|
193
227
|
length: sample.length,
|
|
194
|
-
sampleRate:
|
|
228
|
+
sampleRate: instrumentKey.sampleRate,
|
|
195
229
|
});
|
|
196
230
|
const channelData = audioBuffer.getChannelData(0);
|
|
197
231
|
channelData.set(floatSample);
|
|
198
232
|
return audioBuffer;
|
|
199
233
|
}
|
|
200
234
|
}
|
|
201
|
-
async createNoteBufferNode(
|
|
235
|
+
async createNoteBufferNode(instrumentKey, isSF3) {
|
|
202
236
|
const bufferSource = new AudioBufferSourceNode(this.audioContext);
|
|
203
|
-
const audioBuffer = await this.createNoteBuffer(
|
|
237
|
+
const audioBuffer = await this.createNoteBuffer(instrumentKey, isSF3);
|
|
204
238
|
bufferSource.buffer = audioBuffer;
|
|
205
|
-
bufferSource.loop =
|
|
239
|
+
bufferSource.loop = instrumentKey.sampleModes % 2 !== 0;
|
|
206
240
|
if (bufferSource.loop) {
|
|
207
|
-
bufferSource.loopStart =
|
|
208
|
-
|
|
241
|
+
bufferSource.loopStart = instrumentKey.loopStart /
|
|
242
|
+
instrumentKey.sampleRate;
|
|
243
|
+
bufferSource.loopEnd = instrumentKey.loopEnd / instrumentKey.sampleRate;
|
|
209
244
|
}
|
|
210
245
|
return bufferSource;
|
|
211
246
|
}
|
|
@@ -447,30 +482,26 @@ export class MidyGMLite {
|
|
|
447
482
|
const now = this.audioContext.currentTime;
|
|
448
483
|
return this.resumeTime + now - this.startTime - this.startDelay;
|
|
449
484
|
}
|
|
450
|
-
getActiveNotes(channel) {
|
|
485
|
+
getActiveNotes(channel, time) {
|
|
451
486
|
const activeNotes = new Map();
|
|
452
|
-
channel.scheduledNotes.forEach((
|
|
453
|
-
const activeNote = this.
|
|
487
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
488
|
+
const activeNote = this.getActiveNote(noteList, time);
|
|
454
489
|
if (activeNote) {
|
|
455
490
|
activeNotes.set(activeNote.noteNumber, activeNote);
|
|
456
491
|
}
|
|
457
492
|
});
|
|
458
493
|
return activeNotes;
|
|
459
494
|
}
|
|
460
|
-
|
|
461
|
-
for (let i =
|
|
462
|
-
const
|
|
463
|
-
if (
|
|
464
|
-
return
|
|
495
|
+
getActiveNote(noteList, time) {
|
|
496
|
+
for (let i = noteList.length - 1; i >= 0; i--) {
|
|
497
|
+
const note = noteList[i];
|
|
498
|
+
if (!note)
|
|
499
|
+
return;
|
|
500
|
+
if (time < note.startTime)
|
|
501
|
+
continue;
|
|
502
|
+
return (note.ending) ? null : note;
|
|
465
503
|
}
|
|
466
|
-
|
|
467
|
-
createModulationEffect(audioContext) {
|
|
468
|
-
const lfo = new OscillatorNode(audioContext, {
|
|
469
|
-
frequency: 5,
|
|
470
|
-
});
|
|
471
|
-
return {
|
|
472
|
-
lfo,
|
|
473
|
-
};
|
|
504
|
+
return noteList[0];
|
|
474
505
|
}
|
|
475
506
|
connectNoteEffects(channel, gainNode) {
|
|
476
507
|
gainNode.connect(channel.pannerNode);
|
|
@@ -482,73 +513,91 @@ export class MidyGMLite {
|
|
|
482
513
|
return 8.176 * Math.pow(2, cent / 1200);
|
|
483
514
|
}
|
|
484
515
|
calcSemitoneOffset(channel) {
|
|
485
|
-
return channel.pitchBend * channel.pitchBendRange
|
|
516
|
+
return channel.pitchBend * channel.pitchBendRange;
|
|
486
517
|
}
|
|
487
|
-
calcPlaybackRate(
|
|
488
|
-
return
|
|
518
|
+
calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset) {
|
|
519
|
+
return instrumentKey.playbackRate(noteNumber) *
|
|
520
|
+
Math.pow(2, semitoneOffset / 12);
|
|
489
521
|
}
|
|
490
|
-
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
bufferSource.playbackRate.value = this.calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
|
|
494
|
-
// volume envelope
|
|
495
|
-
const gainNode = new GainNode(this.audioContext, {
|
|
522
|
+
setVolumeEnvelope(channel, note) {
|
|
523
|
+
const { instrumentKey, startTime, velocity } = note;
|
|
524
|
+
note.gainNode = new GainNode(this.audioContext, {
|
|
496
525
|
gain: 0,
|
|
497
526
|
});
|
|
498
527
|
let volume = (velocity / 127) * channel.volume * channel.expression;
|
|
499
528
|
if (volume === 0)
|
|
500
529
|
volume = 1e-6; // exponentialRampToValueAtTime() requires a non-zero value
|
|
501
|
-
const attackVolume = this.cbToRatio(-
|
|
502
|
-
|
|
503
|
-
const
|
|
504
|
-
const
|
|
505
|
-
const
|
|
506
|
-
const
|
|
507
|
-
|
|
530
|
+
const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation) *
|
|
531
|
+
volume;
|
|
532
|
+
const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
|
|
533
|
+
const volDelay = startTime + instrumentKey.volDelay;
|
|
534
|
+
const volAttack = volDelay + instrumentKey.volAttack;
|
|
535
|
+
const volHold = volAttack + instrumentKey.volHold;
|
|
536
|
+
const volDecay = volHold + instrumentKey.volDecay;
|
|
537
|
+
note.gainNode.gain
|
|
508
538
|
.setValueAtTime(1e-6, volDelay) // exponentialRampToValueAtTime() requires a non-zero value
|
|
509
539
|
.exponentialRampToValueAtTime(attackVolume, volAttack)
|
|
510
540
|
.setValueAtTime(attackVolume, volHold)
|
|
511
541
|
.linearRampToValueAtTime(sustainVolume, volDecay);
|
|
512
|
-
|
|
542
|
+
}
|
|
543
|
+
setFilterEnvelope(channel, note) {
|
|
544
|
+
const { instrumentKey, startTime, noteNumber } = note;
|
|
545
|
+
const softPedalFactor = 1 -
|
|
546
|
+
(0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
|
|
513
547
|
const maxFreq = this.audioContext.sampleRate / 2;
|
|
514
|
-
const baseFreq = this.centToHz(
|
|
515
|
-
|
|
516
|
-
const
|
|
517
|
-
|
|
548
|
+
const baseFreq = this.centToHz(instrumentKey.initialFilterFc) *
|
|
549
|
+
softPedalFactor;
|
|
550
|
+
const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc) * softPedalFactor;
|
|
551
|
+
const sustainFreq = (baseFreq +
|
|
552
|
+
(peekFreq - baseFreq) * (1 - instrumentKey.modSustain)) * softPedalFactor;
|
|
553
|
+
const modDelay = startTime + instrumentKey.modDelay;
|
|
554
|
+
const modAttack = modDelay + instrumentKey.modAttack;
|
|
555
|
+
const modHold = modAttack + instrumentKey.modHold;
|
|
556
|
+
const modDecay = modHold + instrumentKey.modDecay;
|
|
518
557
|
const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
|
|
519
558
|
const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
|
|
520
559
|
const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
|
|
521
|
-
|
|
560
|
+
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
522
561
|
type: "lowpass",
|
|
523
|
-
Q:
|
|
562
|
+
Q: instrumentKey.initialFilterQ / 10, // dB
|
|
524
563
|
frequency: adjustedBaseFreq,
|
|
525
564
|
});
|
|
526
|
-
|
|
527
|
-
const modAttack = modDelay + noteInfo.modAttack;
|
|
528
|
-
const modHold = modAttack + noteInfo.modHold;
|
|
529
|
-
const modDecay = modHold + noteInfo.modDecay;
|
|
530
|
-
filterNode.frequency
|
|
565
|
+
note.filterNode.frequency
|
|
531
566
|
.setValueAtTime(adjustedBaseFreq, modDelay)
|
|
532
567
|
.exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
|
|
533
568
|
.setValueAtTime(adjustedPeekFreq, modHold)
|
|
534
569
|
.linearRampToValueAtTime(adjustedSustainFreq, modDecay);
|
|
535
|
-
|
|
570
|
+
note.bufferSource.detune.setValueAtTime(note.bufferSource.detune.value + instrumentKey.modEnvToPitch, modDelay);
|
|
571
|
+
}
|
|
572
|
+
startModulation(channel, note, time) {
|
|
573
|
+
const { instrumentKey } = note;
|
|
574
|
+
note.modLFOGain = new GainNode(this.audioContext, {
|
|
575
|
+
gain: this.cbToRatio(instrumentKey.modLfoToVolume) * channel.modulation,
|
|
576
|
+
});
|
|
577
|
+
note.modLFO = new OscillatorNode(this.audioContext, {
|
|
578
|
+
frequency: this.centToHz(instrumentKey.freqModLFO),
|
|
579
|
+
});
|
|
580
|
+
note.modLFO.start(time);
|
|
581
|
+
note.filterNode.frequency.setValueAtTime(note.filterNode.frequency.value + instrumentKey.modLfoToFilterFc, time);
|
|
582
|
+
note.bufferSource.detune.setValueAtTime(note.bufferSource.detune.value + instrumentKey.modLfoToPitch, time);
|
|
583
|
+
note.modLFO.connect(note.modLFOGain);
|
|
584
|
+
note.modLFOGain.connect(note.bufferSource.detune);
|
|
585
|
+
}
|
|
586
|
+
async createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3) {
|
|
587
|
+
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
588
|
+
const note = new Note(noteNumber, velocity, startTime, instrumentKey);
|
|
589
|
+
note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
|
|
590
|
+
note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
|
|
591
|
+
this.setVolumeEnvelope(channel, note);
|
|
592
|
+
this.setFilterEnvelope(channel, note);
|
|
536
593
|
if (channel.modulation > 0) {
|
|
537
|
-
const
|
|
538
|
-
|
|
539
|
-
lfoGain = new GainNode(this.audioContext, {
|
|
540
|
-
gain: 0,
|
|
541
|
-
});
|
|
542
|
-
lfoGain.gain
|
|
543
|
-
.setValueAtTime(1e-6, vibratoDelay) // exponentialRampToValueAtTime() requires a non-zero value
|
|
544
|
-
.exponentialRampToValueAtTime(channel.modulation, vibratoAttack);
|
|
545
|
-
channel.modulationEffect.lfo.connect(lfoGain);
|
|
546
|
-
lfoGain.connect(bufferSource.detune);
|
|
594
|
+
const delayModLFO = startTime + instrumentKey.delayModLFO;
|
|
595
|
+
this.startModulation(channel, note, delayModLFO);
|
|
547
596
|
}
|
|
548
|
-
bufferSource.connect(filterNode);
|
|
549
|
-
filterNode.connect(gainNode);
|
|
550
|
-
bufferSource.start(startTime,
|
|
551
|
-
return
|
|
597
|
+
note.bufferSource.connect(note.filterNode);
|
|
598
|
+
note.filterNode.connect(note.gainNode);
|
|
599
|
+
note.bufferSource.start(startTime, instrumentKey.start / instrumentKey.sampleRate);
|
|
600
|
+
return note;
|
|
552
601
|
}
|
|
553
602
|
async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
|
|
554
603
|
const channel = this.channels[channelNumber];
|
|
@@ -558,27 +607,17 @@ export class MidyGMLite {
|
|
|
558
607
|
return;
|
|
559
608
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
560
609
|
const isSF3 = soundFont.parsed.info.version.major === 3;
|
|
561
|
-
const
|
|
562
|
-
if (!
|
|
610
|
+
const instrumentKey = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber);
|
|
611
|
+
if (!instrumentKey)
|
|
563
612
|
return;
|
|
564
|
-
const
|
|
565
|
-
|
|
566
|
-
this.connectNoteEffects(channel, gainNode);
|
|
613
|
+
const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
|
|
614
|
+
this.connectNoteEffects(channel, note.gainNode);
|
|
567
615
|
const scheduledNotes = channel.scheduledNotes;
|
|
568
|
-
const scheduledNote = {
|
|
569
|
-
bufferSource,
|
|
570
|
-
filterNode,
|
|
571
|
-
gainNode,
|
|
572
|
-
lfoGain,
|
|
573
|
-
noteInfo,
|
|
574
|
-
noteNumber,
|
|
575
|
-
startTime,
|
|
576
|
-
};
|
|
577
616
|
if (scheduledNotes.has(noteNumber)) {
|
|
578
|
-
scheduledNotes.get(noteNumber).push(
|
|
617
|
+
scheduledNotes.get(noteNumber).push(note);
|
|
579
618
|
}
|
|
580
619
|
else {
|
|
581
|
-
scheduledNotes.set(noteNumber, [
|
|
620
|
+
scheduledNotes.set(noteNumber, [note]);
|
|
582
621
|
}
|
|
583
622
|
}
|
|
584
623
|
noteOn(channelNumber, noteNumber, velocity) {
|
|
@@ -598,15 +637,15 @@ export class MidyGMLite {
|
|
|
598
637
|
continue;
|
|
599
638
|
if (targetNote.ending)
|
|
600
639
|
continue;
|
|
601
|
-
const { bufferSource, filterNode, gainNode,
|
|
640
|
+
const { bufferSource, filterNode, gainNode, modLFO, modLFOGain, instrumentKey, } = targetNote;
|
|
602
641
|
const velocityRate = (velocity + 127) / 127;
|
|
603
|
-
const volEndTime = stopTime +
|
|
642
|
+
const volEndTime = stopTime + instrumentKey.volRelease * velocityRate;
|
|
604
643
|
gainNode.gain.cancelScheduledValues(stopTime);
|
|
605
644
|
gainNode.gain.linearRampToValueAtTime(0, volEndTime);
|
|
606
645
|
const maxFreq = this.audioContext.sampleRate / 2;
|
|
607
|
-
const baseFreq = this.centToHz(
|
|
646
|
+
const baseFreq = this.centToHz(instrumentKey.initialFilterFc);
|
|
608
647
|
const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
|
|
609
|
-
const modEndTime = stopTime +
|
|
648
|
+
const modEndTime = stopTime + instrumentKey.modRelease * velocityRate;
|
|
610
649
|
filterNode.frequency
|
|
611
650
|
.cancelScheduledValues(stopTime)
|
|
612
651
|
.linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
|
|
@@ -620,8 +659,10 @@ export class MidyGMLite {
|
|
|
620
659
|
bufferSource.disconnect(0);
|
|
621
660
|
filterNode.disconnect(0);
|
|
622
661
|
gainNode.disconnect(0);
|
|
623
|
-
if (
|
|
624
|
-
|
|
662
|
+
if (modLFOGain)
|
|
663
|
+
modLFOGain.disconnect(0);
|
|
664
|
+
if (modLFO)
|
|
665
|
+
modLFO.stop();
|
|
625
666
|
resolve();
|
|
626
667
|
};
|
|
627
668
|
bufferSource.stop(volEndTime);
|
|
@@ -679,10 +720,10 @@ export class MidyGMLite {
|
|
|
679
720
|
const channel = this.channels[channelNumber];
|
|
680
721
|
channel.pitchBend = (pitchBend - 8192) / 8192;
|
|
681
722
|
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
682
|
-
const activeNotes = this.getActiveNotes(channel);
|
|
723
|
+
const activeNotes = this.getActiveNotes(channel, now);
|
|
683
724
|
activeNotes.forEach((activeNote) => {
|
|
684
|
-
const { bufferSource,
|
|
685
|
-
const playbackRate = calcPlaybackRate(
|
|
725
|
+
const { bufferSource, instrumentKey, noteNumber } = activeNote;
|
|
726
|
+
const playbackRate = calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
|
|
686
727
|
bufferSource.playbackRate
|
|
687
728
|
.cancelScheduledValues(now)
|
|
688
729
|
.setValueAtTime(playbackRate * pressure, now);
|
|
@@ -719,9 +760,20 @@ export class MidyGMLite {
|
|
|
719
760
|
}
|
|
720
761
|
}
|
|
721
762
|
setModulation(channelNumber, modulation) {
|
|
763
|
+
const now = this.audioContext.currentTime;
|
|
722
764
|
const channel = this.channels[channelNumber];
|
|
723
765
|
channel.modulation = (modulation / 127) *
|
|
724
766
|
(channel.modulationDepthRange * 100);
|
|
767
|
+
const activeNotes = this.getActiveNotes(channel, now);
|
|
768
|
+
activeNotes.forEach((activeNote) => {
|
|
769
|
+
if (activeNote.modLFO) {
|
|
770
|
+
activeNote.gainNode.gain.setValueAtTime(this.cbToRatio(activeNote.instrumentKey.modLfoToVolume) *
|
|
771
|
+
channel.modulation, now);
|
|
772
|
+
}
|
|
773
|
+
else {
|
|
774
|
+
this.startModulation(channel, activeNote, now);
|
|
775
|
+
}
|
|
776
|
+
});
|
|
725
777
|
}
|
|
726
778
|
setVolume(channelNumber, volume) {
|
|
727
779
|
const channel = this.channels[channelNumber];
|
|
@@ -778,8 +830,8 @@ export class MidyGMLite {
|
|
|
778
830
|
const velocity = 0;
|
|
779
831
|
const stopPedal = true;
|
|
780
832
|
const promises = [];
|
|
781
|
-
channel.scheduledNotes.forEach((
|
|
782
|
-
const activeNote = this.
|
|
833
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
834
|
+
const activeNote = this.getActiveNote(noteList, now);
|
|
783
835
|
if (activeNote) {
|
|
784
836
|
const notePromise = this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, stopPedal);
|
|
785
837
|
promises.push(notePromise);
|
|
@@ -796,8 +848,8 @@ export class MidyGMLite {
|
|
|
796
848
|
const velocity = 0;
|
|
797
849
|
const stopPedal = false;
|
|
798
850
|
const promises = [];
|
|
799
|
-
channel.scheduledNotes.forEach((
|
|
800
|
-
const activeNote = this.
|
|
851
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
852
|
+
const activeNote = this.getActiveNote(noteList, now);
|
|
801
853
|
if (activeNote) {
|
|
802
854
|
const notePromise = this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, stopPedal);
|
|
803
855
|
promises.push(notePromise);
|
|
@@ -891,9 +943,6 @@ Object.defineProperty(MidyGMLite, "channelSettings", {
|
|
|
891
943
|
value: {
|
|
892
944
|
volume: 100 / 127,
|
|
893
945
|
pan: 0,
|
|
894
|
-
vibratoRate: 5,
|
|
895
|
-
vibratoDepth: 0.5,
|
|
896
|
-
vibratoDelay: 2.5,
|
|
897
946
|
bank: 0,
|
|
898
947
|
dataMSB: 0,
|
|
899
948
|
dataLSB: 0,
|
package/esm/midy.d.ts
CHANGED
|
@@ -86,9 +86,6 @@ export class Midy {
|
|
|
86
86
|
};
|
|
87
87
|
gainNode: any;
|
|
88
88
|
pannerNode: any;
|
|
89
|
-
modulationEffect: {
|
|
90
|
-
lfo: any;
|
|
91
|
-
};
|
|
92
89
|
reverbEffect: {
|
|
93
90
|
convolverNode: any;
|
|
94
91
|
dryGain: any;
|
|
@@ -136,9 +133,6 @@ export class Midy {
|
|
|
136
133
|
setChannelAudioNodes(audioContext: any): {
|
|
137
134
|
gainNode: any;
|
|
138
135
|
pannerNode: any;
|
|
139
|
-
modulationEffect: {
|
|
140
|
-
lfo: any;
|
|
141
|
-
};
|
|
142
136
|
reverbEffect: {
|
|
143
137
|
convolverNode: any;
|
|
144
138
|
dryGain: any;
|
|
@@ -172,9 +166,6 @@ export class Midy {
|
|
|
172
166
|
};
|
|
173
167
|
gainNode: any;
|
|
174
168
|
pannerNode: any;
|
|
175
|
-
modulationEffect: {
|
|
176
|
-
lfo: any;
|
|
177
|
-
};
|
|
178
169
|
reverbEffect: {
|
|
179
170
|
convolverNode: any;
|
|
180
171
|
dryGain: any;
|
|
@@ -215,8 +206,8 @@ export class Midy {
|
|
|
215
206
|
coarseTuning: number;
|
|
216
207
|
modulationDepthRange: number;
|
|
217
208
|
}[];
|
|
218
|
-
createNoteBuffer(
|
|
219
|
-
createNoteBufferNode(
|
|
209
|
+
createNoteBuffer(instrumentKey: any, isSF3: any): Promise<any>;
|
|
210
|
+
createNoteBufferNode(instrumentKey: any, isSF3: any): Promise<any>;
|
|
220
211
|
convertToFloat32Array(uint8Array: any): Float32Array;
|
|
221
212
|
scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
|
|
222
213
|
getQueueIndex(second: any): number;
|
|
@@ -235,11 +226,8 @@ export class Midy {
|
|
|
235
226
|
seekTo(second: any): void;
|
|
236
227
|
calcTotalTime(): number;
|
|
237
228
|
currentTime(): number;
|
|
238
|
-
getActiveNotes(channel: any): Map<any, any>;
|
|
239
|
-
|
|
240
|
-
createModulationEffect(audioContext: any): {
|
|
241
|
-
lfo: any;
|
|
242
|
-
};
|
|
229
|
+
getActiveNotes(channel: any, time: any): Map<any, any>;
|
|
230
|
+
getActiveNote(noteList: any, time: any): any;
|
|
243
231
|
createReverbEffect(audioContext: any, options?: {}): {
|
|
244
232
|
convolverNode: any;
|
|
245
233
|
dryGain: any;
|
|
@@ -255,13 +243,12 @@ export class Midy {
|
|
|
255
243
|
cbToRatio(cb: any): number;
|
|
256
244
|
centToHz(cent: any): number;
|
|
257
245
|
calcSemitoneOffset(channel: any): any;
|
|
258
|
-
calcPlaybackRate(
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}>;
|
|
246
|
+
calcPlaybackRate(instrumentKey: any, noteNumber: any, semitoneOffset: any): number;
|
|
247
|
+
setVolumeEnvelope(channel: any, note: any): void;
|
|
248
|
+
setFilterEnvelope(channel: any, note: any): void;
|
|
249
|
+
startModulation(channel: any, note: any, time: any): void;
|
|
250
|
+
startVibrato(channel: any, note: any, time: any): void;
|
|
251
|
+
createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
|
|
265
252
|
calcBank(channel: any, channelNumber: any): any;
|
|
266
253
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
267
254
|
noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
|
|
@@ -319,4 +306,19 @@ export class Midy {
|
|
|
319
306
|
handleSysEx(data: any): void;
|
|
320
307
|
scheduleTask(callback: any, startTime: any): Promise<any>;
|
|
321
308
|
}
|
|
309
|
+
declare class Note {
|
|
310
|
+
constructor(noteNumber: any, velocity: any, startTime: any, instrumentKey: any);
|
|
311
|
+
bufferSource: any;
|
|
312
|
+
gainNode: any;
|
|
313
|
+
filterNode: any;
|
|
314
|
+
modLFO: any;
|
|
315
|
+
modLFOGain: any;
|
|
316
|
+
vibLFO: any;
|
|
317
|
+
vibLFOGain: any;
|
|
318
|
+
noteNumber: any;
|
|
319
|
+
velocity: any;
|
|
320
|
+
startTime: any;
|
|
321
|
+
instrumentKey: any;
|
|
322
|
+
}
|
|
323
|
+
export {};
|
|
322
324
|
//# sourceMappingURL=midy.d.ts.map
|
package/esm/midy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAuBA;IAwBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAzED,qBAAmB;IACnB,kBAAc;IACd,qBAAmB;IACnB,yBAAqB;IACrB,2BAAuB;IACvB,cAAa;IACb,cAAa;IACb,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IA+ChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;MAoBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAiBC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EAyDC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA2GC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED;;;;MAoCC;IAED;;;;;MA2CC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED,sCAKC;IAED,mFAGC;IAED,iDAmBC;IAED,iDAiCC;IAED,0DAmBC;IAED,uDAcC;IAED,wHAqCC;IAED,gDAQC;IAED,kGAgCC;IAED,0EAGC;IAED,sIAwDC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,gEAqBC;IAED,sFAcC;IAED,4DAIC;IAED,+DAcC;IAED,qEAGC;IAED,0DAiBC;IAED,0EAkEC;IAED,+CAEC;IAED,yDAiBC;IAED,iEAEC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,+CAEC;IAED,sCAKC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAWC;IAED,uDAGC;IAED,2DAGC;IAED,6DAGC;IAED,6DASC;IAED,4CAkBC;IAED,4CAkBC;IAED,gDAEC;IAED,gDAEC;IAGD,+DAuBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAgDC;IAED,yCAGC;IAED,sCAQC;IAED,6CAGC;IAED,8CAMC;IAED,+CAGC;IAED,kDAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAx/CD;IASE,gFAKC;IAbD,kBAAa;IACb,cAAS;IACT,gBAAW;IACX,YAAO;IACP,gBAAW;IACX,YAAO;IACP,gBAAW;IAGT,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
|