@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/esm/midy-GMLite.js
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import { parseMidi } from "midi-file";
|
|
2
2
|
import { parse, SoundFont } from "@marmooo/soundfont-parser";
|
|
3
3
|
class Note {
|
|
4
|
-
constructor(noteNumber, velocity, startTime
|
|
4
|
+
constructor(noteNumber, velocity, startTime) {
|
|
5
|
+
Object.defineProperty(this, "voice", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
writable: true,
|
|
9
|
+
value: void 0
|
|
10
|
+
});
|
|
11
|
+
Object.defineProperty(this, "voiceParams", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
configurable: true,
|
|
14
|
+
writable: true,
|
|
15
|
+
value: void 0
|
|
16
|
+
});
|
|
5
17
|
Object.defineProperty(this, "index", {
|
|
6
18
|
enumerable: true,
|
|
7
19
|
configurable: true,
|
|
@@ -14,6 +26,12 @@ class Note {
|
|
|
14
26
|
writable: true,
|
|
15
27
|
value: false
|
|
16
28
|
});
|
|
29
|
+
Object.defineProperty(this, "pending", {
|
|
30
|
+
enumerable: true,
|
|
31
|
+
configurable: true,
|
|
32
|
+
writable: true,
|
|
33
|
+
value: true
|
|
34
|
+
});
|
|
17
35
|
Object.defineProperty(this, "bufferSource", {
|
|
18
36
|
enumerable: true,
|
|
19
37
|
configurable: true,
|
|
@@ -59,8 +77,6 @@ class Note {
|
|
|
59
77
|
this.noteNumber = noteNumber;
|
|
60
78
|
this.velocity = velocity;
|
|
61
79
|
this.startTime = startTime;
|
|
62
|
-
this.voice = voice;
|
|
63
|
-
this.voiceParams = voiceParams;
|
|
64
80
|
}
|
|
65
81
|
}
|
|
66
82
|
const drumExclusiveClasses = new Uint8Array(128);
|
|
@@ -83,11 +99,11 @@ const defaultControllerState = {
|
|
|
83
99
|
pitchWheel: { type: 14, defaultValue: 8192 / 16383 },
|
|
84
100
|
pitchWheelSensitivity: { type: 16, defaultValue: 2 / 128 },
|
|
85
101
|
link: { type: 127, defaultValue: 0 },
|
|
86
|
-
|
|
102
|
+
modulationDepthMSB: { type: 128 + 1, defaultValue: 0 },
|
|
87
103
|
// dataMSB: { type: 128 + 6, defaultValue: 0, },
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
104
|
+
volumeMSB: { type: 128 + 7, defaultValue: 100 / 127 },
|
|
105
|
+
panMSB: { type: 128 + 10, defaultValue: 64 / 127 },
|
|
106
|
+
expressionMSB: { type: 128 + 11, defaultValue: 1 },
|
|
91
107
|
// dataLSB: { type: 128 + 38, defaultValue: 0, },
|
|
92
108
|
sustainPedal: { type: 128 + 64, defaultValue: 0 },
|
|
93
109
|
// rpnLSB: { type: 128 + 100, defaultValue: 127 },
|
|
@@ -227,6 +243,12 @@ export class MidyGMLite {
|
|
|
227
243
|
writable: true,
|
|
228
244
|
value: new Map()
|
|
229
245
|
});
|
|
246
|
+
Object.defineProperty(this, "realtimeVoiceCache", {
|
|
247
|
+
enumerable: true,
|
|
248
|
+
configurable: true,
|
|
249
|
+
writable: true,
|
|
250
|
+
value: new Map()
|
|
251
|
+
});
|
|
230
252
|
Object.defineProperty(this, "isPlaying", {
|
|
231
253
|
enumerable: true,
|
|
232
254
|
configurable: true,
|
|
@@ -407,7 +429,7 @@ export class MidyGMLite {
|
|
|
407
429
|
return soundFontIndex * (2 ** 32) + (instrument << 16) + sampleID;
|
|
408
430
|
}
|
|
409
431
|
createChannelAudioNodes(audioContext) {
|
|
410
|
-
const { gainLeft, gainRight } = this.panToGain(defaultControllerState.
|
|
432
|
+
const { gainLeft, gainRight } = this.panToGain(defaultControllerState.panMSB.defaultValue);
|
|
411
433
|
const gainL = new GainNode(audioContext, { gain: gainLeft });
|
|
412
434
|
const gainR = new GainNode(audioContext, { gain: gainRight });
|
|
413
435
|
const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
|
|
@@ -435,10 +457,9 @@ export class MidyGMLite {
|
|
|
435
457
|
return channels;
|
|
436
458
|
}
|
|
437
459
|
async createAudioBuffer(voiceParams) {
|
|
438
|
-
const sample = voiceParams
|
|
439
|
-
const
|
|
440
|
-
const
|
|
441
|
-
const audioBuffer = await sample.toAudioBuffer(this.audioContext, sampleStart, sampleEnd);
|
|
460
|
+
const { sample, start, end } = voiceParams;
|
|
461
|
+
const sampleEnd = sample.data.length + end;
|
|
462
|
+
const audioBuffer = await sample.toAudioBuffer(this.audioContext, start, sampleEnd);
|
|
442
463
|
return audioBuffer;
|
|
443
464
|
}
|
|
444
465
|
createBufferSource(channel, voiceParams, audioBuffer) {
|
|
@@ -465,12 +486,10 @@ export class MidyGMLite {
|
|
|
465
486
|
const startTime = event.startTime + schedulingOffset;
|
|
466
487
|
switch (event.type) {
|
|
467
488
|
case "noteOn":
|
|
468
|
-
await this.
|
|
489
|
+
await this.noteOn(event.channel, event.noteNumber, event.velocity, startTime);
|
|
469
490
|
break;
|
|
470
491
|
case "noteOff": {
|
|
471
|
-
|
|
472
|
-
if (notePromise)
|
|
473
|
-
this.notePromises.push(notePromise);
|
|
492
|
+
this.noteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
|
|
474
493
|
break;
|
|
475
494
|
}
|
|
476
495
|
case "controller":
|
|
@@ -501,6 +520,7 @@ export class MidyGMLite {
|
|
|
501
520
|
this.exclusiveClassNotes.fill(undefined);
|
|
502
521
|
this.drumExclusiveClassNotes.fill(undefined);
|
|
503
522
|
this.voiceCache.clear();
|
|
523
|
+
this.realtimeVoiceCache.clear();
|
|
504
524
|
for (let i = 0; i < this.channels.length; i++) {
|
|
505
525
|
this.channels[i].scheduledNotes = [];
|
|
506
526
|
this.resetChannelStates(i);
|
|
@@ -538,7 +558,6 @@ export class MidyGMLite {
|
|
|
538
558
|
this.notePromises = [];
|
|
539
559
|
while (queueIndex < this.timeline.length) {
|
|
540
560
|
const now = this.audioContext.currentTime;
|
|
541
|
-
queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
|
|
542
561
|
if (this.isPausing) {
|
|
543
562
|
await this.stopNotes(0, true, now);
|
|
544
563
|
await this.audioContext.suspend();
|
|
@@ -560,9 +579,16 @@ export class MidyGMLite {
|
|
|
560
579
|
this.isSeeking = false;
|
|
561
580
|
continue;
|
|
562
581
|
}
|
|
582
|
+
queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
|
|
563
583
|
const waitTime = now + this.noteCheckInterval;
|
|
564
584
|
await this.scheduleTask(() => { }, waitTime);
|
|
565
585
|
}
|
|
586
|
+
if (this.timeline.length <= queueIndex) {
|
|
587
|
+
const now = this.audioContext.currentTime;
|
|
588
|
+
await this.stopNotes(0, true, now);
|
|
589
|
+
await this.audioContext.suspend();
|
|
590
|
+
finished = true;
|
|
591
|
+
}
|
|
566
592
|
if (finished) {
|
|
567
593
|
this.notePromises = [];
|
|
568
594
|
this.resetAllStates();
|
|
@@ -637,7 +663,7 @@ export class MidyGMLite {
|
|
|
637
663
|
const channel = this.channels[channelNumber];
|
|
638
664
|
const promises = [];
|
|
639
665
|
this.processActiveNotes(channel, scheduleTime, (note) => {
|
|
640
|
-
const promise = this.
|
|
666
|
+
const promise = this.noteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
|
|
641
667
|
this.notePromises.push(promise);
|
|
642
668
|
promises.push(promise);
|
|
643
669
|
});
|
|
@@ -647,7 +673,7 @@ export class MidyGMLite {
|
|
|
647
673
|
const channel = this.channels[channelNumber];
|
|
648
674
|
const promises = [];
|
|
649
675
|
this.processScheduledNotes(channel, (note) => {
|
|
650
|
-
const promise = this.
|
|
676
|
+
const promise = this.noteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
|
|
651
677
|
this.notePromises.push(promise);
|
|
652
678
|
promises.push(promise);
|
|
653
679
|
});
|
|
@@ -680,7 +706,7 @@ export class MidyGMLite {
|
|
|
680
706
|
if (!this.isPlaying || this.isPaused)
|
|
681
707
|
return;
|
|
682
708
|
const now = this.audioContext.currentTime;
|
|
683
|
-
this.resumeTime
|
|
709
|
+
this.resumeTime = now - this.startTime - this.startDelay;
|
|
684
710
|
this.isPausing = true;
|
|
685
711
|
await this.playPromise;
|
|
686
712
|
this.isPausing = false;
|
|
@@ -706,11 +732,13 @@ export class MidyGMLite {
|
|
|
706
732
|
if (totalTime < event.startTime)
|
|
707
733
|
totalTime = event.startTime;
|
|
708
734
|
}
|
|
709
|
-
return totalTime;
|
|
735
|
+
return totalTime + this.startDelay;
|
|
710
736
|
}
|
|
711
737
|
currentTime() {
|
|
738
|
+
if (!this.isPlaying)
|
|
739
|
+
return this.resumeTime;
|
|
712
740
|
const now = this.audioContext.currentTime;
|
|
713
|
-
return
|
|
741
|
+
return now + this.resumeTime - this.startTime;
|
|
714
742
|
}
|
|
715
743
|
processScheduledNotes(channel, callback) {
|
|
716
744
|
const scheduledNotes = channel.scheduledNotes;
|
|
@@ -847,31 +875,42 @@ export class MidyGMLite {
|
|
|
847
875
|
note.modulationLFO.connect(note.volumeDepth);
|
|
848
876
|
note.volumeDepth.connect(note.volumeEnvelopeNode.gain);
|
|
849
877
|
}
|
|
850
|
-
async getAudioBuffer(channel, noteNumber, velocity, voiceParams) {
|
|
878
|
+
async getAudioBuffer(channel, noteNumber, velocity, voiceParams, realtime) {
|
|
851
879
|
const audioBufferId = this.getVoiceId(channel, noteNumber, velocity);
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
this.voiceCache.delete(audioBufferId);
|
|
857
|
-
}
|
|
858
|
-
return cache.audioBuffer;
|
|
859
|
-
}
|
|
860
|
-
else {
|
|
861
|
-
const maxCount = this.voiceCounter.get(audioBufferId) ?? 0;
|
|
880
|
+
if (realtime) {
|
|
881
|
+
const cachedAudioBuffer = this.realtimeVoiceCache.get(audioBufferId);
|
|
882
|
+
if (cachedAudioBuffer)
|
|
883
|
+
return cachedAudioBuffer;
|
|
862
884
|
const audioBuffer = await this.createAudioBuffer(voiceParams);
|
|
863
|
-
|
|
864
|
-
this.voiceCache.set(audioBufferId, cache);
|
|
885
|
+
this.realtimeVoiceCache.set(audioBufferId, audioBuffer);
|
|
865
886
|
return audioBuffer;
|
|
866
887
|
}
|
|
888
|
+
else {
|
|
889
|
+
const cache = this.voiceCache.get(audioBufferId);
|
|
890
|
+
if (cache) {
|
|
891
|
+
cache.counter += 1;
|
|
892
|
+
if (cache.maxCount <= cache.counter) {
|
|
893
|
+
this.voiceCache.delete(audioBufferId);
|
|
894
|
+
}
|
|
895
|
+
return cache.audioBuffer;
|
|
896
|
+
}
|
|
897
|
+
else {
|
|
898
|
+
const maxCount = this.voiceCounter.get(audioBufferId) ?? 0;
|
|
899
|
+
const audioBuffer = await this.createAudioBuffer(voiceParams);
|
|
900
|
+
const cache = { audioBuffer, maxCount, counter: 1 };
|
|
901
|
+
this.voiceCache.set(audioBufferId, cache);
|
|
902
|
+
return audioBuffer;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
867
905
|
}
|
|
868
|
-
async
|
|
906
|
+
async setNoteAudioNode(channel, note, realtime) {
|
|
869
907
|
const now = this.audioContext.currentTime;
|
|
908
|
+
const { noteNumber, velocity, startTime } = note;
|
|
870
909
|
const state = channel.state;
|
|
871
910
|
const controllerState = this.getControllerState(channel, noteNumber, velocity);
|
|
872
|
-
const voiceParams = voice.getAllParams(controllerState);
|
|
873
|
-
|
|
874
|
-
const audioBuffer = await this.getAudioBuffer(channel, noteNumber, velocity, voiceParams);
|
|
911
|
+
const voiceParams = note.voice.getAllParams(controllerState);
|
|
912
|
+
note.voiceParams = voiceParams;
|
|
913
|
+
const audioBuffer = await this.getAudioBuffer(channel, noteNumber, velocity, voiceParams, realtime);
|
|
875
914
|
note.bufferSource = this.createBufferSource(channel, voiceParams, audioBuffer);
|
|
876
915
|
note.volumeEnvelopeNode = new GainNode(this.audioContext);
|
|
877
916
|
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
@@ -882,12 +921,18 @@ export class MidyGMLite {
|
|
|
882
921
|
this.setFilterEnvelope(note, now);
|
|
883
922
|
this.setPitchEnvelope(note, now);
|
|
884
923
|
this.updateDetune(channel, note, now);
|
|
885
|
-
if (0 < state.
|
|
924
|
+
if (0 < state.modulationDepthMSB) {
|
|
886
925
|
this.startModulation(channel, note, now);
|
|
887
926
|
}
|
|
888
927
|
note.bufferSource.connect(note.filterNode);
|
|
889
928
|
note.filterNode.connect(note.volumeEnvelopeNode);
|
|
890
|
-
|
|
929
|
+
if (voiceParams.sample.type === "compressed") {
|
|
930
|
+
const offset = voiceParams.start / audioBuffer.sampleRate;
|
|
931
|
+
note.bufferSource.start(startTime, offset);
|
|
932
|
+
}
|
|
933
|
+
else {
|
|
934
|
+
note.bufferSource.start(startTime);
|
|
935
|
+
}
|
|
891
936
|
return note;
|
|
892
937
|
}
|
|
893
938
|
handleExclusiveClass(note, channelNumber, startTime) {
|
|
@@ -898,7 +943,7 @@ export class MidyGMLite {
|
|
|
898
943
|
if (prev) {
|
|
899
944
|
const [prevNote, prevChannelNumber] = prev;
|
|
900
945
|
if (prevNote && !prevNote.ending) {
|
|
901
|
-
this.
|
|
946
|
+
this.noteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
|
|
902
947
|
startTime, true);
|
|
903
948
|
}
|
|
904
949
|
}
|
|
@@ -914,13 +959,31 @@ export class MidyGMLite {
|
|
|
914
959
|
const index = drumExclusiveClass * this.channels.length + channelNumber;
|
|
915
960
|
const prevNote = this.drumExclusiveClassNotes[index];
|
|
916
961
|
if (prevNote && !prevNote.ending) {
|
|
917
|
-
this.
|
|
962
|
+
this.noteOff(channelNumber, prevNote.noteNumber, 0, // velocity,
|
|
918
963
|
startTime, true);
|
|
919
964
|
}
|
|
920
965
|
this.drumExclusiveClassNotes[index] = note;
|
|
921
966
|
}
|
|
922
|
-
|
|
967
|
+
setNoteRouting(channelNumber, note, startTime) {
|
|
968
|
+
const channel = this.channels[channelNumber];
|
|
969
|
+
const volumeEnvelopeNode = note.volumeEnvelopeNode;
|
|
970
|
+
volumeEnvelopeNode.connect(channel.gainL);
|
|
971
|
+
volumeEnvelopeNode.connect(channel.gainR);
|
|
972
|
+
if (0.5 <= channel.state.sustainPedal) {
|
|
973
|
+
channel.sustainNotes.push(note);
|
|
974
|
+
}
|
|
975
|
+
this.handleExclusiveClass(note, channelNumber, startTime);
|
|
976
|
+
this.handleDrumExclusiveClass(note, channelNumber, startTime);
|
|
977
|
+
}
|
|
978
|
+
async noteOn(channelNumber, noteNumber, velocity, startTime) {
|
|
923
979
|
const channel = this.channels[channelNumber];
|
|
980
|
+
const realtime = startTime === undefined;
|
|
981
|
+
if (realtime)
|
|
982
|
+
startTime = this.audioContext.currentTime;
|
|
983
|
+
const note = new Note(noteNumber, velocity, startTime);
|
|
984
|
+
const scheduledNotes = channel.scheduledNotes;
|
|
985
|
+
note.index = scheduledNotes.length;
|
|
986
|
+
scheduledNotes.push(note);
|
|
924
987
|
const programNumber = channel.programNumber;
|
|
925
988
|
const bankTable = this.soundFontTable[programNumber];
|
|
926
989
|
if (!bankTable)
|
|
@@ -930,24 +993,16 @@ export class MidyGMLite {
|
|
|
930
993
|
if (soundFontIndex === undefined)
|
|
931
994
|
return;
|
|
932
995
|
const soundFont = this.soundFonts[soundFontIndex];
|
|
933
|
-
|
|
934
|
-
if (!voice)
|
|
996
|
+
note.voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
|
|
997
|
+
if (!note.voice)
|
|
935
998
|
return;
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
note.
|
|
939
|
-
|
|
940
|
-
|
|
999
|
+
await this.setNoteAudioNode(channel, note, realtime);
|
|
1000
|
+
this.setNoteRouting(channelNumber, note, startTime);
|
|
1001
|
+
note.pending = false;
|
|
1002
|
+
const off = note.offEvent;
|
|
1003
|
+
if (off) {
|
|
1004
|
+
this.noteOff(channelNumber, noteNumber, off.velocity, off.startTime);
|
|
941
1005
|
}
|
|
942
|
-
this.handleExclusiveClass(note, channelNumber, startTime);
|
|
943
|
-
this.handleDrumExclusiveClass(note, channelNumber, startTime);
|
|
944
|
-
const scheduledNotes = channel.scheduledNotes;
|
|
945
|
-
note.index = scheduledNotes.length;
|
|
946
|
-
scheduledNotes.push(note);
|
|
947
|
-
}
|
|
948
|
-
noteOn(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
949
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
950
|
-
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime, undefined);
|
|
951
1006
|
}
|
|
952
1007
|
disconnectNote(note) {
|
|
953
1008
|
note.bufferSource.disconnect();
|
|
@@ -960,6 +1015,7 @@ export class MidyGMLite {
|
|
|
960
1015
|
}
|
|
961
1016
|
}
|
|
962
1017
|
releaseNote(channel, note, endTime) {
|
|
1018
|
+
endTime ??= this.audioContext.currentTime;
|
|
963
1019
|
const volRelease = endTime + note.voiceParams.volRelease;
|
|
964
1020
|
const modRelease = endTime + note.voiceParams.modRelease;
|
|
965
1021
|
const stopTime = Math.min(volRelease, modRelease);
|
|
@@ -980,7 +1036,7 @@ export class MidyGMLite {
|
|
|
980
1036
|
}, stopTime);
|
|
981
1037
|
});
|
|
982
1038
|
}
|
|
983
|
-
|
|
1039
|
+
noteOff(channelNumber, noteNumber, velocity, endTime, force) {
|
|
984
1040
|
const channel = this.channels[channelNumber];
|
|
985
1041
|
if (!force) {
|
|
986
1042
|
if (channel.isDrum)
|
|
@@ -992,9 +1048,15 @@ export class MidyGMLite {
|
|
|
992
1048
|
if (index < 0)
|
|
993
1049
|
return;
|
|
994
1050
|
const note = channel.scheduledNotes[index];
|
|
1051
|
+
if (note.pending) {
|
|
1052
|
+
note.offEvent = { velocity, startTime: endTime };
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
995
1055
|
note.ending = true;
|
|
996
1056
|
this.setNoteIndex(channel, index);
|
|
997
|
-
this.releaseNote(channel, note, endTime);
|
|
1057
|
+
const promise = this.releaseNote(channel, note, endTime);
|
|
1058
|
+
this.notePromises.push(promise);
|
|
1059
|
+
return promise;
|
|
998
1060
|
}
|
|
999
1061
|
setNoteIndex(channel, index) {
|
|
1000
1062
|
let allEnds = true;
|
|
@@ -1022,16 +1084,12 @@ export class MidyGMLite {
|
|
|
1022
1084
|
}
|
|
1023
1085
|
return -1;
|
|
1024
1086
|
}
|
|
1025
|
-
noteOff(channelNumber, noteNumber, velocity, scheduleTime) {
|
|
1026
|
-
scheduleTime ??= this.audioContext.currentTime;
|
|
1027
|
-
return this.scheduleNoteOff(channelNumber, noteNumber, velocity, scheduleTime, false);
|
|
1028
|
-
}
|
|
1029
1087
|
releaseSustainPedal(channelNumber, halfVelocity, scheduleTime) {
|
|
1030
1088
|
const velocity = halfVelocity * 2;
|
|
1031
1089
|
const channel = this.channels[channelNumber];
|
|
1032
1090
|
const promises = [];
|
|
1033
1091
|
for (let i = 0; i < channel.sustainNotes.length; i++) {
|
|
1034
|
-
const promise = this.
|
|
1092
|
+
const promise = this.noteOff(channelNumber, channel.sustainNotes[i].noteNumber, velocity, scheduleTime);
|
|
1035
1093
|
promises.push(promise);
|
|
1036
1094
|
}
|
|
1037
1095
|
channel.sustainNotes = [];
|
|
@@ -1096,11 +1154,12 @@ export class MidyGMLite {
|
|
|
1096
1154
|
setModLfoToPitch(channel, note, scheduleTime) {
|
|
1097
1155
|
if (note.modulationDepth) {
|
|
1098
1156
|
const modLfoToPitch = note.voiceParams.modLfoToPitch;
|
|
1099
|
-
const baseDepth = Math.abs(modLfoToPitch) +
|
|
1100
|
-
|
|
1157
|
+
const baseDepth = Math.abs(modLfoToPitch) +
|
|
1158
|
+
channel.state.modulationDepthMSB;
|
|
1159
|
+
const depth = baseDepth * Math.sign(modLfoToPitch);
|
|
1101
1160
|
note.modulationDepth.gain
|
|
1102
1161
|
.cancelScheduledValues(scheduleTime)
|
|
1103
|
-
.setValueAtTime(
|
|
1162
|
+
.setValueAtTime(depth, scheduleTime);
|
|
1104
1163
|
}
|
|
1105
1164
|
else {
|
|
1106
1165
|
this.startModulation(channel, note, scheduleTime);
|
|
@@ -1137,18 +1196,18 @@ export class MidyGMLite {
|
|
|
1137
1196
|
createVoiceParamsHandlers() {
|
|
1138
1197
|
return {
|
|
1139
1198
|
modLfoToPitch: (channel, note, scheduleTime) => {
|
|
1140
|
-
if (0 < channel.state.
|
|
1199
|
+
if (0 < channel.state.modulationDepthMSB) {
|
|
1141
1200
|
this.setModLfoToPitch(channel, note, scheduleTime);
|
|
1142
1201
|
}
|
|
1143
1202
|
},
|
|
1144
1203
|
vibLfoToPitch: (_channel, _note, _scheduleTime) => { },
|
|
1145
1204
|
modLfoToFilterFc: (channel, note, scheduleTime) => {
|
|
1146
|
-
if (0 < channel.state.
|
|
1205
|
+
if (0 < channel.state.modulationDepthMSB) {
|
|
1147
1206
|
this.setModLfoToFilterFc(note, scheduleTime);
|
|
1148
1207
|
}
|
|
1149
1208
|
},
|
|
1150
1209
|
modLfoToVolume: (channel, note, scheduleTime) => {
|
|
1151
|
-
if (0 < channel.state.
|
|
1210
|
+
if (0 < channel.state.modulationDepthMSB) {
|
|
1152
1211
|
this.setModLfoToVolume(note, scheduleTime);
|
|
1153
1212
|
}
|
|
1154
1213
|
},
|
|
@@ -1386,8 +1445,8 @@ export class MidyGMLite {
|
|
|
1386
1445
|
resetAllControllers(channelNumber, _value, scheduleTime) {
|
|
1387
1446
|
const keys = [
|
|
1388
1447
|
"pitchWheel",
|
|
1389
|
-
"
|
|
1390
|
-
"
|
|
1448
|
+
"expressionMSB",
|
|
1449
|
+
"modulationDepthMSB",
|
|
1391
1450
|
"sustainPedal",
|
|
1392
1451
|
];
|
|
1393
1452
|
const channel = this.channels[channelNumber];
|
package/esm/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/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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"}
|