@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/script/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
|
|
@@ -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/script/midy-GMLite.js
CHANGED
|
@@ -2,7 +2,45 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MidyGMLite = void 0;
|
|
4
4
|
const _esm_js_1 = require("./deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js");
|
|
5
|
-
const _esm_js_2 = require("./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.
|
|
5
|
+
const _esm_js_2 = require("./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.js");
|
|
6
|
+
class Note {
|
|
7
|
+
constructor(noteNumber, velocity, startTime, instrumentKey) {
|
|
8
|
+
Object.defineProperty(this, "bufferSource", {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
configurable: true,
|
|
11
|
+
writable: true,
|
|
12
|
+
value: void 0
|
|
13
|
+
});
|
|
14
|
+
Object.defineProperty(this, "gainNode", {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
configurable: true,
|
|
17
|
+
writable: true,
|
|
18
|
+
value: void 0
|
|
19
|
+
});
|
|
20
|
+
Object.defineProperty(this, "filterNode", {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
writable: true,
|
|
24
|
+
value: void 0
|
|
25
|
+
});
|
|
26
|
+
Object.defineProperty(this, "modLFO", {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
configurable: true,
|
|
29
|
+
writable: true,
|
|
30
|
+
value: void 0
|
|
31
|
+
});
|
|
32
|
+
Object.defineProperty(this, "modLFOGain", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
writable: true,
|
|
36
|
+
value: void 0
|
|
37
|
+
});
|
|
38
|
+
this.noteNumber = noteNumber;
|
|
39
|
+
this.velocity = velocity;
|
|
40
|
+
this.startTime = startTime;
|
|
41
|
+
this.instrumentKey = instrumentKey;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
6
44
|
class MidyGMLite {
|
|
7
45
|
constructor(audioContext) {
|
|
8
46
|
Object.defineProperty(this, "ticksPerBeat", {
|
|
@@ -154,14 +192,11 @@ class MidyGMLite {
|
|
|
154
192
|
const pannerNode = new StereoPannerNode(audioContext, {
|
|
155
193
|
pan: MidyGMLite.channelSettings.pan,
|
|
156
194
|
});
|
|
157
|
-
const modulationEffect = this.createModulationEffect(audioContext);
|
|
158
|
-
modulationEffect.lfo.start();
|
|
159
195
|
pannerNode.connect(gainNode);
|
|
160
196
|
gainNode.connect(this.masterGain);
|
|
161
197
|
return {
|
|
162
198
|
gainNode,
|
|
163
199
|
pannerNode,
|
|
164
|
-
modulationEffect,
|
|
165
200
|
};
|
|
166
201
|
}
|
|
167
202
|
createChannels(audioContext) {
|
|
@@ -171,16 +206,15 @@ class MidyGMLite {
|
|
|
171
206
|
...MidyGMLite.effectSettings,
|
|
172
207
|
...this.setChannelAudioNodes(audioContext),
|
|
173
208
|
scheduledNotes: new Map(),
|
|
174
|
-
sostenutoNotes: new Map(),
|
|
175
209
|
};
|
|
176
210
|
});
|
|
177
211
|
return channels;
|
|
178
212
|
}
|
|
179
|
-
async createNoteBuffer(
|
|
180
|
-
const sampleEnd =
|
|
213
|
+
async createNoteBuffer(instrumentKey, isSF3) {
|
|
214
|
+
const sampleEnd = instrumentKey.sample.length + instrumentKey.end;
|
|
181
215
|
if (isSF3) {
|
|
182
|
-
const sample = new Uint8Array(
|
|
183
|
-
sample.set(
|
|
216
|
+
const sample = new Uint8Array(instrumentKey.sample.length);
|
|
217
|
+
sample.set(instrumentKey.sample);
|
|
184
218
|
const audioBuffer = await this.audioContext.decodeAudioData(sample.buffer);
|
|
185
219
|
for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) {
|
|
186
220
|
const channelData = audioBuffer.getChannelData(channel);
|
|
@@ -189,26 +223,27 @@ class MidyGMLite {
|
|
|
189
223
|
return audioBuffer;
|
|
190
224
|
}
|
|
191
225
|
else {
|
|
192
|
-
const sample =
|
|
226
|
+
const sample = instrumentKey.sample.subarray(0, sampleEnd);
|
|
193
227
|
const floatSample = this.convertToFloat32Array(sample);
|
|
194
228
|
const audioBuffer = new AudioBuffer({
|
|
195
229
|
numberOfChannels: 1,
|
|
196
230
|
length: sample.length,
|
|
197
|
-
sampleRate:
|
|
231
|
+
sampleRate: instrumentKey.sampleRate,
|
|
198
232
|
});
|
|
199
233
|
const channelData = audioBuffer.getChannelData(0);
|
|
200
234
|
channelData.set(floatSample);
|
|
201
235
|
return audioBuffer;
|
|
202
236
|
}
|
|
203
237
|
}
|
|
204
|
-
async createNoteBufferNode(
|
|
238
|
+
async createNoteBufferNode(instrumentKey, isSF3) {
|
|
205
239
|
const bufferSource = new AudioBufferSourceNode(this.audioContext);
|
|
206
|
-
const audioBuffer = await this.createNoteBuffer(
|
|
240
|
+
const audioBuffer = await this.createNoteBuffer(instrumentKey, isSF3);
|
|
207
241
|
bufferSource.buffer = audioBuffer;
|
|
208
|
-
bufferSource.loop =
|
|
242
|
+
bufferSource.loop = instrumentKey.sampleModes % 2 !== 0;
|
|
209
243
|
if (bufferSource.loop) {
|
|
210
|
-
bufferSource.loopStart =
|
|
211
|
-
|
|
244
|
+
bufferSource.loopStart = instrumentKey.loopStart /
|
|
245
|
+
instrumentKey.sampleRate;
|
|
246
|
+
bufferSource.loopEnd = instrumentKey.loopEnd / instrumentKey.sampleRate;
|
|
212
247
|
}
|
|
213
248
|
return bufferSource;
|
|
214
249
|
}
|
|
@@ -450,30 +485,26 @@ class MidyGMLite {
|
|
|
450
485
|
const now = this.audioContext.currentTime;
|
|
451
486
|
return this.resumeTime + now - this.startTime - this.startDelay;
|
|
452
487
|
}
|
|
453
|
-
getActiveNotes(channel) {
|
|
488
|
+
getActiveNotes(channel, time) {
|
|
454
489
|
const activeNotes = new Map();
|
|
455
|
-
channel.scheduledNotes.forEach((
|
|
456
|
-
const activeNote = this.
|
|
490
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
491
|
+
const activeNote = this.getActiveNote(noteList, time);
|
|
457
492
|
if (activeNote) {
|
|
458
493
|
activeNotes.set(activeNote.noteNumber, activeNote);
|
|
459
494
|
}
|
|
460
495
|
});
|
|
461
496
|
return activeNotes;
|
|
462
497
|
}
|
|
463
|
-
|
|
464
|
-
for (let i =
|
|
465
|
-
const
|
|
466
|
-
if (
|
|
467
|
-
return
|
|
498
|
+
getActiveNote(noteList, time) {
|
|
499
|
+
for (let i = noteList.length - 1; i >= 0; i--) {
|
|
500
|
+
const note = noteList[i];
|
|
501
|
+
if (!note)
|
|
502
|
+
return;
|
|
503
|
+
if (time < note.startTime)
|
|
504
|
+
continue;
|
|
505
|
+
return (note.ending) ? null : note;
|
|
468
506
|
}
|
|
469
|
-
|
|
470
|
-
createModulationEffect(audioContext) {
|
|
471
|
-
const lfo = new OscillatorNode(audioContext, {
|
|
472
|
-
frequency: 5,
|
|
473
|
-
});
|
|
474
|
-
return {
|
|
475
|
-
lfo,
|
|
476
|
-
};
|
|
507
|
+
return noteList[0];
|
|
477
508
|
}
|
|
478
509
|
connectNoteEffects(channel, gainNode) {
|
|
479
510
|
gainNode.connect(channel.pannerNode);
|
|
@@ -485,73 +516,91 @@ class MidyGMLite {
|
|
|
485
516
|
return 8.176 * Math.pow(2, cent / 1200);
|
|
486
517
|
}
|
|
487
518
|
calcSemitoneOffset(channel) {
|
|
488
|
-
return channel.pitchBend * channel.pitchBendRange
|
|
519
|
+
return channel.pitchBend * channel.pitchBendRange;
|
|
489
520
|
}
|
|
490
|
-
calcPlaybackRate(
|
|
491
|
-
return
|
|
521
|
+
calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset) {
|
|
522
|
+
return instrumentKey.playbackRate(noteNumber) *
|
|
523
|
+
Math.pow(2, semitoneOffset / 12);
|
|
492
524
|
}
|
|
493
|
-
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
bufferSource.playbackRate.value = this.calcPlaybackRate(noteInfo, noteNumber, semitoneOffset);
|
|
497
|
-
// volume envelope
|
|
498
|
-
const gainNode = new GainNode(this.audioContext, {
|
|
525
|
+
setVolumeEnvelope(channel, note) {
|
|
526
|
+
const { instrumentKey, startTime, velocity } = note;
|
|
527
|
+
note.gainNode = new GainNode(this.audioContext, {
|
|
499
528
|
gain: 0,
|
|
500
529
|
});
|
|
501
530
|
let volume = (velocity / 127) * channel.volume * channel.expression;
|
|
502
531
|
if (volume === 0)
|
|
503
532
|
volume = 1e-6; // exponentialRampToValueAtTime() requires a non-zero value
|
|
504
|
-
const attackVolume = this.cbToRatio(-
|
|
505
|
-
|
|
506
|
-
const
|
|
507
|
-
const
|
|
508
|
-
const
|
|
509
|
-
const
|
|
510
|
-
|
|
533
|
+
const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation) *
|
|
534
|
+
volume;
|
|
535
|
+
const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
|
|
536
|
+
const volDelay = startTime + instrumentKey.volDelay;
|
|
537
|
+
const volAttack = volDelay + instrumentKey.volAttack;
|
|
538
|
+
const volHold = volAttack + instrumentKey.volHold;
|
|
539
|
+
const volDecay = volHold + instrumentKey.volDecay;
|
|
540
|
+
note.gainNode.gain
|
|
511
541
|
.setValueAtTime(1e-6, volDelay) // exponentialRampToValueAtTime() requires a non-zero value
|
|
512
542
|
.exponentialRampToValueAtTime(attackVolume, volAttack)
|
|
513
543
|
.setValueAtTime(attackVolume, volHold)
|
|
514
544
|
.linearRampToValueAtTime(sustainVolume, volDecay);
|
|
515
|
-
|
|
545
|
+
}
|
|
546
|
+
setFilterEnvelope(channel, note) {
|
|
547
|
+
const { instrumentKey, startTime, noteNumber } = note;
|
|
548
|
+
const softPedalFactor = 1 -
|
|
549
|
+
(0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
|
|
516
550
|
const maxFreq = this.audioContext.sampleRate / 2;
|
|
517
|
-
const baseFreq = this.centToHz(
|
|
518
|
-
|
|
519
|
-
const
|
|
520
|
-
|
|
551
|
+
const baseFreq = this.centToHz(instrumentKey.initialFilterFc) *
|
|
552
|
+
softPedalFactor;
|
|
553
|
+
const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc) * softPedalFactor;
|
|
554
|
+
const sustainFreq = (baseFreq +
|
|
555
|
+
(peekFreq - baseFreq) * (1 - instrumentKey.modSustain)) * softPedalFactor;
|
|
556
|
+
const modDelay = startTime + instrumentKey.modDelay;
|
|
557
|
+
const modAttack = modDelay + instrumentKey.modAttack;
|
|
558
|
+
const modHold = modAttack + instrumentKey.modHold;
|
|
559
|
+
const modDecay = modHold + instrumentKey.modDecay;
|
|
521
560
|
const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
|
|
522
561
|
const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
|
|
523
562
|
const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
|
|
524
|
-
|
|
563
|
+
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
525
564
|
type: "lowpass",
|
|
526
|
-
Q:
|
|
565
|
+
Q: instrumentKey.initialFilterQ / 10, // dB
|
|
527
566
|
frequency: adjustedBaseFreq,
|
|
528
567
|
});
|
|
529
|
-
|
|
530
|
-
const modAttack = modDelay + noteInfo.modAttack;
|
|
531
|
-
const modHold = modAttack + noteInfo.modHold;
|
|
532
|
-
const modDecay = modHold + noteInfo.modDecay;
|
|
533
|
-
filterNode.frequency
|
|
568
|
+
note.filterNode.frequency
|
|
534
569
|
.setValueAtTime(adjustedBaseFreq, modDelay)
|
|
535
570
|
.exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
|
|
536
571
|
.setValueAtTime(adjustedPeekFreq, modHold)
|
|
537
572
|
.linearRampToValueAtTime(adjustedSustainFreq, modDecay);
|
|
538
|
-
|
|
573
|
+
note.bufferSource.detune.setValueAtTime(note.bufferSource.detune.value + instrumentKey.modEnvToPitch, modDelay);
|
|
574
|
+
}
|
|
575
|
+
startModulation(channel, note, time) {
|
|
576
|
+
const { instrumentKey } = note;
|
|
577
|
+
note.modLFOGain = new GainNode(this.audioContext, {
|
|
578
|
+
gain: this.cbToRatio(instrumentKey.modLfoToVolume) * channel.modulation,
|
|
579
|
+
});
|
|
580
|
+
note.modLFO = new OscillatorNode(this.audioContext, {
|
|
581
|
+
frequency: this.centToHz(instrumentKey.freqModLFO),
|
|
582
|
+
});
|
|
583
|
+
note.modLFO.start(time);
|
|
584
|
+
note.filterNode.frequency.setValueAtTime(note.filterNode.frequency.value + instrumentKey.modLfoToFilterFc, time);
|
|
585
|
+
note.bufferSource.detune.setValueAtTime(note.bufferSource.detune.value + instrumentKey.modLfoToPitch, time);
|
|
586
|
+
note.modLFO.connect(note.modLFOGain);
|
|
587
|
+
note.modLFOGain.connect(note.bufferSource.detune);
|
|
588
|
+
}
|
|
589
|
+
async createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3) {
|
|
590
|
+
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
591
|
+
const note = new Note(noteNumber, velocity, startTime, instrumentKey);
|
|
592
|
+
note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
|
|
593
|
+
note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
|
|
594
|
+
this.setVolumeEnvelope(channel, note);
|
|
595
|
+
this.setFilterEnvelope(channel, note);
|
|
539
596
|
if (channel.modulation > 0) {
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
lfoGain = new GainNode(this.audioContext, {
|
|
543
|
-
gain: 0,
|
|
544
|
-
});
|
|
545
|
-
lfoGain.gain
|
|
546
|
-
.setValueAtTime(1e-6, vibratoDelay) // exponentialRampToValueAtTime() requires a non-zero value
|
|
547
|
-
.exponentialRampToValueAtTime(channel.modulation, vibratoAttack);
|
|
548
|
-
channel.modulationEffect.lfo.connect(lfoGain);
|
|
549
|
-
lfoGain.connect(bufferSource.detune);
|
|
597
|
+
const delayModLFO = startTime + instrumentKey.delayModLFO;
|
|
598
|
+
this.startModulation(channel, note, delayModLFO);
|
|
550
599
|
}
|
|
551
|
-
bufferSource.connect(filterNode);
|
|
552
|
-
filterNode.connect(gainNode);
|
|
553
|
-
bufferSource.start(startTime,
|
|
554
|
-
return
|
|
600
|
+
note.bufferSource.connect(note.filterNode);
|
|
601
|
+
note.filterNode.connect(note.gainNode);
|
|
602
|
+
note.bufferSource.start(startTime, instrumentKey.start / instrumentKey.sampleRate);
|
|
603
|
+
return note;
|
|
555
604
|
}
|
|
556
605
|
async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
|
|
557
606
|
const channel = this.channels[channelNumber];
|
|
@@ -561,27 +610,17 @@ class MidyGMLite {
|
|
|
561
610
|
return;
|
|
562
611
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
563
612
|
const isSF3 = soundFont.parsed.info.version.major === 3;
|
|
564
|
-
const
|
|
565
|
-
if (!
|
|
613
|
+
const instrumentKey = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber);
|
|
614
|
+
if (!instrumentKey)
|
|
566
615
|
return;
|
|
567
|
-
const
|
|
568
|
-
|
|
569
|
-
this.connectNoteEffects(channel, gainNode);
|
|
616
|
+
const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
|
|
617
|
+
this.connectNoteEffects(channel, note.gainNode);
|
|
570
618
|
const scheduledNotes = channel.scheduledNotes;
|
|
571
|
-
const scheduledNote = {
|
|
572
|
-
bufferSource,
|
|
573
|
-
filterNode,
|
|
574
|
-
gainNode,
|
|
575
|
-
lfoGain,
|
|
576
|
-
noteInfo,
|
|
577
|
-
noteNumber,
|
|
578
|
-
startTime,
|
|
579
|
-
};
|
|
580
619
|
if (scheduledNotes.has(noteNumber)) {
|
|
581
|
-
scheduledNotes.get(noteNumber).push(
|
|
620
|
+
scheduledNotes.get(noteNumber).push(note);
|
|
582
621
|
}
|
|
583
622
|
else {
|
|
584
|
-
scheduledNotes.set(noteNumber, [
|
|
623
|
+
scheduledNotes.set(noteNumber, [note]);
|
|
585
624
|
}
|
|
586
625
|
}
|
|
587
626
|
noteOn(channelNumber, noteNumber, velocity) {
|
|
@@ -601,15 +640,15 @@ class MidyGMLite {
|
|
|
601
640
|
continue;
|
|
602
641
|
if (targetNote.ending)
|
|
603
642
|
continue;
|
|
604
|
-
const { bufferSource, filterNode, gainNode,
|
|
643
|
+
const { bufferSource, filterNode, gainNode, modLFO, modLFOGain, instrumentKey, } = targetNote;
|
|
605
644
|
const velocityRate = (velocity + 127) / 127;
|
|
606
|
-
const volEndTime = stopTime +
|
|
645
|
+
const volEndTime = stopTime + instrumentKey.volRelease * velocityRate;
|
|
607
646
|
gainNode.gain.cancelScheduledValues(stopTime);
|
|
608
647
|
gainNode.gain.linearRampToValueAtTime(0, volEndTime);
|
|
609
648
|
const maxFreq = this.audioContext.sampleRate / 2;
|
|
610
|
-
const baseFreq = this.centToHz(
|
|
649
|
+
const baseFreq = this.centToHz(instrumentKey.initialFilterFc);
|
|
611
650
|
const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
|
|
612
|
-
const modEndTime = stopTime +
|
|
651
|
+
const modEndTime = stopTime + instrumentKey.modRelease * velocityRate;
|
|
613
652
|
filterNode.frequency
|
|
614
653
|
.cancelScheduledValues(stopTime)
|
|
615
654
|
.linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
|
|
@@ -623,8 +662,10 @@ class MidyGMLite {
|
|
|
623
662
|
bufferSource.disconnect(0);
|
|
624
663
|
filterNode.disconnect(0);
|
|
625
664
|
gainNode.disconnect(0);
|
|
626
|
-
if (
|
|
627
|
-
|
|
665
|
+
if (modLFOGain)
|
|
666
|
+
modLFOGain.disconnect(0);
|
|
667
|
+
if (modLFO)
|
|
668
|
+
modLFO.stop();
|
|
628
669
|
resolve();
|
|
629
670
|
};
|
|
630
671
|
bufferSource.stop(volEndTime);
|
|
@@ -682,10 +723,10 @@ class MidyGMLite {
|
|
|
682
723
|
const channel = this.channels[channelNumber];
|
|
683
724
|
channel.pitchBend = (pitchBend - 8192) / 8192;
|
|
684
725
|
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
685
|
-
const activeNotes = this.getActiveNotes(channel);
|
|
726
|
+
const activeNotes = this.getActiveNotes(channel, now);
|
|
686
727
|
activeNotes.forEach((activeNote) => {
|
|
687
|
-
const { bufferSource,
|
|
688
|
-
const playbackRate = calcPlaybackRate(
|
|
728
|
+
const { bufferSource, instrumentKey, noteNumber } = activeNote;
|
|
729
|
+
const playbackRate = calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
|
|
689
730
|
bufferSource.playbackRate
|
|
690
731
|
.cancelScheduledValues(now)
|
|
691
732
|
.setValueAtTime(playbackRate * pressure, now);
|
|
@@ -722,9 +763,20 @@ class MidyGMLite {
|
|
|
722
763
|
}
|
|
723
764
|
}
|
|
724
765
|
setModulation(channelNumber, modulation) {
|
|
766
|
+
const now = this.audioContext.currentTime;
|
|
725
767
|
const channel = this.channels[channelNumber];
|
|
726
768
|
channel.modulation = (modulation / 127) *
|
|
727
769
|
(channel.modulationDepthRange * 100);
|
|
770
|
+
const activeNotes = this.getActiveNotes(channel, now);
|
|
771
|
+
activeNotes.forEach((activeNote) => {
|
|
772
|
+
if (activeNote.modLFO) {
|
|
773
|
+
activeNote.gainNode.gain.setValueAtTime(this.cbToRatio(activeNote.instrumentKey.modLfoToVolume) *
|
|
774
|
+
channel.modulation, now);
|
|
775
|
+
}
|
|
776
|
+
else {
|
|
777
|
+
this.startModulation(channel, activeNote, now);
|
|
778
|
+
}
|
|
779
|
+
});
|
|
728
780
|
}
|
|
729
781
|
setVolume(channelNumber, volume) {
|
|
730
782
|
const channel = this.channels[channelNumber];
|
|
@@ -781,8 +833,8 @@ class MidyGMLite {
|
|
|
781
833
|
const velocity = 0;
|
|
782
834
|
const stopPedal = true;
|
|
783
835
|
const promises = [];
|
|
784
|
-
channel.scheduledNotes.forEach((
|
|
785
|
-
const activeNote = this.
|
|
836
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
837
|
+
const activeNote = this.getActiveNote(noteList, now);
|
|
786
838
|
if (activeNote) {
|
|
787
839
|
const notePromise = this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, stopPedal);
|
|
788
840
|
promises.push(notePromise);
|
|
@@ -799,8 +851,8 @@ class MidyGMLite {
|
|
|
799
851
|
const velocity = 0;
|
|
800
852
|
const stopPedal = false;
|
|
801
853
|
const promises = [];
|
|
802
|
-
channel.scheduledNotes.forEach((
|
|
803
|
-
const activeNote = this.
|
|
854
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
855
|
+
const activeNote = this.getActiveNote(noteList, now);
|
|
804
856
|
if (activeNote) {
|
|
805
857
|
const notePromise = this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, stopPedal);
|
|
806
858
|
promises.push(notePromise);
|
|
@@ -895,9 +947,6 @@ Object.defineProperty(MidyGMLite, "channelSettings", {
|
|
|
895
947
|
value: {
|
|
896
948
|
volume: 100 / 127,
|
|
897
949
|
pan: 0,
|
|
898
|
-
vibratoRate: 5,
|
|
899
|
-
vibratoDepth: 0.5,
|
|
900
|
-
vibratoDelay: 2.5,
|
|
901
950
|
bank: 0,
|
|
902
951
|
dataMSB: 0,
|
|
903
952
|
dataLSB: 0,
|
package/script/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/script/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"}
|