@marmooo/midy 0.2.3 → 0.2.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/midy-GM1.d.ts +22 -4
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +120 -23
- package/esm/midy-GM2.d.ts +34 -24
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +194 -133
- package/esm/midy-GMLite.d.ts +23 -5
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +122 -23
- package/esm/midy.d.ts +37 -23
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +303 -132
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +22 -4
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +120 -23
- package/script/midy-GM2.d.ts +34 -24
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +194 -133
- package/script/midy-GMLite.d.ts +23 -5
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +122 -23
- package/script/midy.d.ts +37 -23
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +303 -132
package/script/midy-GMLite.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export class MidyGMLite {
|
|
|
19
19
|
resumeTime: number;
|
|
20
20
|
soundFonts: any[];
|
|
21
21
|
soundFontTable: any[];
|
|
22
|
+
audioBufferCounter: Map<any, any>;
|
|
23
|
+
audioBufferCache: Map<any, any>;
|
|
22
24
|
isPlaying: boolean;
|
|
23
25
|
isPausing: boolean;
|
|
24
26
|
isPaused: boolean;
|
|
@@ -27,7 +29,7 @@ export class MidyGMLite {
|
|
|
27
29
|
timeline: any[];
|
|
28
30
|
instruments: any[];
|
|
29
31
|
notePromises: any[];
|
|
30
|
-
exclusiveClassMap:
|
|
32
|
+
exclusiveClassMap: SparseMap;
|
|
31
33
|
audioContext: any;
|
|
32
34
|
masterVolume: any;
|
|
33
35
|
voiceParamsHandlers: {
|
|
@@ -68,12 +70,13 @@ export class MidyGMLite {
|
|
|
68
70
|
};
|
|
69
71
|
createChannels(audioContext: any): any[];
|
|
70
72
|
createNoteBuffer(voiceParams: any, isSF3: any): Promise<any>;
|
|
71
|
-
createNoteBufferNode(
|
|
73
|
+
createNoteBufferNode(audioBuffer: any, voiceParams: any): any;
|
|
72
74
|
scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
|
|
73
75
|
getQueueIndex(second: any): number;
|
|
74
76
|
playNotes(): Promise<any>;
|
|
75
77
|
ticksToSecond(ticks: any, secondsPerBeat: any): number;
|
|
76
78
|
secondToTicks(second: any, secondsPerBeat: any): number;
|
|
79
|
+
getAudioBufferId(programNumber: any, noteNumber: any, velocity: any): string;
|
|
77
80
|
extractMidiData(midi: any): {
|
|
78
81
|
instruments: Set<any>;
|
|
79
82
|
timeline: any[];
|
|
@@ -87,19 +90,21 @@ export class MidyGMLite {
|
|
|
87
90
|
seekTo(second: any): void;
|
|
88
91
|
calcTotalTime(): number;
|
|
89
92
|
currentTime(): number;
|
|
90
|
-
getActiveNotes(channel: any, time: any):
|
|
93
|
+
getActiveNotes(channel: any, time: any): SparseMap;
|
|
91
94
|
getActiveNote(noteList: any, time: any): any;
|
|
92
95
|
cbToRatio(cb: any): number;
|
|
93
96
|
rateToCent(rate: any): number;
|
|
94
97
|
centToRate(cent: any): number;
|
|
95
98
|
centToHz(cent: any): number;
|
|
96
99
|
calcChannelDetune(channel: any): number;
|
|
97
|
-
|
|
100
|
+
updateChannelDetune(channel: any): void;
|
|
101
|
+
updateDetune(channel: any, note: any): void;
|
|
98
102
|
setVolumeEnvelope(note: any): void;
|
|
99
103
|
setPitchEnvelope(note: any): void;
|
|
100
104
|
clampCutoffFrequency(frequency: any): number;
|
|
101
105
|
setFilterEnvelope(note: any): void;
|
|
102
106
|
startModulation(channel: any, note: any, startTime: any): void;
|
|
107
|
+
getAudioBuffer(program: any, noteNumber: any, velocity: any, voiceParams: any, isSF3: any): Promise<any>;
|
|
103
108
|
createNote(channel: any, voice: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
|
|
104
109
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
105
110
|
noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
|
|
@@ -163,7 +168,7 @@ export class MidyGMLite {
|
|
|
163
168
|
setRPNLSB(channelNumber: any, value: any): void;
|
|
164
169
|
dataEntryMSB(channelNumber: any, value: any): void;
|
|
165
170
|
handlePitchBendRangeRPN(channelNumber: any): void;
|
|
166
|
-
setPitchBendRange(channelNumber: any,
|
|
171
|
+
setPitchBendRange(channelNumber: any, value: any): void;
|
|
167
172
|
allSoundOff(channelNumber: any): Promise<void>;
|
|
168
173
|
resetAllControllers(channelNumber: any): void;
|
|
169
174
|
allNotesOff(channelNumber: any): Promise<void>;
|
|
@@ -176,6 +181,19 @@ export class MidyGMLite {
|
|
|
176
181
|
handleSysEx(data: any): void;
|
|
177
182
|
scheduleTask(callback: any, startTime: any): Promise<any>;
|
|
178
183
|
}
|
|
184
|
+
declare class SparseMap {
|
|
185
|
+
constructor(size: any);
|
|
186
|
+
data: any[];
|
|
187
|
+
activeIndices: any[];
|
|
188
|
+
set(key: any, value: any): void;
|
|
189
|
+
get(key: any): any;
|
|
190
|
+
delete(key: any): boolean;
|
|
191
|
+
has(key: any): boolean;
|
|
192
|
+
get size(): number;
|
|
193
|
+
clear(): void;
|
|
194
|
+
forEach(callback: any): void;
|
|
195
|
+
[Symbol.iterator](): Generator<any[], void, unknown>;
|
|
196
|
+
}
|
|
179
197
|
declare class Note {
|
|
180
198
|
constructor(noteNumber: any, velocity: any, startTime: any, voice: any, voiceParams: any);
|
|
181
199
|
bufferSource: any;
|
|
@@ -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":"AAgJA;IAsBE;;;;;;;;;MASE;IAEF,+BAQC;IAxCD,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,kCAA+B;IAC/B,gCAA6B;IAC7B,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAClB,6BAAuC;IAcrC,kBAAgC;IAChC,kBAA8C;IAC9C;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAKnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAUC;IAED,6DA2BC;IAED,8DASC;IAED,2EA+CC;IAED,mCAOC;IAED,0BAoDC;IAED,uDAEC;IAED,wDAEC;IAED,6EAEC;IAED;;;MA4EC;IAED,+EAmBC;IAED,qDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,mDASC;IAED,6CAQC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,wCAIC;IAED,wCAQC;IAED,4CAKC;IAED,mCAgBC;IAED,kCAqBC;IAED,6CAIC;IAED,mCAuBC;IAED,+DAoBC;IAED,yGAgBC;IAED,gHAuCC;IAED,kGAgDC;IAED,0EAGC;IAED,qFAwBC;IAED,6HAuBC;IAED,0FAGC;IAED,kEAeC;IAED,gFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,mDASC;IAED,gDASC;IAED,qCAMC;IAED,mCAQC;IAED,gCAOC;IAED,+BAMC;IAED;;;;;;;;;;;MAqBC;IAED,oFAMC;IAED,0DA6CC;IAED;;;;;;;;;;;;;MAeC;IAED,+EAWC;IAED,qCAeC;IAED,8DAIC;IACD,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,mDAGC;IAED,wCAWC;IAED,sDAKC;IAED,kFAeC;IAED,oCAYC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,kDAKC;IAED,wDASC;IAED,+CAEC;IAED,8CAqBC;IAED,+CAEC;IAED,4DAgBC;IAED,oBAMC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAv0CD;IACE,uBAGC;IAFC,YAA2B;IAC3B,qBAAuB;IAGzB,gCAKC;IAED,mBAEC;IAED,0BAUC;IAED,uBAEC;IAED,mBAEC;IAED,cAMC;IASD,6BAKC;IAZD,qDAKC;CAQF;AAED;IAQE,0FAMC;IAbD,kBAAa;IACb,gBAAW;IACX,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
|
package/script/midy-GMLite.js
CHANGED
|
@@ -3,6 +3,58 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.MidyGMLite = void 0;
|
|
4
4
|
const midi_file_1 = require("midi-file");
|
|
5
5
|
const soundfont_parser_1 = require("@marmooo/soundfont-parser");
|
|
6
|
+
// 2-3 times faster than Map
|
|
7
|
+
class SparseMap {
|
|
8
|
+
constructor(size) {
|
|
9
|
+
this.data = new Array(size);
|
|
10
|
+
this.activeIndices = [];
|
|
11
|
+
}
|
|
12
|
+
set(key, value) {
|
|
13
|
+
if (this.data[key] === undefined) {
|
|
14
|
+
this.activeIndices.push(key);
|
|
15
|
+
}
|
|
16
|
+
this.data[key] = value;
|
|
17
|
+
}
|
|
18
|
+
get(key) {
|
|
19
|
+
return this.data[key];
|
|
20
|
+
}
|
|
21
|
+
delete(key) {
|
|
22
|
+
if (this.data[key] !== undefined) {
|
|
23
|
+
this.data[key] = undefined;
|
|
24
|
+
const index = this.activeIndices.indexOf(key);
|
|
25
|
+
if (index !== -1) {
|
|
26
|
+
this.activeIndices.splice(index, 1);
|
|
27
|
+
}
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
has(key) {
|
|
33
|
+
return this.data[key] !== undefined;
|
|
34
|
+
}
|
|
35
|
+
get size() {
|
|
36
|
+
return this.activeIndices.length;
|
|
37
|
+
}
|
|
38
|
+
clear() {
|
|
39
|
+
for (let i = 0; i < this.activeIndices.length; i++) {
|
|
40
|
+
const key = this.activeIndices[i];
|
|
41
|
+
this.data[key] = undefined;
|
|
42
|
+
}
|
|
43
|
+
this.activeIndices = [];
|
|
44
|
+
}
|
|
45
|
+
*[Symbol.iterator]() {
|
|
46
|
+
for (let i = 0; i < this.activeIndices.length; i++) {
|
|
47
|
+
const key = this.activeIndices[i];
|
|
48
|
+
yield [key, this.data[key]];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
forEach(callback) {
|
|
52
|
+
for (let i = 0; i < this.activeIndices.length; i++) {
|
|
53
|
+
const key = this.activeIndices[i];
|
|
54
|
+
callback(this.data[key], key, this);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
6
58
|
class Note {
|
|
7
59
|
constructor(noteNumber, velocity, startTime, voice, voiceParams) {
|
|
8
60
|
Object.defineProperty(this, "bufferSource", {
|
|
@@ -169,6 +221,18 @@ class MidyGMLite {
|
|
|
169
221
|
writable: true,
|
|
170
222
|
value: this.initSoundFontTable()
|
|
171
223
|
});
|
|
224
|
+
Object.defineProperty(this, "audioBufferCounter", {
|
|
225
|
+
enumerable: true,
|
|
226
|
+
configurable: true,
|
|
227
|
+
writable: true,
|
|
228
|
+
value: new Map()
|
|
229
|
+
});
|
|
230
|
+
Object.defineProperty(this, "audioBufferCache", {
|
|
231
|
+
enumerable: true,
|
|
232
|
+
configurable: true,
|
|
233
|
+
writable: true,
|
|
234
|
+
value: new Map()
|
|
235
|
+
});
|
|
172
236
|
Object.defineProperty(this, "isPlaying", {
|
|
173
237
|
enumerable: true,
|
|
174
238
|
configurable: true,
|
|
@@ -221,7 +285,7 @@ class MidyGMLite {
|
|
|
221
285
|
enumerable: true,
|
|
222
286
|
configurable: true,
|
|
223
287
|
writable: true,
|
|
224
|
-
value: new
|
|
288
|
+
value: new SparseMap(128)
|
|
225
289
|
});
|
|
226
290
|
this.audioContext = audioContext;
|
|
227
291
|
this.masterVolume = new GainNode(audioContext);
|
|
@@ -234,7 +298,7 @@ class MidyGMLite {
|
|
|
234
298
|
initSoundFontTable() {
|
|
235
299
|
const table = new Array(128);
|
|
236
300
|
for (let i = 0; i < 128; i++) {
|
|
237
|
-
table[i] = new
|
|
301
|
+
table[i] = new SparseMap(128);
|
|
238
302
|
}
|
|
239
303
|
return table;
|
|
240
304
|
}
|
|
@@ -287,7 +351,7 @@ class MidyGMLite {
|
|
|
287
351
|
...this.constructor.channelSettings,
|
|
288
352
|
state: new ControllerState(),
|
|
289
353
|
...this.setChannelAudioNodes(audioContext),
|
|
290
|
-
scheduledNotes: new
|
|
354
|
+
scheduledNotes: new SparseMap(128),
|
|
291
355
|
};
|
|
292
356
|
});
|
|
293
357
|
return channels;
|
|
@@ -321,9 +385,8 @@ class MidyGMLite {
|
|
|
321
385
|
return audioBuffer;
|
|
322
386
|
}
|
|
323
387
|
}
|
|
324
|
-
|
|
388
|
+
createNoteBufferNode(audioBuffer, voiceParams) {
|
|
325
389
|
const bufferSource = new AudioBufferSourceNode(this.audioContext);
|
|
326
|
-
const audioBuffer = await this.createNoteBuffer(voiceParams, isSF3);
|
|
327
390
|
bufferSource.buffer = audioBuffer;
|
|
328
391
|
bufferSource.loop = voiceParams.sampleModes % 2 !== 0;
|
|
329
392
|
if (bufferSource.loop) {
|
|
@@ -388,6 +451,7 @@ class MidyGMLite {
|
|
|
388
451
|
await Promise.all(this.notePromises);
|
|
389
452
|
this.notePromises = [];
|
|
390
453
|
this.exclusiveClassMap.clear();
|
|
454
|
+
this.audioBufferCache.clear();
|
|
391
455
|
resolve();
|
|
392
456
|
return;
|
|
393
457
|
}
|
|
@@ -403,8 +467,9 @@ class MidyGMLite {
|
|
|
403
467
|
}
|
|
404
468
|
else if (this.isStopping) {
|
|
405
469
|
await this.stopNotes(0, true);
|
|
406
|
-
this.exclusiveClassMap.clear();
|
|
407
470
|
this.notePromises = [];
|
|
471
|
+
this.exclusiveClassMap.clear();
|
|
472
|
+
this.audioBufferCache.clear();
|
|
408
473
|
resolve();
|
|
409
474
|
this.isStopping = false;
|
|
410
475
|
this.isPaused = false;
|
|
@@ -435,6 +500,9 @@ class MidyGMLite {
|
|
|
435
500
|
secondToTicks(second, secondsPerBeat) {
|
|
436
501
|
return second * this.ticksPerBeat / secondsPerBeat;
|
|
437
502
|
}
|
|
503
|
+
getAudioBufferId(programNumber, noteNumber, velocity) {
|
|
504
|
+
return `${programNumber}:${noteNumber}:${velocity}`;
|
|
505
|
+
}
|
|
438
506
|
extractMidiData(midi) {
|
|
439
507
|
const instruments = new Set();
|
|
440
508
|
const timeline = [];
|
|
@@ -455,6 +523,8 @@ class MidyGMLite {
|
|
|
455
523
|
switch (event.type) {
|
|
456
524
|
case "noteOn": {
|
|
457
525
|
const channel = tmpChannels[event.channel];
|
|
526
|
+
const audioBufferId = this.getAudioBufferId(channel.programNumber, event.noteNumber, event.velocity);
|
|
527
|
+
this.audioBufferCounter.set(audioBufferId, (this.audioBufferCounter.get(audioBufferId) ?? 0) + 1);
|
|
458
528
|
if (channel.programNumber < 0) {
|
|
459
529
|
instruments.add(`${channel.bank}:0`);
|
|
460
530
|
channel.programNumber = 0;
|
|
@@ -471,6 +541,10 @@ class MidyGMLite {
|
|
|
471
541
|
timeline.push(event);
|
|
472
542
|
}
|
|
473
543
|
}
|
|
544
|
+
for (const [audioBufferId, count] of this.audioBufferCounter) {
|
|
545
|
+
if (count === 1)
|
|
546
|
+
this.audioBufferCounter.delete(audioBufferId);
|
|
547
|
+
}
|
|
474
548
|
const priority = {
|
|
475
549
|
controller: 0,
|
|
476
550
|
sysEx: 1,
|
|
@@ -561,7 +635,7 @@ class MidyGMLite {
|
|
|
561
635
|
return this.resumeTime + now - this.startTime - this.startDelay;
|
|
562
636
|
}
|
|
563
637
|
getActiveNotes(channel, time) {
|
|
564
|
-
const activeNotes = new
|
|
638
|
+
const activeNotes = new SparseMap(128);
|
|
565
639
|
channel.scheduledNotes.forEach((noteList) => {
|
|
566
640
|
const activeNote = this.getActiveNote(noteList, time);
|
|
567
641
|
if (activeNote) {
|
|
@@ -598,19 +672,22 @@ class MidyGMLite {
|
|
|
598
672
|
const pitchWheelSensitivity = channel.state.pitchWheelSensitivity * 12800;
|
|
599
673
|
return pitchWheel * pitchWheelSensitivity;
|
|
600
674
|
}
|
|
601
|
-
|
|
602
|
-
const now = this.audioContext.currentTime;
|
|
675
|
+
updateChannelDetune(channel) {
|
|
603
676
|
channel.scheduledNotes.forEach((noteList) => {
|
|
604
677
|
for (let i = 0; i < noteList.length; i++) {
|
|
605
678
|
const note = noteList[i];
|
|
606
679
|
if (!note)
|
|
607
680
|
continue;
|
|
608
|
-
note
|
|
609
|
-
.cancelScheduledValues(now)
|
|
610
|
-
.setValueAtTime(channel.detune, now);
|
|
681
|
+
this.updateDetune(channel, note);
|
|
611
682
|
}
|
|
612
683
|
});
|
|
613
684
|
}
|
|
685
|
+
updateDetune(channel, note) {
|
|
686
|
+
const now = this.audioContext.currentTime;
|
|
687
|
+
note.bufferSource.detune
|
|
688
|
+
.cancelScheduledValues(now)
|
|
689
|
+
.setValueAtTime(channel.detune, now);
|
|
690
|
+
}
|
|
614
691
|
setVolumeEnvelope(note) {
|
|
615
692
|
const now = this.audioContext.currentTime;
|
|
616
693
|
const { voiceParams, startTime } = note;
|
|
@@ -698,11 +775,31 @@ class MidyGMLite {
|
|
|
698
775
|
note.modulationLFO.connect(note.volumeDepth);
|
|
699
776
|
note.volumeDepth.connect(note.volumeEnvelopeNode.gain);
|
|
700
777
|
}
|
|
778
|
+
async getAudioBuffer(program, noteNumber, velocity, voiceParams, isSF3) {
|
|
779
|
+
const audioBufferId = this.getAudioBufferId(program, noteNumber, velocity);
|
|
780
|
+
const cache = this.audioBufferCache.get(audioBufferId);
|
|
781
|
+
if (cache) {
|
|
782
|
+
cache.counter += 1;
|
|
783
|
+
if (cache.maxCount <= cache.counter) {
|
|
784
|
+
this.audioBufferCache.delete(audioBufferId);
|
|
785
|
+
}
|
|
786
|
+
return cache.audioBuffer;
|
|
787
|
+
}
|
|
788
|
+
else {
|
|
789
|
+
const maxCount = this.audioBufferCounter.get(audioBufferId) ?? 0;
|
|
790
|
+
const audioBuffer = await this.createNoteBuffer(voiceParams, isSF3);
|
|
791
|
+
const cache = { audioBuffer, maxCount, counter: 1 };
|
|
792
|
+
this.audioBufferCache.set(audioBufferId, cache);
|
|
793
|
+
return audioBuffer;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
701
796
|
async createNote(channel, voice, noteNumber, velocity, startTime, isSF3) {
|
|
702
797
|
const state = channel.state;
|
|
703
|
-
const
|
|
798
|
+
const controllerState = this.getControllerState(channel, noteNumber, velocity);
|
|
799
|
+
const voiceParams = voice.getAllParams(controllerState);
|
|
704
800
|
const note = new Note(noteNumber, velocity, startTime, voice, voiceParams);
|
|
705
|
-
|
|
801
|
+
const audioBuffer = await this.getAudioBuffer(channel.program, noteNumber, velocity, voiceParams, isSF3);
|
|
802
|
+
note.bufferSource = this.createNoteBufferNode(audioBuffer, voiceParams);
|
|
706
803
|
note.volumeEnvelopeNode = new GainNode(this.audioContext);
|
|
707
804
|
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
708
805
|
type: "lowpass",
|
|
@@ -726,10 +823,10 @@ class MidyGMLite {
|
|
|
726
823
|
if (soundFontIndex === undefined)
|
|
727
824
|
return;
|
|
728
825
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
729
|
-
const isSF3 = soundFont.parsed.info.version.major === 3;
|
|
730
826
|
const voice = soundFont.getVoice(bankNumber, channel.program, noteNumber, velocity);
|
|
731
827
|
if (!voice)
|
|
732
828
|
return;
|
|
829
|
+
const isSF3 = soundFont.parsed.info.version.major === 3;
|
|
733
830
|
const note = await this.createNote(channel, voice, noteNumber, velocity, startTime, isSF3);
|
|
734
831
|
note.volumeEnvelopeNode.connect(channel.gainL);
|
|
735
832
|
note.volumeEnvelopeNode.connect(channel.gainR);
|
|
@@ -859,7 +956,7 @@ class MidyGMLite {
|
|
|
859
956
|
const next = (value - 8192) / 8192;
|
|
860
957
|
state.pitchWheel = value / 16383;
|
|
861
958
|
channel.detune += (next - prev) * state.pitchWheelSensitivity * 12800;
|
|
862
|
-
this.
|
|
959
|
+
this.updateChannelDetune(channel);
|
|
863
960
|
this.applyVoiceParams(channel, 14);
|
|
864
961
|
}
|
|
865
962
|
setModLfoToPitch(channel, note) {
|
|
@@ -963,7 +1060,7 @@ class MidyGMLite {
|
|
|
963
1060
|
if (key in voiceParams)
|
|
964
1061
|
noteVoiceParams[key] = voiceParams[key];
|
|
965
1062
|
}
|
|
966
|
-
this.setFilterEnvelope(
|
|
1063
|
+
this.setFilterEnvelope(note);
|
|
967
1064
|
this.setPitchEnvelope(note);
|
|
968
1065
|
}
|
|
969
1066
|
else if (volumeEnvelopeKeySet.has(key)) {
|
|
@@ -1003,7 +1100,7 @@ class MidyGMLite {
|
|
|
1003
1100
|
if (handler) {
|
|
1004
1101
|
handler.call(this, channelNumber, value);
|
|
1005
1102
|
const channel = this.channels[channelNumber];
|
|
1006
|
-
this.applyVoiceParams(channel,
|
|
1103
|
+
this.applyVoiceParams(channel, controllerType + 128);
|
|
1007
1104
|
}
|
|
1008
1105
|
else {
|
|
1009
1106
|
console.warn(`Unsupported Control change: controllerType=${controllerType} value=${value}`);
|
|
@@ -1121,12 +1218,14 @@ class MidyGMLite {
|
|
|
1121
1218
|
const pitchBendRange = channel.dataMSB + channel.dataLSB / 100;
|
|
1122
1219
|
this.setPitchBendRange(channelNumber, pitchBendRange);
|
|
1123
1220
|
}
|
|
1124
|
-
setPitchBendRange(channelNumber,
|
|
1221
|
+
setPitchBendRange(channelNumber, value) {
|
|
1125
1222
|
const channel = this.channels[channelNumber];
|
|
1126
1223
|
const state = channel.state;
|
|
1127
|
-
|
|
1128
|
-
const
|
|
1129
|
-
|
|
1224
|
+
const prev = state.pitchWheelSensitivity;
|
|
1225
|
+
const next = value / 128;
|
|
1226
|
+
state.pitchWheelSensitivity = next;
|
|
1227
|
+
channel.detune += (state.pitchWheel * 2 - 1) * (next - prev) * 12800;
|
|
1228
|
+
this.updateChannelDetune(channel);
|
|
1130
1229
|
this.applyVoiceParams(channel, 16);
|
|
1131
1230
|
}
|
|
1132
1231
|
allSoundOff(channelNumber) {
|
|
@@ -1143,7 +1242,7 @@ class MidyGMLite {
|
|
|
1143
1242
|
const state = channel.state;
|
|
1144
1243
|
for (let i = 0; i < stateTypes.length; i++) {
|
|
1145
1244
|
const type = stateTypes[i];
|
|
1146
|
-
state[type] = defaultControllerState[type];
|
|
1245
|
+
state[type] = defaultControllerState[type].defaultValue;
|
|
1147
1246
|
}
|
|
1148
1247
|
const settingTypes = [
|
|
1149
1248
|
"rpnMSB",
|
package/script/midy.d.ts
CHANGED
|
@@ -2,8 +2,9 @@ export class Midy {
|
|
|
2
2
|
static channelSettings: {
|
|
3
3
|
currentBufferSource: null;
|
|
4
4
|
detune: number;
|
|
5
|
-
scaleOctaveTuningTable:
|
|
6
|
-
|
|
5
|
+
scaleOctaveTuningTable: Float32Array<ArrayBuffer>;
|
|
6
|
+
channelPressureTable: Uint8Array<ArrayBuffer>;
|
|
7
|
+
polyphonicKeyPressureTable: Uint8Array<ArrayBuffer>;
|
|
7
8
|
keyBasedInstrumentControlTable: Int8Array<ArrayBuffer>;
|
|
8
9
|
program: number;
|
|
9
10
|
bank: number;
|
|
@@ -17,14 +18,6 @@ export class Midy {
|
|
|
17
18
|
coarseTuning: number;
|
|
18
19
|
modulationDepthRange: number;
|
|
19
20
|
};
|
|
20
|
-
static controllerDestinationSettings: {
|
|
21
|
-
pitchControl: number;
|
|
22
|
-
filterCutoffControl: number;
|
|
23
|
-
amplitudeControl: number;
|
|
24
|
-
lfoPitchDepth: number;
|
|
25
|
-
lfoFilterDepth: number;
|
|
26
|
-
lfoAmplitudeDepth: number;
|
|
27
|
-
};
|
|
28
21
|
constructor(audioContext: any, options?: {
|
|
29
22
|
reverbAlgorithm: (audioContext: any) => {
|
|
30
23
|
input: any;
|
|
@@ -55,6 +48,8 @@ export class Midy {
|
|
|
55
48
|
resumeTime: number;
|
|
56
49
|
soundFonts: any[];
|
|
57
50
|
soundFontTable: any[];
|
|
51
|
+
audioBufferCounter: Map<any, any>;
|
|
52
|
+
audioBufferCache: Map<any, any>;
|
|
58
53
|
isPlaying: boolean;
|
|
59
54
|
isPausing: boolean;
|
|
60
55
|
isPaused: boolean;
|
|
@@ -63,7 +58,7 @@ export class Midy {
|
|
|
63
58
|
timeline: any[];
|
|
64
59
|
instruments: any[];
|
|
65
60
|
notePromises: any[];
|
|
66
|
-
exclusiveClassMap:
|
|
61
|
+
exclusiveClassMap: SparseMap;
|
|
67
62
|
defaultOptions: {
|
|
68
63
|
reverbAlgorithm: (audioContext: any) => {
|
|
69
64
|
input: any;
|
|
@@ -151,13 +146,14 @@ export class Midy {
|
|
|
151
146
|
};
|
|
152
147
|
createChannels(audioContext: any): any[];
|
|
153
148
|
createNoteBuffer(voiceParams: any, isSF3: any): Promise<any>;
|
|
154
|
-
createNoteBufferNode(
|
|
149
|
+
createNoteBufferNode(audioBuffer: any, voiceParams: any): any;
|
|
155
150
|
findPortamentoTarget(queueIndex: any): any;
|
|
156
151
|
scheduleTimelineEvents(t: any, offset: any, queueIndex: any): Promise<any>;
|
|
157
152
|
getQueueIndex(second: any): number;
|
|
158
153
|
playNotes(): Promise<any>;
|
|
159
154
|
ticksToSecond(ticks: any, secondsPerBeat: any): number;
|
|
160
155
|
secondToTicks(second: any, secondsPerBeat: any): number;
|
|
156
|
+
getAudioBufferId(programNumber: any, noteNumber: any, velocity: any): string;
|
|
161
157
|
extractMidiData(midi: any): {
|
|
162
158
|
instruments: Set<any>;
|
|
163
159
|
timeline: any[];
|
|
@@ -171,7 +167,7 @@ export class Midy {
|
|
|
171
167
|
seekTo(second: any): void;
|
|
172
168
|
calcTotalTime(): number;
|
|
173
169
|
currentTime(): number;
|
|
174
|
-
getActiveNotes(channel: any, time: any):
|
|
170
|
+
getActiveNotes(channel: any, time: any): SparseMap;
|
|
175
171
|
getActiveNote(noteList: any, time: any): any;
|
|
176
172
|
createConvolutionReverbImpulse(audioContext: any, decay: any, preDecay: any): any;
|
|
177
173
|
createConvolutionReverb(audioContext: any, impulse: any): {
|
|
@@ -201,16 +197,18 @@ export class Midy {
|
|
|
201
197
|
centToHz(cent: any): number;
|
|
202
198
|
calcChannelDetune(channel: any): any;
|
|
203
199
|
calcNoteDetune(channel: any, note: any): any;
|
|
204
|
-
|
|
200
|
+
updateChannelDetune(channel: any): void;
|
|
201
|
+
updateDetune(channel: any, note: any, pressure: any): void;
|
|
205
202
|
getPortamentoTime(channel: any): number;
|
|
206
203
|
setPortamentoStartVolumeEnvelope(channel: any, note: any): void;
|
|
207
|
-
setVolumeEnvelope(channel: any, note: any): void;
|
|
204
|
+
setVolumeEnvelope(channel: any, note: any, pressure: any): void;
|
|
208
205
|
setPitchEnvelope(note: any): void;
|
|
209
206
|
clampCutoffFrequency(frequency: any): number;
|
|
210
207
|
setPortamentoStartFilterEnvelope(channel: any, note: any): void;
|
|
211
|
-
setFilterEnvelope(channel: any, note: any): void;
|
|
208
|
+
setFilterEnvelope(channel: any, note: any, pressure: any): void;
|
|
212
209
|
startModulation(channel: any, note: any, startTime: any): void;
|
|
213
210
|
startVibrato(channel: any, note: any, startTime: any): void;
|
|
211
|
+
getAudioBuffer(program: any, noteNumber: any, velocity: any, voiceParams: any, isSF3: any): Promise<any>;
|
|
214
212
|
createNote(channel: any, voice: any, noteNumber: any, velocity: any, startTime: any, portamento: any, isSF3: any): Promise<Note>;
|
|
215
213
|
calcBank(channel: any, channelNumber: any): any;
|
|
216
214
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any, portamento: any): Promise<void>;
|
|
@@ -226,14 +224,15 @@ export class Midy {
|
|
|
226
224
|
handleChannelPressure(channelNumber: any, value: any): void;
|
|
227
225
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
|
|
228
226
|
setPitchBend(channelNumber: any, value: any): void;
|
|
229
|
-
setModLfoToPitch(channel: any, note: any): void;
|
|
227
|
+
setModLfoToPitch(channel: any, note: any, pressure: any): void;
|
|
230
228
|
setVibLfoToPitch(channel: any, note: any): void;
|
|
231
|
-
setModLfoToFilterFc(
|
|
232
|
-
setModLfoToVolume(
|
|
229
|
+
setModLfoToFilterFc(note: any, pressure: any): void;
|
|
230
|
+
setModLfoToVolume(note: any, pressure: any): void;
|
|
233
231
|
setReverbEffectsSend(channel: any, note: any, prevValue: any): void;
|
|
234
232
|
setChorusEffectsSend(channel: any, note: any, prevValue: any): void;
|
|
235
233
|
setDelayModLFO(note: any): void;
|
|
236
234
|
setFreqModLFO(note: any): void;
|
|
235
|
+
setFreqVibLFO(channel: any, note: any): void;
|
|
237
236
|
createVoiceParamsHandlers(): {
|
|
238
237
|
modLfoToPitch: (channel: any, note: any, _prevValue: any) => void;
|
|
239
238
|
vibLfoToPitch: (channel: any, note: any, _prevValue: any) => void;
|
|
@@ -341,7 +340,7 @@ export class Midy {
|
|
|
341
340
|
handleUniversalNonRealTimeExclusiveMessage(data: any): void;
|
|
342
341
|
GM1SystemOn(): void;
|
|
343
342
|
GM2SystemOn(): void;
|
|
344
|
-
handleUniversalRealTimeExclusiveMessage(data: any):
|
|
343
|
+
handleUniversalRealTimeExclusiveMessage(data: any): any;
|
|
345
344
|
handleMasterVolumeSysEx(data: any): void;
|
|
346
345
|
setMasterVolume(volume: any): void;
|
|
347
346
|
handleMasterFineTuningSysEx(data: any): void;
|
|
@@ -367,18 +366,32 @@ export class Midy {
|
|
|
367
366
|
setChorusSendToReverb(value: any): void;
|
|
368
367
|
getChorusSendToReverb(value: any): number;
|
|
369
368
|
getChannelBitmap(data: any): any[];
|
|
370
|
-
handleScaleOctaveTuning1ByteFormatSysEx(data: any): void;
|
|
369
|
+
handleScaleOctaveTuning1ByteFormatSysEx(data: any, realtime: any): void;
|
|
370
|
+
handleScaleOctaveTuning2ByteFormatSysEx(data: any, realtime: any): void;
|
|
371
371
|
applyDestinationSettings(channel: any, note: any, table: any): void;
|
|
372
|
-
handleChannelPressureSysEx(data: any): void;
|
|
372
|
+
handleChannelPressureSysEx(data: any, tableName: any): void;
|
|
373
373
|
initControlTable(): Uint8Array<ArrayBuffer>;
|
|
374
374
|
applyControlTable(channel: any, controllerType: any): void;
|
|
375
375
|
handleControlChangeSysEx(data: any): void;
|
|
376
376
|
getKeyBasedInstrumentControlValue(channel: any, keyNumber: any, controllerType: any): number;
|
|
377
377
|
handleKeyBasedInstrumentControlSysEx(data: any): void;
|
|
378
378
|
handleExclusiveMessage(data: any): void;
|
|
379
|
-
handleSysEx(data: any):
|
|
379
|
+
handleSysEx(data: any): any;
|
|
380
380
|
scheduleTask(callback: any, startTime: any): Promise<any>;
|
|
381
381
|
}
|
|
382
|
+
declare class SparseMap {
|
|
383
|
+
constructor(size: any);
|
|
384
|
+
data: any[];
|
|
385
|
+
activeIndices: any[];
|
|
386
|
+
set(key: any, value: any): void;
|
|
387
|
+
get(key: any): any;
|
|
388
|
+
delete(key: any): boolean;
|
|
389
|
+
has(key: any): boolean;
|
|
390
|
+
get size(): number;
|
|
391
|
+
clear(): void;
|
|
392
|
+
forEach(callback: any): void;
|
|
393
|
+
[Symbol.iterator](): Generator<any[], void, unknown>;
|
|
394
|
+
}
|
|
382
395
|
declare class Note {
|
|
383
396
|
constructor(noteNumber: any, velocity: any, startTime: any, voice: any, voiceParams: any);
|
|
384
397
|
bufferSource: any;
|
|
@@ -395,6 +408,7 @@ declare class Note {
|
|
|
395
408
|
reverbEffectsSend: any;
|
|
396
409
|
chorusEffectsSend: any;
|
|
397
410
|
portamento: any;
|
|
411
|
+
pressure: number;
|
|
398
412
|
noteNumber: any;
|
|
399
413
|
velocity: any;
|
|
400
414
|
startTime: any;
|
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":"AA+KA;IAqCE;;;;;;;;;;;;;;;;;;MAkBE;IAgCF;;;;;OAaC;IAnGD,qBAAmB;IACnB,kBAAc;IACd,yBAAqB;IACrB,2BAAuB;IACvB;;;MAGE;IACF;;;;;;MAME;IACF,cAAa;IACb,cAAa;IACb,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,kCAA+B;IAC/B,gCAA6B;IAC7B,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAClB,6BAAuC;IAsBvC;;;;;MA4BE;IAGA,kBAAgC;IAChC;;;;;MAAqD;IACrD,kBAA8C;IAC9C;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IACjD;;;MAA8D;IAC9D;;;;;;;;MAAyD;IAO3D,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAYC;IAED,6DA2BC;IAED,8DASC;IAED,2CAcC;IAED,2EA8DC;IAED,mCAOC;IAED,0BAoDC;IAED,uDAEC;IAED,wDAEC;IAED,6EAEC;IAED;;;MAgHC;IAED,+EAoBC;IAED,qDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,mDASC;IAED,6CAQC;IAED,kFAuBC;IAED;;;;MAWC;IAED,gFAUC;IAED,mFAYC;IAED,sGAcC;IAID;;;MA8BC;IAED;;;;;;;;MA0CC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,qCAUC;IAED,6CAEC;IAED,wCAQC;IAED,2DAOC;IAED,wCAIC;IAED,gEAWC;IAED,gEAkBC;IAED,kCAqBC;IAED,6CAIC;IAED,gEAuBC;IAED,gEA2BC;IAED,+DAoBC;IAED,4DAaC;IAED,yGAgBC;IAED,iIAoEC;IAED,gDAQC;IAED,mHA0DC;IAED,2FASC;IAED,qFAqCC;IAED,wJAwCC;IAED,qHAUC;IAED,kEAeC;IAED,oEAYC;IAED,gFAqBC;IAED,sFAWC;IAED,4DAIC;IAED,4DAeC;IAED,qEAGC;IAED,mDASC;IAED,+DAQC;IAED,gDASC;IAED,oDAMC;IAED,kDAQC;IAED,oEA2BC;IAED,oEA2BC;IAED,gCAOC;IAED,+BAMC;IAED,6CAMC;IAED;;;;;;;;;;;MAgDC;IAED,oFAMC;IAED,0DAiDC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAqCC;IAED,+EAYC;IAED,+CAEC;IAED,qCAeC;IAED,8DAIC;IAED,iEAIC;IAED,sCAiBC;IAED,iDAKC;IAED;;;MAMC;IAED,mCAqBC;IAED,2CAKC;IAED,yDAIC;IAED,+CAEC;IAED,mDAGC;IAED,wCAWC;IAED,sDAKC;IAED,oDAEC;IAED,wDASC;IAED,uDAGC;IAED,mEAaC;IAED,2DAGC;IAED,yDAYC;IAED,yDAcC;IAED,uDAUC;IAED,2DAWC;IAED,6DAqBC;IAED,6DAYC;IAED,mEAmCC;IAED,mEAmCC;IAED,kFAeC;IAED,2DAMC;IAED,gDAyBC;IAGD,wCAEC;IAGD,wCAEC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,kDAKC;IAED,wDASC;IAED,8CAKC;IAED,oDAOC;IAED,gDAKC;IAED,sDAOC;IAED,wDAKC;IAED,6EAIC;IAED,+CAEC;IAED,8CAyBC;IAED,+CAEC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DA+BC;IAED,oBASC;IAED,oBASC;IAED,wDAkDC;IAED,yCAGC;IAED,mCAQC;IAED,6CAGC;IAED,sCAMC;IAED,+CAGC;IAED,wCAMC;IAED,mDAeC;IAED,4CAOC;IAED,+BAKC;IAED,qDAiBC;IAED,gCAIC;IAED,kCAEC;IA6BD,4CAEC;IAED,4CAaC;IAED,+BAiBC;IAED,wFAKC;IAED,mCAKC;IAED,qCAEC;IAED,oCAOC;IAED,sCAEC;IAED,oCAUC;IAED,sCAEC;IAED,wCAuBC;IAED,0CAEC;IAED,mCAeC;IAED,wEAeC;IAED,wEAmBC;IAED,oEAuDC;IAED,4DAQC;IAED,4CAUC;IAED,2DAWC;IAED,0CASC;IAED,6FAIC;IAED,sDAcC;IAED,wCAEC;IAED,4BASC;IAED,0DAUC;CACF;AAryFD;IACE,uBAGC;IAFC,YAA2B;IAC3B,qBAAuB;IAGzB,gCAKC;IAED,mBAEC;IAED,0BAUC;IAED,uBAEC;IAED,mBAEC;IAED,cAMC;IASD,6BAKC;IAZD,qDAKC;CAQF;AAED;IAiBE,0FAMC;IAtBD,kBAAa;IACb,gBAAW;IACX,wBAAmB;IACnB,gBAAW;IACX,WAAM;IACN,WAAM;IACN,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAChB,gBAAW;IACX,kBAAa;IACb,uBAAkB;IAClB,uBAAkB;IAClB,gBAAW;IACX,iBAAa;IAGX,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
|