@marmooo/midy 0.3.8 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/esm/midy-GM1.d.ts +8 -26
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +140 -80
- package/esm/midy-GM2.d.ts +8 -31
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +155 -95
- package/esm/midy-GMLite.d.ts +8 -26
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +134 -75
- package/esm/midy.d.ts +15 -37
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +228 -111
- package/package.json +2 -2
- package/script/midy-GM1.d.ts +8 -26
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +140 -80
- package/script/midy-GM2.d.ts +8 -31
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +155 -95
- package/script/midy-GMLite.d.ts +8 -26
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +134 -75
- package/script/midy.d.ts +15 -37
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +228 -111
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@marmooo/midy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "A MIDI player/synthesizer written in JavaScript that supports GM-Lite/GM1 and SF2/SF3.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"test": "node test_runner.js"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@marmooo/soundfont-parser": "^0.1.
|
|
25
|
+
"@marmooo/soundfont-parser": "^0.1.5",
|
|
26
26
|
"midi-file": "^1.2.4"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
package/script/midy-GM1.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export class MidyGM1 {
|
|
|
25
25
|
soundFontTable: never[][];
|
|
26
26
|
voiceCounter: Map<any, any>;
|
|
27
27
|
voiceCache: Map<any, any>;
|
|
28
|
+
realtimeVoiceCache: Map<any, any>;
|
|
28
29
|
isPlaying: boolean;
|
|
29
30
|
isPausing: boolean;
|
|
30
31
|
isPaused: boolean;
|
|
@@ -104,21 +105,20 @@ export class MidyGM1 {
|
|
|
104
105
|
clampCutoffFrequency(frequency: any): number;
|
|
105
106
|
setFilterEnvelope(note: any, scheduleTime: any): void;
|
|
106
107
|
startModulation(channel: any, note: any, scheduleTime: any): void;
|
|
107
|
-
getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any): Promise<any>;
|
|
108
|
-
|
|
108
|
+
getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any, realtime: any): Promise<any>;
|
|
109
|
+
setNoteAudioNode(channel: any, note: any, realtime: any): Promise<any>;
|
|
109
110
|
handleExclusiveClass(note: any, channelNumber: any, startTime: any): void;
|
|
110
|
-
|
|
111
|
-
noteOn(channelNumber: any, noteNumber: any, velocity: any,
|
|
111
|
+
setNoteRouting(channelNumber: any, note: any, startTime: any): void;
|
|
112
|
+
noteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
112
113
|
disconnectNote(note: any): void;
|
|
113
114
|
releaseNote(channel: any, note: any, endTime: any): Promise<any>;
|
|
114
|
-
|
|
115
|
+
noteOff(channelNumber: any, noteNumber: any, velocity: any, endTime: any, force: any): Promise<any> | undefined;
|
|
115
116
|
setNoteIndex(channel: any, index: any): void;
|
|
116
117
|
findNoteOffIndex(channel: any, noteNumber: any): any;
|
|
117
|
-
|
|
118
|
-
releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
|
|
118
|
+
releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
|
|
119
119
|
createMessageHandlers(): any[];
|
|
120
120
|
handleMessage(data: any, scheduleTime: any): void;
|
|
121
|
-
handleChannelMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<
|
|
121
|
+
handleChannelMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<any>;
|
|
122
122
|
setProgramChange(channelNumber: any, programNumber: any, _scheduleTime: any): void;
|
|
123
123
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any, scheduleTime: any): void;
|
|
124
124
|
setPitchBend(channelNumber: any, value: any, scheduleTime: any): void;
|
|
@@ -179,22 +179,4 @@ export class MidyGM1 {
|
|
|
179
179
|
handleSysEx(data: any, scheduleTime: any): void;
|
|
180
180
|
scheduleTask(callback: any, scheduleTime: any): Promise<any>;
|
|
181
181
|
}
|
|
182
|
-
declare class Note {
|
|
183
|
-
constructor(noteNumber: any, velocity: any, startTime: any, voice: any, voiceParams: any);
|
|
184
|
-
index: number;
|
|
185
|
-
ending: boolean;
|
|
186
|
-
bufferSource: any;
|
|
187
|
-
filterNode: any;
|
|
188
|
-
filterDepth: any;
|
|
189
|
-
volumeEnvelopeNode: any;
|
|
190
|
-
volumeDepth: any;
|
|
191
|
-
modulationLFO: any;
|
|
192
|
-
modulationDepth: any;
|
|
193
|
-
noteNumber: any;
|
|
194
|
-
velocity: any;
|
|
195
|
-
startTime: any;
|
|
196
|
-
voice: any;
|
|
197
|
-
voiceParams: any;
|
|
198
|
-
}
|
|
199
|
-
export {};
|
|
200
182
|
//# sourceMappingURL=midy-GM1.d.ts.map
|
package/script/midy-GM1.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AA6FA;IA0BE;;;;;;;;;;;MAWE;IAEF,+BAeC;IArDD,aAAa;IACb,oBAAiB;IACjB,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,0BAAuD;IACvD,4BAAyB;IACzB,0BAAuB;IACvB,kCAA+B;IAC/B,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,iBAAY;IACZ,gBAAc;IACd,oBAAkB;IAClB,sBAAwB;IACxB,2BAAqC;IAgBnC,kBAAgC;IAChC,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF,uBAAmD;IACnD;;;;;;;;;;;MAA2D;IAC3D,6BAA+D;IAC/D,gBAAiD;IAMnD,mCASC;IAED,2DAYC;IAED,yCAmBC;IAED,oCASC;IAED,sBAoCC;IAED,8DAWC;IAED;;;;MAeC;IAED,yCAaC;IAED,kDASC;IAED,4DASC;IAED,yEAoDC;IAED,mCAOC;IAED,uBASC;IAED,yDA2BC;IAED,2BA8CC;IAED,uDAEC;IAED,wDAEC;IAED,qCAKC;IAED;;;MAwDC;IAED,kGAeC;IAED,mGAeC;IAED,wEAMC;IAED,uBAMC;IAED,sBAKC;IAED,uBAQC;IAED,wBAKC;IAED,0BAKC;IAED,wBAOC;IAED,sBAIC;IAED,yDAQC;IAED,yEASC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,qCAMC;IAED,2DAIC;IAED,+DAIC;IAED,sDAeC;IAED,qDAoBC;IAED,6CAIC;IAED,sDAsBC;IAED,kEAoBC;IAED,4GAkCC;IAED,uEAwCC;IAED,0EAiBC;IAED,oEASC;IAED,0FAwBC;IAED,gCASC;IAED,iEAqBC;IAED,gHAqBC;IAED,6CAUC;IAED,qDAUC;IAED,4GAeC;IAED,+BAmBC;IAED,kDAOC;IAED,sGA2BC;IAED,mFAGC;IAED,wFAGC;IAED,sEAUC;IAED,mEAYC;IAED,wDAKC;IAED,sDAOC;IAED,mDAMC;IAED,kDAKC;IAED;;;;;;;;;;;MAiCC;IAED,oFAMC;IAED,6EA2BC;IAED,qCAeC;IAED,+FAWC;IAED,wDAUC;IAED,iFAKC;IAED,oEAKC;IAED;;;MAMC;IAED,8DAKC;IAED,4EAKC;IAED,sEAGC;IAED,2DAUC;IAED,yEAWC;IAED,kFAeC;IAED,2DAMC;IAED,uDAkBC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAUC;IAED,iEAMC;IAED,uEAQC;IAED,mEAKC;IAED,yEAQC;IAED,gFAGC;IAED,6CAqBC;IAGD,8EAgCC;IAED,gFAGC;IAED,+EAgBC;IAED,qCASC;IAED,4EAaC;IAED,4DAGC;IAED,qDAKC;IAED,gDAYC;IAGD,6DAgBC;CACF"}
|
package/script/midy-GM1.js
CHANGED
|
@@ -4,7 +4,19 @@ exports.MidyGM1 = void 0;
|
|
|
4
4
|
const midi_file_1 = require("midi-file");
|
|
5
5
|
const soundfont_parser_1 = require("@marmooo/soundfont-parser");
|
|
6
6
|
class Note {
|
|
7
|
-
constructor(noteNumber, velocity, startTime
|
|
7
|
+
constructor(noteNumber, velocity, startTime) {
|
|
8
|
+
Object.defineProperty(this, "voice", {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
configurable: true,
|
|
11
|
+
writable: true,
|
|
12
|
+
value: void 0
|
|
13
|
+
});
|
|
14
|
+
Object.defineProperty(this, "voiceParams", {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
configurable: true,
|
|
17
|
+
writable: true,
|
|
18
|
+
value: void 0
|
|
19
|
+
});
|
|
8
20
|
Object.defineProperty(this, "index", {
|
|
9
21
|
enumerable: true,
|
|
10
22
|
configurable: true,
|
|
@@ -17,6 +29,12 @@ class Note {
|
|
|
17
29
|
writable: true,
|
|
18
30
|
value: false
|
|
19
31
|
});
|
|
32
|
+
Object.defineProperty(this, "pending", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
writable: true,
|
|
36
|
+
value: true
|
|
37
|
+
});
|
|
20
38
|
Object.defineProperty(this, "bufferSource", {
|
|
21
39
|
enumerable: true,
|
|
22
40
|
configurable: true,
|
|
@@ -62,8 +80,6 @@ class Note {
|
|
|
62
80
|
this.noteNumber = noteNumber;
|
|
63
81
|
this.velocity = velocity;
|
|
64
82
|
this.startTime = startTime;
|
|
65
|
-
this.voice = voice;
|
|
66
|
-
this.voiceParams = voiceParams;
|
|
67
83
|
}
|
|
68
84
|
}
|
|
69
85
|
// normalized to 0-1 for use with the SF2 modulator model
|
|
@@ -73,11 +89,11 @@ const defaultControllerState = {
|
|
|
73
89
|
pitchWheel: { type: 14, defaultValue: 8192 / 16383 },
|
|
74
90
|
pitchWheelSensitivity: { type: 16, defaultValue: 2 / 128 },
|
|
75
91
|
link: { type: 127, defaultValue: 0 },
|
|
76
|
-
|
|
92
|
+
modulationDepthMSB: { type: 128 + 1, defaultValue: 0 },
|
|
77
93
|
// dataMSB: { type: 128 + 6, defaultValue: 0, },
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
94
|
+
volumeMSB: { type: 128 + 7, defaultValue: 100 / 127 },
|
|
95
|
+
panMSB: { type: 128 + 10, defaultValue: 64 / 127 },
|
|
96
|
+
expressionMSB: { type: 128 + 11, defaultValue: 1 },
|
|
81
97
|
// dataLSB: { type: 128 + 38, defaultValue: 0, },
|
|
82
98
|
sustainPedal: { type: 128 + 64, defaultValue: 0 },
|
|
83
99
|
// rpnLSB: { type: 128 + 100, defaultValue: 127 },
|
|
@@ -217,6 +233,12 @@ class MidyGM1 {
|
|
|
217
233
|
writable: true,
|
|
218
234
|
value: new Map()
|
|
219
235
|
});
|
|
236
|
+
Object.defineProperty(this, "realtimeVoiceCache", {
|
|
237
|
+
enumerable: true,
|
|
238
|
+
configurable: true,
|
|
239
|
+
writable: true,
|
|
240
|
+
value: new Map()
|
|
241
|
+
});
|
|
220
242
|
Object.defineProperty(this, "isPlaying", {
|
|
221
243
|
enumerable: true,
|
|
222
244
|
configurable: true,
|
|
@@ -391,7 +413,7 @@ class MidyGM1 {
|
|
|
391
413
|
return soundFontIndex * (2 ** 32) + (instrument << 16) + sampleID;
|
|
392
414
|
}
|
|
393
415
|
createChannelAudioNodes(audioContext) {
|
|
394
|
-
const { gainLeft, gainRight } = this.panToGain(defaultControllerState.
|
|
416
|
+
const { gainLeft, gainRight } = this.panToGain(defaultControllerState.panMSB.defaultValue);
|
|
395
417
|
const gainL = new GainNode(audioContext, { gain: gainLeft });
|
|
396
418
|
const gainR = new GainNode(audioContext, { gain: gainRight });
|
|
397
419
|
const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
|
|
@@ -419,10 +441,9 @@ class MidyGM1 {
|
|
|
419
441
|
return channels;
|
|
420
442
|
}
|
|
421
443
|
async createAudioBuffer(voiceParams) {
|
|
422
|
-
const sample = voiceParams
|
|
423
|
-
const
|
|
424
|
-
const
|
|
425
|
-
const audioBuffer = await sample.toAudioBuffer(this.audioContext, sampleStart, sampleEnd);
|
|
444
|
+
const { sample, start, end } = voiceParams;
|
|
445
|
+
const sampleEnd = sample.data.length + end;
|
|
446
|
+
const audioBuffer = await sample.toAudioBuffer(this.audioContext, start, sampleEnd);
|
|
426
447
|
return audioBuffer;
|
|
427
448
|
}
|
|
428
449
|
createBufferSource(voiceParams, audioBuffer) {
|
|
@@ -447,12 +468,10 @@ class MidyGM1 {
|
|
|
447
468
|
const startTime = event.startTime + schedulingOffset;
|
|
448
469
|
switch (event.type) {
|
|
449
470
|
case "noteOn":
|
|
450
|
-
await this.
|
|
471
|
+
await this.noteOn(event.channel, event.noteNumber, event.velocity, startTime);
|
|
451
472
|
break;
|
|
452
473
|
case "noteOff": {
|
|
453
|
-
|
|
454
|
-
if (notePromise)
|
|
455
|
-
this.notePromises.push(notePromise);
|
|
474
|
+
this.noteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
|
|
456
475
|
break;
|
|
457
476
|
}
|
|
458
477
|
case "controller":
|
|
@@ -483,6 +502,7 @@ class MidyGM1 {
|
|
|
483
502
|
this.exclusiveClassNotes.fill(undefined);
|
|
484
503
|
this.drumExclusiveClassNotes.fill(undefined);
|
|
485
504
|
this.voiceCache.clear();
|
|
505
|
+
this.realtimeVoiceCache.clear();
|
|
486
506
|
for (let i = 0; i < this.channels.length; i++) {
|
|
487
507
|
this.channels[i].scheduledNotes = [];
|
|
488
508
|
this.resetChannelStates(i);
|
|
@@ -520,7 +540,6 @@ class MidyGM1 {
|
|
|
520
540
|
this.notePromises = [];
|
|
521
541
|
while (queueIndex < this.timeline.length) {
|
|
522
542
|
const now = this.audioContext.currentTime;
|
|
523
|
-
queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
|
|
524
543
|
if (this.isPausing) {
|
|
525
544
|
await this.stopNotes(0, true, now);
|
|
526
545
|
await this.audioContext.suspend();
|
|
@@ -542,9 +561,16 @@ class MidyGM1 {
|
|
|
542
561
|
this.isSeeking = false;
|
|
543
562
|
continue;
|
|
544
563
|
}
|
|
564
|
+
queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
|
|
545
565
|
const waitTime = now + this.noteCheckInterval;
|
|
546
566
|
await this.scheduleTask(() => { }, waitTime);
|
|
547
567
|
}
|
|
568
|
+
if (this.timeline.length <= queueIndex) {
|
|
569
|
+
const now = this.audioContext.currentTime;
|
|
570
|
+
await this.stopNotes(0, true, now);
|
|
571
|
+
await this.audioContext.suspend();
|
|
572
|
+
finished = true;
|
|
573
|
+
}
|
|
548
574
|
if (finished) {
|
|
549
575
|
this.notePromises = [];
|
|
550
576
|
this.resetAllStates();
|
|
@@ -619,7 +645,7 @@ class MidyGM1 {
|
|
|
619
645
|
const channel = this.channels[channelNumber];
|
|
620
646
|
const promises = [];
|
|
621
647
|
this.processActiveNotes(channel, scheduleTime, (note) => {
|
|
622
|
-
const promise = this.
|
|
648
|
+
const promise = this.noteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
|
|
623
649
|
this.notePromises.push(promise);
|
|
624
650
|
promises.push(promise);
|
|
625
651
|
});
|
|
@@ -629,7 +655,7 @@ class MidyGM1 {
|
|
|
629
655
|
const channel = this.channels[channelNumber];
|
|
630
656
|
const promises = [];
|
|
631
657
|
this.processScheduledNotes(channel, (note) => {
|
|
632
|
-
const promise = this.
|
|
658
|
+
const promise = this.noteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
|
|
633
659
|
this.notePromises.push(promise);
|
|
634
660
|
promises.push(promise);
|
|
635
661
|
});
|
|
@@ -662,7 +688,7 @@ class MidyGM1 {
|
|
|
662
688
|
if (!this.isPlaying || this.isPaused)
|
|
663
689
|
return;
|
|
664
690
|
const now = this.audioContext.currentTime;
|
|
665
|
-
this.resumeTime
|
|
691
|
+
this.resumeTime = now - this.startTime - this.startDelay;
|
|
666
692
|
this.isPausing = true;
|
|
667
693
|
await this.playPromise;
|
|
668
694
|
this.isPausing = false;
|
|
@@ -688,11 +714,13 @@ class MidyGM1 {
|
|
|
688
714
|
if (totalTime < event.startTime)
|
|
689
715
|
totalTime = event.startTime;
|
|
690
716
|
}
|
|
691
|
-
return totalTime;
|
|
717
|
+
return totalTime + this.startDelay;
|
|
692
718
|
}
|
|
693
719
|
currentTime() {
|
|
720
|
+
if (!this.isPlaying)
|
|
721
|
+
return this.resumeTime;
|
|
694
722
|
const now = this.audioContext.currentTime;
|
|
695
|
-
return
|
|
723
|
+
return now + this.resumeTime - this.startTime;
|
|
696
724
|
}
|
|
697
725
|
processScheduledNotes(channel, callback) {
|
|
698
726
|
const scheduledNotes = channel.scheduledNotes;
|
|
@@ -831,31 +859,42 @@ class MidyGM1 {
|
|
|
831
859
|
note.modulationLFO.connect(note.volumeDepth);
|
|
832
860
|
note.volumeDepth.connect(note.volumeEnvelopeNode.gain);
|
|
833
861
|
}
|
|
834
|
-
async getAudioBuffer(channel, noteNumber, velocity, voiceParams) {
|
|
862
|
+
async getAudioBuffer(channel, noteNumber, velocity, voiceParams, realtime) {
|
|
835
863
|
const audioBufferId = this.getVoiceId(channel, noteNumber, velocity);
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
this.voiceCache.delete(audioBufferId);
|
|
841
|
-
}
|
|
842
|
-
return cache.audioBuffer;
|
|
843
|
-
}
|
|
844
|
-
else {
|
|
845
|
-
const maxCount = this.voiceCounter.get(audioBufferId) ?? 0;
|
|
864
|
+
if (realtime) {
|
|
865
|
+
const cachedAudioBuffer = this.realtimeVoiceCache.get(audioBufferId);
|
|
866
|
+
if (cachedAudioBuffer)
|
|
867
|
+
return cachedAudioBuffer;
|
|
846
868
|
const audioBuffer = await this.createAudioBuffer(voiceParams);
|
|
847
|
-
|
|
848
|
-
this.voiceCache.set(audioBufferId, cache);
|
|
869
|
+
this.realtimeVoiceCache.set(audioBufferId, audioBuffer);
|
|
849
870
|
return audioBuffer;
|
|
850
871
|
}
|
|
872
|
+
else {
|
|
873
|
+
const cache = this.voiceCache.get(audioBufferId);
|
|
874
|
+
if (cache) {
|
|
875
|
+
cache.counter += 1;
|
|
876
|
+
if (cache.maxCount <= cache.counter) {
|
|
877
|
+
this.voiceCache.delete(audioBufferId);
|
|
878
|
+
}
|
|
879
|
+
return cache.audioBuffer;
|
|
880
|
+
}
|
|
881
|
+
else {
|
|
882
|
+
const maxCount = this.voiceCounter.get(audioBufferId) ?? 0;
|
|
883
|
+
const audioBuffer = await this.createAudioBuffer(voiceParams);
|
|
884
|
+
const cache = { audioBuffer, maxCount, counter: 1 };
|
|
885
|
+
this.voiceCache.set(audioBufferId, cache);
|
|
886
|
+
return audioBuffer;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
851
889
|
}
|
|
852
|
-
async
|
|
890
|
+
async setNoteAudioNode(channel, note, realtime) {
|
|
853
891
|
const now = this.audioContext.currentTime;
|
|
892
|
+
const { noteNumber, velocity, startTime } = note;
|
|
854
893
|
const state = channel.state;
|
|
855
894
|
const controllerState = this.getControllerState(channel, noteNumber, velocity);
|
|
856
|
-
const voiceParams = voice.getAllParams(controllerState);
|
|
857
|
-
|
|
858
|
-
const audioBuffer = await this.getAudioBuffer(channel, noteNumber, velocity, voiceParams);
|
|
895
|
+
const voiceParams = note.voice.getAllParams(controllerState);
|
|
896
|
+
note.voiceParams = voiceParams;
|
|
897
|
+
const audioBuffer = await this.getAudioBuffer(channel, noteNumber, velocity, voiceParams, realtime);
|
|
859
898
|
note.bufferSource = this.createBufferSource(voiceParams, audioBuffer);
|
|
860
899
|
note.volumeEnvelopeNode = new GainNode(this.audioContext);
|
|
861
900
|
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
@@ -871,7 +910,13 @@ class MidyGM1 {
|
|
|
871
910
|
}
|
|
872
911
|
note.bufferSource.connect(note.filterNode);
|
|
873
912
|
note.filterNode.connect(note.volumeEnvelopeNode);
|
|
874
|
-
|
|
913
|
+
if (voiceParams.sample.type === "compressed") {
|
|
914
|
+
const offset = voiceParams.start / audioBuffer.sampleRate;
|
|
915
|
+
note.bufferSource.start(startTime, offset);
|
|
916
|
+
}
|
|
917
|
+
else {
|
|
918
|
+
note.bufferSource.start(startTime);
|
|
919
|
+
}
|
|
875
920
|
return note;
|
|
876
921
|
}
|
|
877
922
|
handleExclusiveClass(note, channelNumber, startTime) {
|
|
@@ -882,14 +927,31 @@ class MidyGM1 {
|
|
|
882
927
|
if (prev) {
|
|
883
928
|
const [prevNote, prevChannelNumber] = prev;
|
|
884
929
|
if (prevNote && !prevNote.ending) {
|
|
885
|
-
this.
|
|
930
|
+
this.noteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
|
|
886
931
|
startTime, true);
|
|
887
932
|
}
|
|
888
933
|
}
|
|
889
934
|
this.exclusiveClassNotes[exclusiveClass] = [note, channelNumber];
|
|
890
935
|
}
|
|
891
|
-
|
|
936
|
+
setNoteRouting(channelNumber, note, startTime) {
|
|
937
|
+
const channel = this.channels[channelNumber];
|
|
938
|
+
const volumeEnvelopeNode = note.volumeEnvelopeNode;
|
|
939
|
+
volumeEnvelopeNode.connect(channel.gainL);
|
|
940
|
+
volumeEnvelopeNode.connect(channel.gainR);
|
|
941
|
+
if (0.5 <= channel.state.sustainPedal) {
|
|
942
|
+
channel.sustainNotes.push(note);
|
|
943
|
+
}
|
|
944
|
+
this.handleExclusiveClass(note, channelNumber, startTime);
|
|
945
|
+
}
|
|
946
|
+
async noteOn(channelNumber, noteNumber, velocity, startTime) {
|
|
892
947
|
const channel = this.channels[channelNumber];
|
|
948
|
+
const realtime = startTime === undefined;
|
|
949
|
+
if (realtime)
|
|
950
|
+
startTime = this.audioContext.currentTime;
|
|
951
|
+
const note = new Note(noteNumber, velocity, startTime);
|
|
952
|
+
const scheduledNotes = channel.scheduledNotes;
|
|
953
|
+
note.index = scheduledNotes.length;
|
|
954
|
+
scheduledNotes.push(note);
|
|
893
955
|
const programNumber = channel.programNumber;
|
|
894
956
|
const bankTable = this.soundFontTable[programNumber];
|
|
895
957
|
if (!bankTable)
|
|
@@ -899,23 +961,16 @@ class MidyGM1 {
|
|
|
899
961
|
if (soundFontIndex === undefined)
|
|
900
962
|
return;
|
|
901
963
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
902
|
-
|
|
903
|
-
if (!voice)
|
|
964
|
+
note.voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
|
|
965
|
+
if (!note.voice)
|
|
904
966
|
return;
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
note.
|
|
908
|
-
|
|
909
|
-
|
|
967
|
+
await this.setNoteAudioNode(channel, note, realtime);
|
|
968
|
+
this.setNoteRouting(channelNumber, note, startTime);
|
|
969
|
+
note.pending = false;
|
|
970
|
+
const off = note.offEvent;
|
|
971
|
+
if (off) {
|
|
972
|
+
this.noteOff(channelNumber, noteNumber, off.velocity, off.startTime);
|
|
910
973
|
}
|
|
911
|
-
this.handleExclusiveClass(note, channelNumber, startTime);
|
|
912
|
-
const scheduledNotes = channel.scheduledNotes;
|
|
913
|
-
note.index = scheduledNotes.length;
|
|
914
|
-
scheduledNotes.push(note);
|
|
915
|
-
}
|
|
916
|
-
noteOn(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
917
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
918
|
-
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime, undefined);
|
|
919
974
|
}
|
|
920
975
|
disconnectNote(note) {
|
|
921
976
|
note.bufferSource.disconnect();
|
|
@@ -928,6 +983,7 @@ class MidyGM1 {
|
|
|
928
983
|
}
|
|
929
984
|
}
|
|
930
985
|
releaseNote(channel, note, endTime) {
|
|
986
|
+
endTime ??= this.audioContext.currentTime;
|
|
931
987
|
const volRelease = endTime + note.voiceParams.volRelease;
|
|
932
988
|
const modRelease = endTime + note.voiceParams.modRelease;
|
|
933
989
|
const stopTime = Math.min(volRelease, modRelease);
|
|
@@ -948,7 +1004,7 @@ class MidyGM1 {
|
|
|
948
1004
|
}, stopTime);
|
|
949
1005
|
});
|
|
950
1006
|
}
|
|
951
|
-
|
|
1007
|
+
noteOff(channelNumber, noteNumber, velocity, endTime, force) {
|
|
952
1008
|
const channel = this.channels[channelNumber];
|
|
953
1009
|
if (!force && 0.5 <= channel.state.sustainPedal)
|
|
954
1010
|
return;
|
|
@@ -956,9 +1012,15 @@ class MidyGM1 {
|
|
|
956
1012
|
if (index < 0)
|
|
957
1013
|
return;
|
|
958
1014
|
const note = channel.scheduledNotes[index];
|
|
1015
|
+
if (note.pending) {
|
|
1016
|
+
note.offEvent = { velocity, startTime: endTime };
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
959
1019
|
note.ending = true;
|
|
960
1020
|
this.setNoteIndex(channel, index);
|
|
961
|
-
this.releaseNote(channel, note, endTime);
|
|
1021
|
+
const promise = this.releaseNote(channel, note, endTime);
|
|
1022
|
+
this.notePromises.push(promise);
|
|
1023
|
+
return promise;
|
|
962
1024
|
}
|
|
963
1025
|
setNoteIndex(channel, index) {
|
|
964
1026
|
let allEnds = true;
|
|
@@ -986,16 +1048,12 @@ class MidyGM1 {
|
|
|
986
1048
|
}
|
|
987
1049
|
return -1;
|
|
988
1050
|
}
|
|
989
|
-
noteOff(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
990
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
991
|
-
return this.scheduleNoteOff(channelNumber, noteNumber, velocity, scheduleTime, false);
|
|
992
|
-
}
|
|
993
1051
|
releaseSustainPedal(channelNumber, halfVelocity, scheduleTime) {
|
|
994
1052
|
const velocity = halfVelocity * 2;
|
|
995
1053
|
const channel = this.channels[channelNumber];
|
|
996
1054
|
const promises = [];
|
|
997
1055
|
for (let i = 0; i < channel.sustainNotes.length; i++) {
|
|
998
|
-
const promise = this.
|
|
1056
|
+
const promise = this.noteOff(channelNumber, channel.sustainNotes[i].noteNumber, velocity, scheduleTime);
|
|
999
1057
|
promises.push(promise);
|
|
1000
1058
|
}
|
|
1001
1059
|
channel.sustainNotes = [];
|
|
@@ -1060,11 +1118,12 @@ class MidyGM1 {
|
|
|
1060
1118
|
setModLfoToPitch(channel, note, scheduleTime) {
|
|
1061
1119
|
if (note.modulationDepth) {
|
|
1062
1120
|
const modLfoToPitch = note.voiceParams.modLfoToPitch;
|
|
1063
|
-
const baseDepth = Math.abs(modLfoToPitch) +
|
|
1064
|
-
|
|
1121
|
+
const baseDepth = Math.abs(modLfoToPitch) +
|
|
1122
|
+
channel.state.modulationDepthMSB;
|
|
1123
|
+
const depth = baseDepth * Math.sign(modLfoToPitch);
|
|
1065
1124
|
note.modulationDepth.gain
|
|
1066
1125
|
.cancelScheduledValues(scheduleTime)
|
|
1067
|
-
.setValueAtTime(
|
|
1126
|
+
.setValueAtTime(depth, scheduleTime);
|
|
1068
1127
|
}
|
|
1069
1128
|
else {
|
|
1070
1129
|
this.startModulation(channel, note, scheduleTime);
|
|
@@ -1101,18 +1160,18 @@ class MidyGM1 {
|
|
|
1101
1160
|
createVoiceParamsHandlers() {
|
|
1102
1161
|
return {
|
|
1103
1162
|
modLfoToPitch: (channel, note, scheduleTime) => {
|
|
1104
|
-
if (0 < channel.state.
|
|
1163
|
+
if (0 < channel.state.modulationDepthMSB) {
|
|
1105
1164
|
this.setModLfoToPitch(channel, note, scheduleTime);
|
|
1106
1165
|
}
|
|
1107
1166
|
},
|
|
1108
1167
|
vibLfoToPitch: (_channel, _note, _scheduleTime) => { },
|
|
1109
1168
|
modLfoToFilterFc: (channel, note, scheduleTime) => {
|
|
1110
|
-
if (0 < channel.state.
|
|
1169
|
+
if (0 < channel.state.modulationDepthMSB) {
|
|
1111
1170
|
this.setModLfoToFilterFc(note, scheduleTime);
|
|
1112
1171
|
}
|
|
1113
1172
|
},
|
|
1114
1173
|
modLfoToVolume: (channel, note, scheduleTime) => {
|
|
1115
|
-
if (0 < channel.state.
|
|
1174
|
+
if (0 < channel.state.modulationDepthMSB) {
|
|
1116
1175
|
this.setModLfoToVolume(note, scheduleTime);
|
|
1117
1176
|
}
|
|
1118
1177
|
},
|
|
@@ -1124,7 +1183,7 @@ class MidyGM1 {
|
|
|
1124
1183
|
}
|
|
1125
1184
|
},
|
|
1126
1185
|
freqModLFO: (_channel, note, scheduleTime) => {
|
|
1127
|
-
if (0 < channel.state.
|
|
1186
|
+
if (0 < channel.state.modulationDepthMSB) {
|
|
1128
1187
|
this.setFreqModLFO(note, scheduleTime);
|
|
1129
1188
|
}
|
|
1130
1189
|
},
|
|
@@ -1199,7 +1258,8 @@ class MidyGM1 {
|
|
|
1199
1258
|
}
|
|
1200
1259
|
}
|
|
1201
1260
|
updateModulation(channel, scheduleTime) {
|
|
1202
|
-
const depth = channel.state.
|
|
1261
|
+
const depth = channel.state.modulationDepthMSB *
|
|
1262
|
+
channel.modulationDepthRange;
|
|
1203
1263
|
this.processScheduledNotes(channel, (note) => {
|
|
1204
1264
|
if (note.modulationDepth) {
|
|
1205
1265
|
note.modulationDepth.gain.setValueAtTime(depth, scheduleTime);
|
|
@@ -1212,13 +1272,13 @@ class MidyGM1 {
|
|
|
1212
1272
|
setModulationDepth(channelNumber, modulation, scheduleTime) {
|
|
1213
1273
|
const channel = this.channels[channelNumber];
|
|
1214
1274
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1215
|
-
channel.state.
|
|
1275
|
+
channel.state.modulationDepthMSB = modulation / 127;
|
|
1216
1276
|
this.updateModulation(channel, scheduleTime);
|
|
1217
1277
|
}
|
|
1218
1278
|
setVolume(channelNumber, volume, scheduleTime) {
|
|
1219
1279
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1220
1280
|
const channel = this.channels[channelNumber];
|
|
1221
|
-
channel.state.
|
|
1281
|
+
channel.state.volumeMSB = volume / 127;
|
|
1222
1282
|
this.updateChannelVolume(channel, scheduleTime);
|
|
1223
1283
|
}
|
|
1224
1284
|
panToGain(pan) {
|
|
@@ -1231,13 +1291,13 @@ class MidyGM1 {
|
|
|
1231
1291
|
setPan(channelNumber, pan, scheduleTime) {
|
|
1232
1292
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1233
1293
|
const channel = this.channels[channelNumber];
|
|
1234
|
-
channel.state.
|
|
1294
|
+
channel.state.panMSB = pan / 127;
|
|
1235
1295
|
this.updateChannelVolume(channel, scheduleTime);
|
|
1236
1296
|
}
|
|
1237
1297
|
setExpression(channelNumber, expression, scheduleTime) {
|
|
1238
1298
|
scheduleTime ??= this.audioContext.currentTime;
|
|
1239
1299
|
const channel = this.channels[channelNumber];
|
|
1240
|
-
channel.state.
|
|
1300
|
+
channel.state.expressionMSB = expression / 127;
|
|
1241
1301
|
this.updateChannelVolume(channel, scheduleTime);
|
|
1242
1302
|
}
|
|
1243
1303
|
dataEntryLSB(channelNumber, value, scheduleTime) {
|
|
@@ -1246,8 +1306,8 @@ class MidyGM1 {
|
|
|
1246
1306
|
}
|
|
1247
1307
|
updateChannelVolume(channel, scheduleTime) {
|
|
1248
1308
|
const state = channel.state;
|
|
1249
|
-
const volume = state.
|
|
1250
|
-
const { gainLeft, gainRight } = this.panToGain(state.
|
|
1309
|
+
const volume = state.volumeMSB * state.expressionMSB;
|
|
1310
|
+
const { gainLeft, gainRight } = this.panToGain(state.panMSB);
|
|
1251
1311
|
channel.gainL.gain
|
|
1252
1312
|
.cancelScheduledValues(scheduleTime)
|
|
1253
1313
|
.setValueAtTime(volume * gainLeft, scheduleTime);
|
|
@@ -1395,8 +1455,8 @@ class MidyGM1 {
|
|
|
1395
1455
|
resetAllControllers(channelNumber, _value, scheduleTime) {
|
|
1396
1456
|
const keys = [
|
|
1397
1457
|
"pitchWheel",
|
|
1398
|
-
"
|
|
1399
|
-
"
|
|
1458
|
+
"expressionMSB",
|
|
1459
|
+
"modulationDepthMSB",
|
|
1400
1460
|
"sustainPedal",
|
|
1401
1461
|
];
|
|
1402
1462
|
const channel = this.channels[channelNumber];
|
package/script/midy-GM2.d.ts
CHANGED
|
@@ -44,6 +44,7 @@ export class MidyGM2 {
|
|
|
44
44
|
soundFontTable: never[][];
|
|
45
45
|
voiceCounter: Map<any, any>;
|
|
46
46
|
voiceCache: Map<any, any>;
|
|
47
|
+
realtimeVoiceCache: Map<any, any>;
|
|
47
48
|
isPlaying: boolean;
|
|
48
49
|
isPausing: boolean;
|
|
49
50
|
isPaused: boolean;
|
|
@@ -173,20 +174,19 @@ export class MidyGM2 {
|
|
|
173
174
|
setFilterEnvelope(channel: any, note: any, scheduleTime: any): void;
|
|
174
175
|
startModulation(channel: any, note: any, scheduleTime: any): void;
|
|
175
176
|
startVibrato(channel: any, note: any, scheduleTime: any): void;
|
|
176
|
-
getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any): Promise<any>;
|
|
177
|
-
|
|
177
|
+
getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any, realtime: any): Promise<any>;
|
|
178
|
+
setNoteAudioNode(channel: any, note: any, realtime: any): Promise<any>;
|
|
178
179
|
handleExclusiveClass(note: any, channelNumber: any, startTime: any): void;
|
|
179
180
|
handleDrumExclusiveClass(note: any, channelNumber: any, startTime: any): void;
|
|
180
|
-
|
|
181
|
-
noteOn(channelNumber: any, noteNumber: any, velocity: any,
|
|
181
|
+
setNoteRouting(channelNumber: any, note: any, startTime: any): void;
|
|
182
|
+
noteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
182
183
|
disconnectNote(note: any): void;
|
|
183
184
|
releaseNote(channel: any, note: any, endTime: any): Promise<any>;
|
|
184
|
-
|
|
185
|
+
noteOff(channelNumber: any, noteNumber: any, velocity: any, endTime: any, force: any): Promise<any> | undefined;
|
|
185
186
|
setNoteIndex(channel: any, index: any): void;
|
|
186
187
|
findNoteOffIndex(channel: any, noteNumber: any): any;
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
releaseSostenutoPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
|
|
188
|
+
releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
|
|
189
|
+
releaseSostenutoPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
|
|
190
190
|
createMessageHandlers(): any[];
|
|
191
191
|
handleMessage(data: any, scheduleTime: any): void;
|
|
192
192
|
activeSensing(): void;
|
|
@@ -312,27 +312,4 @@ export class MidyGM2 {
|
|
|
312
312
|
handleSysEx(data: any, scheduleTime: any): void;
|
|
313
313
|
scheduleTask(callback: any, scheduleTime: any): Promise<any>;
|
|
314
314
|
}
|
|
315
|
-
declare class Note {
|
|
316
|
-
constructor(noteNumber: any, velocity: any, startTime: any, voice: any, voiceParams: any);
|
|
317
|
-
index: number;
|
|
318
|
-
ending: boolean;
|
|
319
|
-
bufferSource: any;
|
|
320
|
-
filterNode: any;
|
|
321
|
-
filterDepth: any;
|
|
322
|
-
volumeEnvelopeNode: any;
|
|
323
|
-
volumeDepth: any;
|
|
324
|
-
modulationLFO: any;
|
|
325
|
-
modulationDepth: any;
|
|
326
|
-
vibratoLFO: any;
|
|
327
|
-
vibratoDepth: any;
|
|
328
|
-
reverbSend: any;
|
|
329
|
-
chorusSend: any;
|
|
330
|
-
portamentoNoteNumber: number;
|
|
331
|
-
noteNumber: any;
|
|
332
|
-
velocity: any;
|
|
333
|
-
startTime: any;
|
|
334
|
-
voice: any;
|
|
335
|
-
voiceParams: any;
|
|
336
|
-
}
|
|
337
|
-
export {};
|
|
338
315
|
//# sourceMappingURL=midy-GM2.d.ts.map
|
package/script/midy-GM2.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"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"}
|