@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/esm/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;
|
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":"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/esm/midy-GMLite.js
CHANGED
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
import { parseMidi } from "midi-file";
|
|
2
2
|
import { parse, SoundFont } from "@marmooo/soundfont-parser";
|
|
3
|
+
// 2-3 times faster than Map
|
|
4
|
+
class SparseMap {
|
|
5
|
+
constructor(size) {
|
|
6
|
+
this.data = new Array(size);
|
|
7
|
+
this.activeIndices = [];
|
|
8
|
+
}
|
|
9
|
+
set(key, value) {
|
|
10
|
+
if (this.data[key] === undefined) {
|
|
11
|
+
this.activeIndices.push(key);
|
|
12
|
+
}
|
|
13
|
+
this.data[key] = value;
|
|
14
|
+
}
|
|
15
|
+
get(key) {
|
|
16
|
+
return this.data[key];
|
|
17
|
+
}
|
|
18
|
+
delete(key) {
|
|
19
|
+
if (this.data[key] !== undefined) {
|
|
20
|
+
this.data[key] = undefined;
|
|
21
|
+
const index = this.activeIndices.indexOf(key);
|
|
22
|
+
if (index !== -1) {
|
|
23
|
+
this.activeIndices.splice(index, 1);
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
has(key) {
|
|
30
|
+
return this.data[key] !== undefined;
|
|
31
|
+
}
|
|
32
|
+
get size() {
|
|
33
|
+
return this.activeIndices.length;
|
|
34
|
+
}
|
|
35
|
+
clear() {
|
|
36
|
+
for (let i = 0; i < this.activeIndices.length; i++) {
|
|
37
|
+
const key = this.activeIndices[i];
|
|
38
|
+
this.data[key] = undefined;
|
|
39
|
+
}
|
|
40
|
+
this.activeIndices = [];
|
|
41
|
+
}
|
|
42
|
+
*[Symbol.iterator]() {
|
|
43
|
+
for (let i = 0; i < this.activeIndices.length; i++) {
|
|
44
|
+
const key = this.activeIndices[i];
|
|
45
|
+
yield [key, this.data[key]];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
forEach(callback) {
|
|
49
|
+
for (let i = 0; i < this.activeIndices.length; i++) {
|
|
50
|
+
const key = this.activeIndices[i];
|
|
51
|
+
callback(this.data[key], key, this);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
3
55
|
class Note {
|
|
4
56
|
constructor(noteNumber, velocity, startTime, voice, voiceParams) {
|
|
5
57
|
Object.defineProperty(this, "bufferSource", {
|
|
@@ -166,6 +218,18 @@ export class MidyGMLite {
|
|
|
166
218
|
writable: true,
|
|
167
219
|
value: this.initSoundFontTable()
|
|
168
220
|
});
|
|
221
|
+
Object.defineProperty(this, "audioBufferCounter", {
|
|
222
|
+
enumerable: true,
|
|
223
|
+
configurable: true,
|
|
224
|
+
writable: true,
|
|
225
|
+
value: new Map()
|
|
226
|
+
});
|
|
227
|
+
Object.defineProperty(this, "audioBufferCache", {
|
|
228
|
+
enumerable: true,
|
|
229
|
+
configurable: true,
|
|
230
|
+
writable: true,
|
|
231
|
+
value: new Map()
|
|
232
|
+
});
|
|
169
233
|
Object.defineProperty(this, "isPlaying", {
|
|
170
234
|
enumerable: true,
|
|
171
235
|
configurable: true,
|
|
@@ -218,7 +282,7 @@ export class MidyGMLite {
|
|
|
218
282
|
enumerable: true,
|
|
219
283
|
configurable: true,
|
|
220
284
|
writable: true,
|
|
221
|
-
value: new
|
|
285
|
+
value: new SparseMap(128)
|
|
222
286
|
});
|
|
223
287
|
this.audioContext = audioContext;
|
|
224
288
|
this.masterVolume = new GainNode(audioContext);
|
|
@@ -231,7 +295,7 @@ export class MidyGMLite {
|
|
|
231
295
|
initSoundFontTable() {
|
|
232
296
|
const table = new Array(128);
|
|
233
297
|
for (let i = 0; i < 128; i++) {
|
|
234
|
-
table[i] = new
|
|
298
|
+
table[i] = new SparseMap(128);
|
|
235
299
|
}
|
|
236
300
|
return table;
|
|
237
301
|
}
|
|
@@ -284,7 +348,7 @@ export class MidyGMLite {
|
|
|
284
348
|
...this.constructor.channelSettings,
|
|
285
349
|
state: new ControllerState(),
|
|
286
350
|
...this.setChannelAudioNodes(audioContext),
|
|
287
|
-
scheduledNotes: new
|
|
351
|
+
scheduledNotes: new SparseMap(128),
|
|
288
352
|
};
|
|
289
353
|
});
|
|
290
354
|
return channels;
|
|
@@ -318,9 +382,8 @@ export class MidyGMLite {
|
|
|
318
382
|
return audioBuffer;
|
|
319
383
|
}
|
|
320
384
|
}
|
|
321
|
-
|
|
385
|
+
createNoteBufferNode(audioBuffer, voiceParams) {
|
|
322
386
|
const bufferSource = new AudioBufferSourceNode(this.audioContext);
|
|
323
|
-
const audioBuffer = await this.createNoteBuffer(voiceParams, isSF3);
|
|
324
387
|
bufferSource.buffer = audioBuffer;
|
|
325
388
|
bufferSource.loop = voiceParams.sampleModes % 2 !== 0;
|
|
326
389
|
if (bufferSource.loop) {
|
|
@@ -385,6 +448,7 @@ export class MidyGMLite {
|
|
|
385
448
|
await Promise.all(this.notePromises);
|
|
386
449
|
this.notePromises = [];
|
|
387
450
|
this.exclusiveClassMap.clear();
|
|
451
|
+
this.audioBufferCache.clear();
|
|
388
452
|
resolve();
|
|
389
453
|
return;
|
|
390
454
|
}
|
|
@@ -400,8 +464,9 @@ export class MidyGMLite {
|
|
|
400
464
|
}
|
|
401
465
|
else if (this.isStopping) {
|
|
402
466
|
await this.stopNotes(0, true);
|
|
403
|
-
this.exclusiveClassMap.clear();
|
|
404
467
|
this.notePromises = [];
|
|
468
|
+
this.exclusiveClassMap.clear();
|
|
469
|
+
this.audioBufferCache.clear();
|
|
405
470
|
resolve();
|
|
406
471
|
this.isStopping = false;
|
|
407
472
|
this.isPaused = false;
|
|
@@ -432,6 +497,9 @@ export class MidyGMLite {
|
|
|
432
497
|
secondToTicks(second, secondsPerBeat) {
|
|
433
498
|
return second * this.ticksPerBeat / secondsPerBeat;
|
|
434
499
|
}
|
|
500
|
+
getAudioBufferId(programNumber, noteNumber, velocity) {
|
|
501
|
+
return `${programNumber}:${noteNumber}:${velocity}`;
|
|
502
|
+
}
|
|
435
503
|
extractMidiData(midi) {
|
|
436
504
|
const instruments = new Set();
|
|
437
505
|
const timeline = [];
|
|
@@ -452,6 +520,8 @@ export class MidyGMLite {
|
|
|
452
520
|
switch (event.type) {
|
|
453
521
|
case "noteOn": {
|
|
454
522
|
const channel = tmpChannels[event.channel];
|
|
523
|
+
const audioBufferId = this.getAudioBufferId(channel.programNumber, event.noteNumber, event.velocity);
|
|
524
|
+
this.audioBufferCounter.set(audioBufferId, (this.audioBufferCounter.get(audioBufferId) ?? 0) + 1);
|
|
455
525
|
if (channel.programNumber < 0) {
|
|
456
526
|
instruments.add(`${channel.bank}:0`);
|
|
457
527
|
channel.programNumber = 0;
|
|
@@ -468,6 +538,10 @@ export class MidyGMLite {
|
|
|
468
538
|
timeline.push(event);
|
|
469
539
|
}
|
|
470
540
|
}
|
|
541
|
+
for (const [audioBufferId, count] of this.audioBufferCounter) {
|
|
542
|
+
if (count === 1)
|
|
543
|
+
this.audioBufferCounter.delete(audioBufferId);
|
|
544
|
+
}
|
|
471
545
|
const priority = {
|
|
472
546
|
controller: 0,
|
|
473
547
|
sysEx: 1,
|
|
@@ -558,7 +632,7 @@ export class MidyGMLite {
|
|
|
558
632
|
return this.resumeTime + now - this.startTime - this.startDelay;
|
|
559
633
|
}
|
|
560
634
|
getActiveNotes(channel, time) {
|
|
561
|
-
const activeNotes = new
|
|
635
|
+
const activeNotes = new SparseMap(128);
|
|
562
636
|
channel.scheduledNotes.forEach((noteList) => {
|
|
563
637
|
const activeNote = this.getActiveNote(noteList, time);
|
|
564
638
|
if (activeNote) {
|
|
@@ -595,19 +669,22 @@ export class MidyGMLite {
|
|
|
595
669
|
const pitchWheelSensitivity = channel.state.pitchWheelSensitivity * 12800;
|
|
596
670
|
return pitchWheel * pitchWheelSensitivity;
|
|
597
671
|
}
|
|
598
|
-
|
|
599
|
-
const now = this.audioContext.currentTime;
|
|
672
|
+
updateChannelDetune(channel) {
|
|
600
673
|
channel.scheduledNotes.forEach((noteList) => {
|
|
601
674
|
for (let i = 0; i < noteList.length; i++) {
|
|
602
675
|
const note = noteList[i];
|
|
603
676
|
if (!note)
|
|
604
677
|
continue;
|
|
605
|
-
note
|
|
606
|
-
.cancelScheduledValues(now)
|
|
607
|
-
.setValueAtTime(channel.detune, now);
|
|
678
|
+
this.updateDetune(channel, note);
|
|
608
679
|
}
|
|
609
680
|
});
|
|
610
681
|
}
|
|
682
|
+
updateDetune(channel, note) {
|
|
683
|
+
const now = this.audioContext.currentTime;
|
|
684
|
+
note.bufferSource.detune
|
|
685
|
+
.cancelScheduledValues(now)
|
|
686
|
+
.setValueAtTime(channel.detune, now);
|
|
687
|
+
}
|
|
611
688
|
setVolumeEnvelope(note) {
|
|
612
689
|
const now = this.audioContext.currentTime;
|
|
613
690
|
const { voiceParams, startTime } = note;
|
|
@@ -695,11 +772,31 @@ export class MidyGMLite {
|
|
|
695
772
|
note.modulationLFO.connect(note.volumeDepth);
|
|
696
773
|
note.volumeDepth.connect(note.volumeEnvelopeNode.gain);
|
|
697
774
|
}
|
|
775
|
+
async getAudioBuffer(program, noteNumber, velocity, voiceParams, isSF3) {
|
|
776
|
+
const audioBufferId = this.getAudioBufferId(program, noteNumber, velocity);
|
|
777
|
+
const cache = this.audioBufferCache.get(audioBufferId);
|
|
778
|
+
if (cache) {
|
|
779
|
+
cache.counter += 1;
|
|
780
|
+
if (cache.maxCount <= cache.counter) {
|
|
781
|
+
this.audioBufferCache.delete(audioBufferId);
|
|
782
|
+
}
|
|
783
|
+
return cache.audioBuffer;
|
|
784
|
+
}
|
|
785
|
+
else {
|
|
786
|
+
const maxCount = this.audioBufferCounter.get(audioBufferId) ?? 0;
|
|
787
|
+
const audioBuffer = await this.createNoteBuffer(voiceParams, isSF3);
|
|
788
|
+
const cache = { audioBuffer, maxCount, counter: 1 };
|
|
789
|
+
this.audioBufferCache.set(audioBufferId, cache);
|
|
790
|
+
return audioBuffer;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
698
793
|
async createNote(channel, voice, noteNumber, velocity, startTime, isSF3) {
|
|
699
794
|
const state = channel.state;
|
|
700
|
-
const
|
|
795
|
+
const controllerState = this.getControllerState(channel, noteNumber, velocity);
|
|
796
|
+
const voiceParams = voice.getAllParams(controllerState);
|
|
701
797
|
const note = new Note(noteNumber, velocity, startTime, voice, voiceParams);
|
|
702
|
-
|
|
798
|
+
const audioBuffer = await this.getAudioBuffer(channel.program, noteNumber, velocity, voiceParams, isSF3);
|
|
799
|
+
note.bufferSource = this.createNoteBufferNode(audioBuffer, voiceParams);
|
|
703
800
|
note.volumeEnvelopeNode = new GainNode(this.audioContext);
|
|
704
801
|
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
705
802
|
type: "lowpass",
|
|
@@ -723,10 +820,10 @@ export class MidyGMLite {
|
|
|
723
820
|
if (soundFontIndex === undefined)
|
|
724
821
|
return;
|
|
725
822
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
726
|
-
const isSF3 = soundFont.parsed.info.version.major === 3;
|
|
727
823
|
const voice = soundFont.getVoice(bankNumber, channel.program, noteNumber, velocity);
|
|
728
824
|
if (!voice)
|
|
729
825
|
return;
|
|
826
|
+
const isSF3 = soundFont.parsed.info.version.major === 3;
|
|
730
827
|
const note = await this.createNote(channel, voice, noteNumber, velocity, startTime, isSF3);
|
|
731
828
|
note.volumeEnvelopeNode.connect(channel.gainL);
|
|
732
829
|
note.volumeEnvelopeNode.connect(channel.gainR);
|
|
@@ -856,7 +953,7 @@ export class MidyGMLite {
|
|
|
856
953
|
const next = (value - 8192) / 8192;
|
|
857
954
|
state.pitchWheel = value / 16383;
|
|
858
955
|
channel.detune += (next - prev) * state.pitchWheelSensitivity * 12800;
|
|
859
|
-
this.
|
|
956
|
+
this.updateChannelDetune(channel);
|
|
860
957
|
this.applyVoiceParams(channel, 14);
|
|
861
958
|
}
|
|
862
959
|
setModLfoToPitch(channel, note) {
|
|
@@ -960,7 +1057,7 @@ export class MidyGMLite {
|
|
|
960
1057
|
if (key in voiceParams)
|
|
961
1058
|
noteVoiceParams[key] = voiceParams[key];
|
|
962
1059
|
}
|
|
963
|
-
this.setFilterEnvelope(
|
|
1060
|
+
this.setFilterEnvelope(note);
|
|
964
1061
|
this.setPitchEnvelope(note);
|
|
965
1062
|
}
|
|
966
1063
|
else if (volumeEnvelopeKeySet.has(key)) {
|
|
@@ -1000,7 +1097,7 @@ export class MidyGMLite {
|
|
|
1000
1097
|
if (handler) {
|
|
1001
1098
|
handler.call(this, channelNumber, value);
|
|
1002
1099
|
const channel = this.channels[channelNumber];
|
|
1003
|
-
this.applyVoiceParams(channel,
|
|
1100
|
+
this.applyVoiceParams(channel, controllerType + 128);
|
|
1004
1101
|
}
|
|
1005
1102
|
else {
|
|
1006
1103
|
console.warn(`Unsupported Control change: controllerType=${controllerType} value=${value}`);
|
|
@@ -1118,12 +1215,14 @@ export class MidyGMLite {
|
|
|
1118
1215
|
const pitchBendRange = channel.dataMSB + channel.dataLSB / 100;
|
|
1119
1216
|
this.setPitchBendRange(channelNumber, pitchBendRange);
|
|
1120
1217
|
}
|
|
1121
|
-
setPitchBendRange(channelNumber,
|
|
1218
|
+
setPitchBendRange(channelNumber, value) {
|
|
1122
1219
|
const channel = this.channels[channelNumber];
|
|
1123
1220
|
const state = channel.state;
|
|
1124
|
-
|
|
1125
|
-
const
|
|
1126
|
-
|
|
1221
|
+
const prev = state.pitchWheelSensitivity;
|
|
1222
|
+
const next = value / 128;
|
|
1223
|
+
state.pitchWheelSensitivity = next;
|
|
1224
|
+
channel.detune += (state.pitchWheel * 2 - 1) * (next - prev) * 12800;
|
|
1225
|
+
this.updateChannelDetune(channel);
|
|
1127
1226
|
this.applyVoiceParams(channel, 16);
|
|
1128
1227
|
}
|
|
1129
1228
|
allSoundOff(channelNumber) {
|
|
@@ -1140,7 +1239,7 @@ export class MidyGMLite {
|
|
|
1140
1239
|
const state = channel.state;
|
|
1141
1240
|
for (let i = 0; i < stateTypes.length; i++) {
|
|
1142
1241
|
const type = stateTypes[i];
|
|
1143
|
-
state[type] = defaultControllerState[type];
|
|
1242
|
+
state[type] = defaultControllerState[type].defaultValue;
|
|
1144
1243
|
}
|
|
1145
1244
|
const settingTypes = [
|
|
1146
1245
|
"rpnMSB",
|
package/esm/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/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":"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"}
|