@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/script/midy-GMLite.js
CHANGED
|
@@ -4,7 +4,19 @@ exports.MidyGMLite = 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
|
const drumExclusiveClasses = new Uint8Array(128);
|
|
@@ -86,11 +102,11 @@ const defaultControllerState = {
|
|
|
86
102
|
pitchWheel: { type: 14, defaultValue: 8192 / 16383 },
|
|
87
103
|
pitchWheelSensitivity: { type: 16, defaultValue: 2 / 128 },
|
|
88
104
|
link: { type: 127, defaultValue: 0 },
|
|
89
|
-
|
|
105
|
+
modulationDepthMSB: { type: 128 + 1, defaultValue: 0 },
|
|
90
106
|
// dataMSB: { type: 128 + 6, defaultValue: 0, },
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
107
|
+
volumeMSB: { type: 128 + 7, defaultValue: 100 / 127 },
|
|
108
|
+
panMSB: { type: 128 + 10, defaultValue: 64 / 127 },
|
|
109
|
+
expressionMSB: { type: 128 + 11, defaultValue: 1 },
|
|
94
110
|
// dataLSB: { type: 128 + 38, defaultValue: 0, },
|
|
95
111
|
sustainPedal: { type: 128 + 64, defaultValue: 0 },
|
|
96
112
|
// rpnLSB: { type: 128 + 100, defaultValue: 127 },
|
|
@@ -230,6 +246,12 @@ class MidyGMLite {
|
|
|
230
246
|
writable: true,
|
|
231
247
|
value: new Map()
|
|
232
248
|
});
|
|
249
|
+
Object.defineProperty(this, "realtimeVoiceCache", {
|
|
250
|
+
enumerable: true,
|
|
251
|
+
configurable: true,
|
|
252
|
+
writable: true,
|
|
253
|
+
value: new Map()
|
|
254
|
+
});
|
|
233
255
|
Object.defineProperty(this, "isPlaying", {
|
|
234
256
|
enumerable: true,
|
|
235
257
|
configurable: true,
|
|
@@ -410,7 +432,7 @@ class MidyGMLite {
|
|
|
410
432
|
return soundFontIndex * (2 ** 32) + (instrument << 16) + sampleID;
|
|
411
433
|
}
|
|
412
434
|
createChannelAudioNodes(audioContext) {
|
|
413
|
-
const { gainLeft, gainRight } = this.panToGain(defaultControllerState.
|
|
435
|
+
const { gainLeft, gainRight } = this.panToGain(defaultControllerState.panMSB.defaultValue);
|
|
414
436
|
const gainL = new GainNode(audioContext, { gain: gainLeft });
|
|
415
437
|
const gainR = new GainNode(audioContext, { gain: gainRight });
|
|
416
438
|
const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
|
|
@@ -438,10 +460,9 @@ class MidyGMLite {
|
|
|
438
460
|
return channels;
|
|
439
461
|
}
|
|
440
462
|
async createAudioBuffer(voiceParams) {
|
|
441
|
-
const sample = voiceParams
|
|
442
|
-
const
|
|
443
|
-
const
|
|
444
|
-
const audioBuffer = await sample.toAudioBuffer(this.audioContext, sampleStart, sampleEnd);
|
|
463
|
+
const { sample, start, end } = voiceParams;
|
|
464
|
+
const sampleEnd = sample.data.length + end;
|
|
465
|
+
const audioBuffer = await sample.toAudioBuffer(this.audioContext, start, sampleEnd);
|
|
445
466
|
return audioBuffer;
|
|
446
467
|
}
|
|
447
468
|
createBufferSource(channel, voiceParams, audioBuffer) {
|
|
@@ -468,12 +489,10 @@ class MidyGMLite {
|
|
|
468
489
|
const startTime = event.startTime + schedulingOffset;
|
|
469
490
|
switch (event.type) {
|
|
470
491
|
case "noteOn":
|
|
471
|
-
await this.
|
|
492
|
+
await this.noteOn(event.channel, event.noteNumber, event.velocity, startTime);
|
|
472
493
|
break;
|
|
473
494
|
case "noteOff": {
|
|
474
|
-
|
|
475
|
-
if (notePromise)
|
|
476
|
-
this.notePromises.push(notePromise);
|
|
495
|
+
this.noteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
|
|
477
496
|
break;
|
|
478
497
|
}
|
|
479
498
|
case "controller":
|
|
@@ -504,6 +523,7 @@ class MidyGMLite {
|
|
|
504
523
|
this.exclusiveClassNotes.fill(undefined);
|
|
505
524
|
this.drumExclusiveClassNotes.fill(undefined);
|
|
506
525
|
this.voiceCache.clear();
|
|
526
|
+
this.realtimeVoiceCache.clear();
|
|
507
527
|
for (let i = 0; i < this.channels.length; i++) {
|
|
508
528
|
this.channels[i].scheduledNotes = [];
|
|
509
529
|
this.resetChannelStates(i);
|
|
@@ -541,7 +561,6 @@ class MidyGMLite {
|
|
|
541
561
|
this.notePromises = [];
|
|
542
562
|
while (queueIndex < this.timeline.length) {
|
|
543
563
|
const now = this.audioContext.currentTime;
|
|
544
|
-
queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
|
|
545
564
|
if (this.isPausing) {
|
|
546
565
|
await this.stopNotes(0, true, now);
|
|
547
566
|
await this.audioContext.suspend();
|
|
@@ -563,9 +582,16 @@ class MidyGMLite {
|
|
|
563
582
|
this.isSeeking = false;
|
|
564
583
|
continue;
|
|
565
584
|
}
|
|
585
|
+
queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
|
|
566
586
|
const waitTime = now + this.noteCheckInterval;
|
|
567
587
|
await this.scheduleTask(() => { }, waitTime);
|
|
568
588
|
}
|
|
589
|
+
if (this.timeline.length <= queueIndex) {
|
|
590
|
+
const now = this.audioContext.currentTime;
|
|
591
|
+
await this.stopNotes(0, true, now);
|
|
592
|
+
await this.audioContext.suspend();
|
|
593
|
+
finished = true;
|
|
594
|
+
}
|
|
569
595
|
if (finished) {
|
|
570
596
|
this.notePromises = [];
|
|
571
597
|
this.resetAllStates();
|
|
@@ -640,7 +666,7 @@ class MidyGMLite {
|
|
|
640
666
|
const channel = this.channels[channelNumber];
|
|
641
667
|
const promises = [];
|
|
642
668
|
this.processActiveNotes(channel, scheduleTime, (note) => {
|
|
643
|
-
const promise = this.
|
|
669
|
+
const promise = this.noteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
|
|
644
670
|
this.notePromises.push(promise);
|
|
645
671
|
promises.push(promise);
|
|
646
672
|
});
|
|
@@ -650,7 +676,7 @@ class MidyGMLite {
|
|
|
650
676
|
const channel = this.channels[channelNumber];
|
|
651
677
|
const promises = [];
|
|
652
678
|
this.processScheduledNotes(channel, (note) => {
|
|
653
|
-
const promise = this.
|
|
679
|
+
const promise = this.noteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
|
|
654
680
|
this.notePromises.push(promise);
|
|
655
681
|
promises.push(promise);
|
|
656
682
|
});
|
|
@@ -683,7 +709,7 @@ class MidyGMLite {
|
|
|
683
709
|
if (!this.isPlaying || this.isPaused)
|
|
684
710
|
return;
|
|
685
711
|
const now = this.audioContext.currentTime;
|
|
686
|
-
this.resumeTime
|
|
712
|
+
this.resumeTime = now - this.startTime - this.startDelay;
|
|
687
713
|
this.isPausing = true;
|
|
688
714
|
await this.playPromise;
|
|
689
715
|
this.isPausing = false;
|
|
@@ -709,11 +735,13 @@ class MidyGMLite {
|
|
|
709
735
|
if (totalTime < event.startTime)
|
|
710
736
|
totalTime = event.startTime;
|
|
711
737
|
}
|
|
712
|
-
return totalTime;
|
|
738
|
+
return totalTime + this.startDelay;
|
|
713
739
|
}
|
|
714
740
|
currentTime() {
|
|
741
|
+
if (!this.isPlaying)
|
|
742
|
+
return this.resumeTime;
|
|
715
743
|
const now = this.audioContext.currentTime;
|
|
716
|
-
return
|
|
744
|
+
return now + this.resumeTime - this.startTime;
|
|
717
745
|
}
|
|
718
746
|
processScheduledNotes(channel, callback) {
|
|
719
747
|
const scheduledNotes = channel.scheduledNotes;
|
|
@@ -850,31 +878,42 @@ class MidyGMLite {
|
|
|
850
878
|
note.modulationLFO.connect(note.volumeDepth);
|
|
851
879
|
note.volumeDepth.connect(note.volumeEnvelopeNode.gain);
|
|
852
880
|
}
|
|
853
|
-
async getAudioBuffer(channel, noteNumber, velocity, voiceParams) {
|
|
881
|
+
async getAudioBuffer(channel, noteNumber, velocity, voiceParams, realtime) {
|
|
854
882
|
const audioBufferId = this.getVoiceId(channel, noteNumber, velocity);
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
this.voiceCache.delete(audioBufferId);
|
|
860
|
-
}
|
|
861
|
-
return cache.audioBuffer;
|
|
862
|
-
}
|
|
863
|
-
else {
|
|
864
|
-
const maxCount = this.voiceCounter.get(audioBufferId) ?? 0;
|
|
883
|
+
if (realtime) {
|
|
884
|
+
const cachedAudioBuffer = this.realtimeVoiceCache.get(audioBufferId);
|
|
885
|
+
if (cachedAudioBuffer)
|
|
886
|
+
return cachedAudioBuffer;
|
|
865
887
|
const audioBuffer = await this.createAudioBuffer(voiceParams);
|
|
866
|
-
|
|
867
|
-
this.voiceCache.set(audioBufferId, cache);
|
|
888
|
+
this.realtimeVoiceCache.set(audioBufferId, audioBuffer);
|
|
868
889
|
return audioBuffer;
|
|
869
890
|
}
|
|
891
|
+
else {
|
|
892
|
+
const cache = this.voiceCache.get(audioBufferId);
|
|
893
|
+
if (cache) {
|
|
894
|
+
cache.counter += 1;
|
|
895
|
+
if (cache.maxCount <= cache.counter) {
|
|
896
|
+
this.voiceCache.delete(audioBufferId);
|
|
897
|
+
}
|
|
898
|
+
return cache.audioBuffer;
|
|
899
|
+
}
|
|
900
|
+
else {
|
|
901
|
+
const maxCount = this.voiceCounter.get(audioBufferId) ?? 0;
|
|
902
|
+
const audioBuffer = await this.createAudioBuffer(voiceParams);
|
|
903
|
+
const cache = { audioBuffer, maxCount, counter: 1 };
|
|
904
|
+
this.voiceCache.set(audioBufferId, cache);
|
|
905
|
+
return audioBuffer;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
870
908
|
}
|
|
871
|
-
async
|
|
909
|
+
async setNoteAudioNode(channel, note, realtime) {
|
|
872
910
|
const now = this.audioContext.currentTime;
|
|
911
|
+
const { noteNumber, velocity, startTime } = note;
|
|
873
912
|
const state = channel.state;
|
|
874
913
|
const controllerState = this.getControllerState(channel, noteNumber, velocity);
|
|
875
|
-
const voiceParams = voice.getAllParams(controllerState);
|
|
876
|
-
|
|
877
|
-
const audioBuffer = await this.getAudioBuffer(channel, noteNumber, velocity, voiceParams);
|
|
914
|
+
const voiceParams = note.voice.getAllParams(controllerState);
|
|
915
|
+
note.voiceParams = voiceParams;
|
|
916
|
+
const audioBuffer = await this.getAudioBuffer(channel, noteNumber, velocity, voiceParams, realtime);
|
|
878
917
|
note.bufferSource = this.createBufferSource(channel, voiceParams, audioBuffer);
|
|
879
918
|
note.volumeEnvelopeNode = new GainNode(this.audioContext);
|
|
880
919
|
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
@@ -885,12 +924,18 @@ class MidyGMLite {
|
|
|
885
924
|
this.setFilterEnvelope(note, now);
|
|
886
925
|
this.setPitchEnvelope(note, now);
|
|
887
926
|
this.updateDetune(channel, note, now);
|
|
888
|
-
if (0 < state.
|
|
927
|
+
if (0 < state.modulationDepthMSB) {
|
|
889
928
|
this.startModulation(channel, note, now);
|
|
890
929
|
}
|
|
891
930
|
note.bufferSource.connect(note.filterNode);
|
|
892
931
|
note.filterNode.connect(note.volumeEnvelopeNode);
|
|
893
|
-
|
|
932
|
+
if (voiceParams.sample.type === "compressed") {
|
|
933
|
+
const offset = voiceParams.start / audioBuffer.sampleRate;
|
|
934
|
+
note.bufferSource.start(startTime, offset);
|
|
935
|
+
}
|
|
936
|
+
else {
|
|
937
|
+
note.bufferSource.start(startTime);
|
|
938
|
+
}
|
|
894
939
|
return note;
|
|
895
940
|
}
|
|
896
941
|
handleExclusiveClass(note, channelNumber, startTime) {
|
|
@@ -901,7 +946,7 @@ class MidyGMLite {
|
|
|
901
946
|
if (prev) {
|
|
902
947
|
const [prevNote, prevChannelNumber] = prev;
|
|
903
948
|
if (prevNote && !prevNote.ending) {
|
|
904
|
-
this.
|
|
949
|
+
this.noteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
|
|
905
950
|
startTime, true);
|
|
906
951
|
}
|
|
907
952
|
}
|
|
@@ -917,13 +962,31 @@ class MidyGMLite {
|
|
|
917
962
|
const index = drumExclusiveClass * this.channels.length + channelNumber;
|
|
918
963
|
const prevNote = this.drumExclusiveClassNotes[index];
|
|
919
964
|
if (prevNote && !prevNote.ending) {
|
|
920
|
-
this.
|
|
965
|
+
this.noteOff(channelNumber, prevNote.noteNumber, 0, // velocity,
|
|
921
966
|
startTime, true);
|
|
922
967
|
}
|
|
923
968
|
this.drumExclusiveClassNotes[index] = note;
|
|
924
969
|
}
|
|
925
|
-
|
|
970
|
+
setNoteRouting(channelNumber, note, startTime) {
|
|
971
|
+
const channel = this.channels[channelNumber];
|
|
972
|
+
const volumeEnvelopeNode = note.volumeEnvelopeNode;
|
|
973
|
+
volumeEnvelopeNode.connect(channel.gainL);
|
|
974
|
+
volumeEnvelopeNode.connect(channel.gainR);
|
|
975
|
+
if (0.5 <= channel.state.sustainPedal) {
|
|
976
|
+
channel.sustainNotes.push(note);
|
|
977
|
+
}
|
|
978
|
+
this.handleExclusiveClass(note, channelNumber, startTime);
|
|
979
|
+
this.handleDrumExclusiveClass(note, channelNumber, startTime);
|
|
980
|
+
}
|
|
981
|
+
async noteOn(channelNumber, noteNumber, velocity, startTime) {
|
|
926
982
|
const channel = this.channels[channelNumber];
|
|
983
|
+
const realtime = startTime === undefined;
|
|
984
|
+
if (realtime)
|
|
985
|
+
startTime = this.audioContext.currentTime;
|
|
986
|
+
const note = new Note(noteNumber, velocity, startTime);
|
|
987
|
+
const scheduledNotes = channel.scheduledNotes;
|
|
988
|
+
note.index = scheduledNotes.length;
|
|
989
|
+
scheduledNotes.push(note);
|
|
927
990
|
const programNumber = channel.programNumber;
|
|
928
991
|
const bankTable = this.soundFontTable[programNumber];
|
|
929
992
|
if (!bankTable)
|
|
@@ -933,24 +996,16 @@ class MidyGMLite {
|
|
|
933
996
|
if (soundFontIndex === undefined)
|
|
934
997
|
return;
|
|
935
998
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
936
|
-
|
|
937
|
-
if (!voice)
|
|
999
|
+
note.voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
|
|
1000
|
+
if (!note.voice)
|
|
938
1001
|
return;
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
note.
|
|
942
|
-
|
|
943
|
-
|
|
1002
|
+
await this.setNoteAudioNode(channel, note, realtime);
|
|
1003
|
+
this.setNoteRouting(channelNumber, note, startTime);
|
|
1004
|
+
note.pending = false;
|
|
1005
|
+
const off = note.offEvent;
|
|
1006
|
+
if (off) {
|
|
1007
|
+
this.noteOff(channelNumber, noteNumber, off.velocity, off.startTime);
|
|
944
1008
|
}
|
|
945
|
-
this.handleExclusiveClass(note, channelNumber, startTime);
|
|
946
|
-
this.handleDrumExclusiveClass(note, channelNumber, startTime);
|
|
947
|
-
const scheduledNotes = channel.scheduledNotes;
|
|
948
|
-
note.index = scheduledNotes.length;
|
|
949
|
-
scheduledNotes.push(note);
|
|
950
|
-
}
|
|
951
|
-
noteOn(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
952
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
953
|
-
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime, undefined);
|
|
954
1009
|
}
|
|
955
1010
|
disconnectNote(note) {
|
|
956
1011
|
note.bufferSource.disconnect();
|
|
@@ -963,6 +1018,7 @@ class MidyGMLite {
|
|
|
963
1018
|
}
|
|
964
1019
|
}
|
|
965
1020
|
releaseNote(channel, note, endTime) {
|
|
1021
|
+
endTime ??= this.audioContext.currentTime;
|
|
966
1022
|
const volRelease = endTime + note.voiceParams.volRelease;
|
|
967
1023
|
const modRelease = endTime + note.voiceParams.modRelease;
|
|
968
1024
|
const stopTime = Math.min(volRelease, modRelease);
|
|
@@ -983,7 +1039,7 @@ class MidyGMLite {
|
|
|
983
1039
|
}, stopTime);
|
|
984
1040
|
});
|
|
985
1041
|
}
|
|
986
|
-
|
|
1042
|
+
noteOff(channelNumber, noteNumber, velocity, endTime, force) {
|
|
987
1043
|
const channel = this.channels[channelNumber];
|
|
988
1044
|
if (!force) {
|
|
989
1045
|
if (channel.isDrum)
|
|
@@ -995,9 +1051,15 @@ class MidyGMLite {
|
|
|
995
1051
|
if (index < 0)
|
|
996
1052
|
return;
|
|
997
1053
|
const note = channel.scheduledNotes[index];
|
|
1054
|
+
if (note.pending) {
|
|
1055
|
+
note.offEvent = { velocity, startTime: endTime };
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
998
1058
|
note.ending = true;
|
|
999
1059
|
this.setNoteIndex(channel, index);
|
|
1000
|
-
this.releaseNote(channel, note, endTime);
|
|
1060
|
+
const promise = this.releaseNote(channel, note, endTime);
|
|
1061
|
+
this.notePromises.push(promise);
|
|
1062
|
+
return promise;
|
|
1001
1063
|
}
|
|
1002
1064
|
setNoteIndex(channel, index) {
|
|
1003
1065
|
let allEnds = true;
|
|
@@ -1025,16 +1087,12 @@ class MidyGMLite {
|
|
|
1025
1087
|
}
|
|
1026
1088
|
return -1;
|
|
1027
1089
|
}
|
|
1028
|
-
noteOff(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
1029
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1030
|
-
return this.scheduleNoteOff(channelNumber, noteNumber, velocity, scheduleTime, false);
|
|
1031
|
-
}
|
|
1032
1090
|
releaseSustainPedal(channelNumber, halfVelocity, scheduleTime) {
|
|
1033
1091
|
const velocity = halfVelocity * 2;
|
|
1034
1092
|
const channel = this.channels[channelNumber];
|
|
1035
1093
|
const promises = [];
|
|
1036
1094
|
for (let i = 0; i < channel.sustainNotes.length; i++) {
|
|
1037
|
-
const promise = this.
|
|
1095
|
+
const promise = this.noteOff(channelNumber, channel.sustainNotes[i].noteNumber, velocity, scheduleTime);
|
|
1038
1096
|
promises.push(promise);
|
|
1039
1097
|
}
|
|
1040
1098
|
channel.sustainNotes = [];
|
|
@@ -1099,11 +1157,12 @@ class MidyGMLite {
|
|
|
1099
1157
|
setModLfoToPitch(channel, note, scheduleTime) {
|
|
1100
1158
|
if (note.modulationDepth) {
|
|
1101
1159
|
const modLfoToPitch = note.voiceParams.modLfoToPitch;
|
|
1102
|
-
const baseDepth = Math.abs(modLfoToPitch) +
|
|
1103
|
-
|
|
1160
|
+
const baseDepth = Math.abs(modLfoToPitch) +
|
|
1161
|
+
channel.state.modulationDepthMSB;
|
|
1162
|
+
const depth = baseDepth * Math.sign(modLfoToPitch);
|
|
1104
1163
|
note.modulationDepth.gain
|
|
1105
1164
|
.cancelScheduledValues(scheduleTime)
|
|
1106
|
-
.setValueAtTime(
|
|
1165
|
+
.setValueAtTime(depth, scheduleTime);
|
|
1107
1166
|
}
|
|
1108
1167
|
else {
|
|
1109
1168
|
this.startModulation(channel, note, scheduleTime);
|
|
@@ -1140,18 +1199,18 @@ class MidyGMLite {
|
|
|
1140
1199
|
createVoiceParamsHandlers() {
|
|
1141
1200
|
return {
|
|
1142
1201
|
modLfoToPitch: (channel, note, scheduleTime) => {
|
|
1143
|
-
if (0 < channel.state.
|
|
1202
|
+
if (0 < channel.state.modulationDepthMSB) {
|
|
1144
1203
|
this.setModLfoToPitch(channel, note, scheduleTime);
|
|
1145
1204
|
}
|
|
1146
1205
|
},
|
|
1147
1206
|
vibLfoToPitch: (_channel, _note, _scheduleTime) => { },
|
|
1148
1207
|
modLfoToFilterFc: (channel, note, scheduleTime) => {
|
|
1149
|
-
if (0 < channel.state.
|
|
1208
|
+
if (0 < channel.state.modulationDepthMSB) {
|
|
1150
1209
|
this.setModLfoToFilterFc(note, scheduleTime);
|
|
1151
1210
|
}
|
|
1152
1211
|
},
|
|
1153
1212
|
modLfoToVolume: (channel, note, scheduleTime) => {
|
|
1154
|
-
if (0 < channel.state.
|
|
1213
|
+
if (0 < channel.state.modulationDepthMSB) {
|
|
1155
1214
|
this.setModLfoToVolume(note, scheduleTime);
|
|
1156
1215
|
}
|
|
1157
1216
|
},
|
|
@@ -1389,8 +1448,8 @@ class MidyGMLite {
|
|
|
1389
1448
|
resetAllControllers(channelNumber, _value, scheduleTime) {
|
|
1390
1449
|
const keys = [
|
|
1391
1450
|
"pitchWheel",
|
|
1392
|
-
"
|
|
1393
|
-
"
|
|
1451
|
+
"expressionMSB",
|
|
1452
|
+
"modulationDepthMSB",
|
|
1394
1453
|
"sustainPedal",
|
|
1395
1454
|
];
|
|
1396
1455
|
const channel = this.channels[channelNumber];
|
package/script/midy.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export class Midy {
|
|
|
13
13
|
modulationDepthRange: number;
|
|
14
14
|
fineTuning: number;
|
|
15
15
|
coarseTuning: number;
|
|
16
|
+
portamentoControl: boolean;
|
|
16
17
|
};
|
|
17
18
|
constructor(audioContext: any);
|
|
18
19
|
mode: string;
|
|
@@ -44,6 +45,7 @@ export class Midy {
|
|
|
44
45
|
soundFontTable: never[][];
|
|
45
46
|
voiceCounter: Map<any, any>;
|
|
46
47
|
voiceCache: Map<any, any>;
|
|
48
|
+
realtimeVoiceCache: Map<any, any>;
|
|
47
49
|
isPlaying: boolean;
|
|
48
50
|
isPausing: boolean;
|
|
49
51
|
isPaused: boolean;
|
|
@@ -173,20 +175,19 @@ export class Midy {
|
|
|
173
175
|
setFilterEnvelope(channel: any, note: any, scheduleTime: any): void;
|
|
174
176
|
startModulation(channel: any, note: any, scheduleTime: any): void;
|
|
175
177
|
startVibrato(channel: any, note: any, scheduleTime: any): void;
|
|
176
|
-
getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any): Promise<any>;
|
|
177
|
-
|
|
178
|
+
getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any, realtime: any): Promise<any>;
|
|
179
|
+
setNoteAudioNode(channel: any, note: any, realtime: any): Promise<any>;
|
|
178
180
|
handleExclusiveClass(note: any, channelNumber: any, startTime: any): void;
|
|
179
181
|
handleDrumExclusiveClass(note: any, channelNumber: any, startTime: any): void;
|
|
180
|
-
|
|
181
|
-
noteOn(channelNumber: any, noteNumber: any, velocity: any,
|
|
182
|
+
setNoteRouting(channelNumber: any, note: any, startTime: any): void;
|
|
183
|
+
noteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
182
184
|
disconnectNote(note: any): void;
|
|
183
185
|
releaseNote(channel: any, note: any, endTime: any): Promise<any>;
|
|
184
|
-
|
|
186
|
+
noteOff(channelNumber: any, noteNumber: any, velocity: any, endTime: any, force: any): Promise<any> | undefined;
|
|
185
187
|
setNoteIndex(channel: any, index: any): void;
|
|
186
188
|
findNoteOffIndex(channel: any, noteNumber: any): any;
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
releaseSostenutoPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
|
|
189
|
+
releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
|
|
190
|
+
releaseSostenutoPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
|
|
190
191
|
createMessageHandlers(): any[];
|
|
191
192
|
handleMessage(data: any, scheduleTime: any): void;
|
|
192
193
|
activeSensing(): void;
|
|
@@ -223,16 +224,16 @@ export class Midy {
|
|
|
223
224
|
setControlChange(channelNumber: any, controllerType: any, value: any, scheduleTime: any): void;
|
|
224
225
|
setBankMSB(channelNumber: any, msb: any): void;
|
|
225
226
|
updateModulation(channel: any, scheduleTime: any): void;
|
|
226
|
-
setModulationDepth(channelNumber: any,
|
|
227
|
+
setModulationDepth(channelNumber: any, value: any, scheduleTime: any): void;
|
|
227
228
|
updatePortamento(channel: any, scheduleTime: any): void;
|
|
228
|
-
setPortamentoTime(channelNumber: any,
|
|
229
|
-
setVolume(channelNumber: any,
|
|
229
|
+
setPortamentoTime(channelNumber: any, value: any, scheduleTime: any): void;
|
|
230
|
+
setVolume(channelNumber: any, value: any, scheduleTime: any): void;
|
|
230
231
|
panToGain(pan: any): {
|
|
231
232
|
gainLeft: number;
|
|
232
233
|
gainRight: number;
|
|
233
234
|
};
|
|
234
|
-
setPan(channelNumber: any,
|
|
235
|
-
setExpression(channelNumber: any,
|
|
235
|
+
setPan(channelNumber: any, value: any, scheduleTime: any): void;
|
|
236
|
+
setExpression(channelNumber: any, value: any, scheduleTime: any): void;
|
|
236
237
|
setBankLSB(channelNumber: any, lsb: any): void;
|
|
237
238
|
dataEntryLSB(channelNumber: any, value: any, scheduleTime: any): void;
|
|
238
239
|
updateChannelVolume(channel: any, scheduleTime: any): void;
|
|
@@ -252,6 +253,7 @@ export class Midy {
|
|
|
252
253
|
setVibratoRate(channelNumber: any, vibratoRate: any, scheduleTime: any): void;
|
|
253
254
|
setVibratoDepth(channelNumber: any, vibratoDepth: any, scheduleTime: any): void;
|
|
254
255
|
setVibratoDelay(channelNumber: any, vibratoDelay: any, scheduleTime: any): void;
|
|
256
|
+
setPortamentoNoteNumber(channelNumber: any, value: any, scheduleTime: any): void;
|
|
255
257
|
setReverbSendLevel(channelNumber: any, reverbSendLevel: any, scheduleTime: any): void;
|
|
256
258
|
setChorusSendLevel(channelNumber: any, chorusSendLevel: any, scheduleTime: any): void;
|
|
257
259
|
limitData(channel: any, minMSB: any, maxMSB: any, minLSB: any, maxLSB: any): void;
|
|
@@ -326,28 +328,4 @@ export class Midy {
|
|
|
326
328
|
handleSysEx(data: any, scheduleTime: any): void;
|
|
327
329
|
scheduleTask(callback: any, scheduleTime: any): Promise<any>;
|
|
328
330
|
}
|
|
329
|
-
declare class Note {
|
|
330
|
-
constructor(noteNumber: any, velocity: any, startTime: any, voice: any, voiceParams: any);
|
|
331
|
-
index: number;
|
|
332
|
-
ending: boolean;
|
|
333
|
-
bufferSource: any;
|
|
334
|
-
filterNode: any;
|
|
335
|
-
filterDepth: any;
|
|
336
|
-
volumeEnvelopeNode: any;
|
|
337
|
-
volumeDepth: any;
|
|
338
|
-
modulationLFO: any;
|
|
339
|
-
modulationDepth: any;
|
|
340
|
-
vibratoLFO: any;
|
|
341
|
-
vibratoDepth: any;
|
|
342
|
-
reverbSend: any;
|
|
343
|
-
chorusSend: any;
|
|
344
|
-
portamentoNoteNumber: number;
|
|
345
|
-
pressure: number;
|
|
346
|
-
noteNumber: any;
|
|
347
|
-
velocity: any;
|
|
348
|
-
startTime: any;
|
|
349
|
-
voice: any;
|
|
350
|
-
voiceParams: any;
|
|
351
|
-
}
|
|
352
|
-
export {};
|
|
353
331
|
//# sourceMappingURL=midy.d.ts.map
|
package/script/midy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
|