@marmooo/midy 0.1.2 → 0.1.4
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/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.d.ts +153 -0
- package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.d.ts.map +1 -0
- package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.2 → soundfont-parser@0.0.4}/+esm.js +73 -66
- package/esm/midy-GM1.d.ts +19 -13
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +171 -131
- package/esm/midy-GM2.d.ts +22 -14
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +186 -133
- package/esm/midy-GMLite.d.ts +17 -13
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +159 -131
- package/esm/midy.d.ts +30 -16
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +266 -166
- package/package.json +1 -1
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.d.ts +153 -0
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.d.ts.map +1 -0
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.2 → soundfont-parser@0.0.4}/+esm.js +75 -68
- package/script/midy-GM1.d.ts +19 -13
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +171 -131
- package/script/midy-GM2.d.ts +22 -14
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +186 -133
- package/script/midy-GMLite.d.ts +17 -13
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +159 -131
- package/script/midy.d.ts +30 -16
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +266 -166
- package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.d.ts +0 -135
- package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.d.ts.map +0 -1
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.d.ts +0 -135
- package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.d.ts.map +0 -1
package/script/midy-GM2.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MidyGM2 = void 0;
|
|
4
4
|
const _esm_js_1 = require("./deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js");
|
|
5
|
-
const _esm_js_2 = require("./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.
|
|
5
|
+
const _esm_js_2 = require("./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.js");
|
|
6
6
|
class Note {
|
|
7
7
|
constructor(noteNumber, velocity, startTime, instrumentKey) {
|
|
8
8
|
Object.defineProperty(this, "bufferSource", {
|
|
@@ -11,37 +11,43 @@ class Note {
|
|
|
11
11
|
writable: true,
|
|
12
12
|
value: void 0
|
|
13
13
|
});
|
|
14
|
-
Object.defineProperty(this, "
|
|
14
|
+
Object.defineProperty(this, "filterNode", {
|
|
15
15
|
enumerable: true,
|
|
16
16
|
configurable: true,
|
|
17
17
|
writable: true,
|
|
18
18
|
value: void 0
|
|
19
19
|
});
|
|
20
|
-
Object.defineProperty(this, "
|
|
20
|
+
Object.defineProperty(this, "volumeNode", {
|
|
21
21
|
enumerable: true,
|
|
22
22
|
configurable: true,
|
|
23
23
|
writable: true,
|
|
24
24
|
value: void 0
|
|
25
25
|
});
|
|
26
|
-
Object.defineProperty(this, "
|
|
26
|
+
Object.defineProperty(this, "volumeDepth", {
|
|
27
27
|
enumerable: true,
|
|
28
28
|
configurable: true,
|
|
29
29
|
writable: true,
|
|
30
30
|
value: void 0
|
|
31
31
|
});
|
|
32
|
-
Object.defineProperty(this, "
|
|
32
|
+
Object.defineProperty(this, "modulationLFO", {
|
|
33
33
|
enumerable: true,
|
|
34
34
|
configurable: true,
|
|
35
35
|
writable: true,
|
|
36
36
|
value: void 0
|
|
37
37
|
});
|
|
38
|
-
Object.defineProperty(this, "
|
|
38
|
+
Object.defineProperty(this, "modulationDepth", {
|
|
39
39
|
enumerable: true,
|
|
40
40
|
configurable: true,
|
|
41
41
|
writable: true,
|
|
42
42
|
value: void 0
|
|
43
43
|
});
|
|
44
|
-
Object.defineProperty(this, "
|
|
44
|
+
Object.defineProperty(this, "vibratoLFO", {
|
|
45
|
+
enumerable: true,
|
|
46
|
+
configurable: true,
|
|
47
|
+
writable: true,
|
|
48
|
+
value: void 0
|
|
49
|
+
});
|
|
50
|
+
Object.defineProperty(this, "vibratoDepth", {
|
|
45
51
|
enumerable: true,
|
|
46
52
|
configurable: true,
|
|
47
53
|
writable: true,
|
|
@@ -407,7 +413,7 @@ class MidyGM2 {
|
|
|
407
413
|
const t = this.audioContext.currentTime + offset;
|
|
408
414
|
queueIndex = await this.scheduleTimelineEvents(t, offset, queueIndex);
|
|
409
415
|
if (this.isPausing) {
|
|
410
|
-
await this.stopNotes();
|
|
416
|
+
await this.stopNotes(0, true);
|
|
411
417
|
this.notePromises = [];
|
|
412
418
|
resolve();
|
|
413
419
|
this.isPausing = false;
|
|
@@ -415,7 +421,7 @@ class MidyGM2 {
|
|
|
415
421
|
return;
|
|
416
422
|
}
|
|
417
423
|
else if (this.isStopping) {
|
|
418
|
-
await this.stopNotes();
|
|
424
|
+
await this.stopNotes(0, true);
|
|
419
425
|
this.notePromises = [];
|
|
420
426
|
resolve();
|
|
421
427
|
this.isStopping = false;
|
|
@@ -423,7 +429,7 @@ class MidyGM2 {
|
|
|
423
429
|
return;
|
|
424
430
|
}
|
|
425
431
|
else if (this.isSeeking) {
|
|
426
|
-
this.stopNotes();
|
|
432
|
+
this.stopNotes(0, true);
|
|
427
433
|
this.startTime = this.audioContext.currentTime;
|
|
428
434
|
queueIndex = this.getQueueIndex(this.resumeTime);
|
|
429
435
|
offset = this.resumeTime - this.startTime;
|
|
@@ -538,21 +544,25 @@ class MidyGM2 {
|
|
|
538
544
|
}
|
|
539
545
|
return { instruments, timeline };
|
|
540
546
|
}
|
|
541
|
-
|
|
547
|
+
async stopChannelNotes(channelNumber, velocity, stopPedal) {
|
|
542
548
|
const now = this.audioContext.currentTime;
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
});
|
|
553
|
-
});
|
|
554
|
-
channel.scheduledNotes.clear();
|
|
549
|
+
const channel = this.channels[channelNumber];
|
|
550
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
551
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
552
|
+
const note = noteList[i];
|
|
553
|
+
if (!note)
|
|
554
|
+
continue;
|
|
555
|
+
const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, stopPedal);
|
|
556
|
+
this.notePromises.push(promise);
|
|
557
|
+
}
|
|
555
558
|
});
|
|
559
|
+
channel.scheduledNotes.clear();
|
|
560
|
+
await Promise.all(this.notePromises);
|
|
561
|
+
}
|
|
562
|
+
stopNotes(velocity, stopPedal) {
|
|
563
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
564
|
+
this.stopChannelNotes(i, velocity, stopPedal);
|
|
565
|
+
}
|
|
556
566
|
return Promise.all(this.notePromises);
|
|
557
567
|
}
|
|
558
568
|
async start() {
|
|
@@ -767,79 +777,137 @@ class MidyGM2 {
|
|
|
767
777
|
}
|
|
768
778
|
setVolumeEnvelope(note) {
|
|
769
779
|
const { instrumentKey, startTime } = note;
|
|
770
|
-
note.gainNode = new GainNode(this.audioContext, { gain: 0 });
|
|
771
780
|
const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
|
|
772
781
|
const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
|
|
773
782
|
const volDelay = startTime + instrumentKey.volDelay;
|
|
774
783
|
const volAttack = volDelay + instrumentKey.volAttack;
|
|
775
784
|
const volHold = volAttack + instrumentKey.volHold;
|
|
776
785
|
const volDecay = volHold + instrumentKey.volDecay;
|
|
777
|
-
note.
|
|
786
|
+
note.volumeNode.gain
|
|
787
|
+
.cancelScheduledValues(startTime)
|
|
788
|
+
.setValueAtTime(0, startTime)
|
|
778
789
|
.setValueAtTime(1e-6, volDelay) // exponentialRampToValueAtTime() requires a non-zero value
|
|
779
790
|
.exponentialRampToValueAtTime(attackVolume, volAttack)
|
|
780
791
|
.setValueAtTime(attackVolume, volHold)
|
|
781
792
|
.linearRampToValueAtTime(sustainVolume, volDecay);
|
|
782
793
|
}
|
|
794
|
+
setPitch(note, semitoneOffset) {
|
|
795
|
+
const { instrumentKey, noteNumber, startTime } = note;
|
|
796
|
+
const modEnvToPitch = instrumentKey.modEnvToPitch / 100;
|
|
797
|
+
note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
|
|
798
|
+
if (modEnvToPitch === 0)
|
|
799
|
+
return;
|
|
800
|
+
const basePitch = note.bufferSource.playbackRate.value;
|
|
801
|
+
const peekPitch = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset + modEnvToPitch);
|
|
802
|
+
const modDelay = startTime + instrumentKey.modDelay;
|
|
803
|
+
const modAttack = modDelay + instrumentKey.modAttack;
|
|
804
|
+
const modHold = modAttack + instrumentKey.modHold;
|
|
805
|
+
const modDecay = modHold + instrumentKey.modDecay;
|
|
806
|
+
note.bufferSource.playbackRate.value
|
|
807
|
+
.setValueAtTime(basePitch, modDelay)
|
|
808
|
+
.exponentialRampToValueAtTime(peekPitch, modAttack)
|
|
809
|
+
.setValueAtTime(peekPitch, modHold)
|
|
810
|
+
.linearRampToValueAtTime(basePitch, modDecay);
|
|
811
|
+
}
|
|
812
|
+
clampCutoffFrequency(frequency) {
|
|
813
|
+
const minFrequency = 20; // min Hz of initialFilterFc
|
|
814
|
+
const maxFrequency = 20000; // max Hz of initialFilterFc
|
|
815
|
+
return Math.max(minFrequency, Math.min(frequency, maxFrequency));
|
|
816
|
+
}
|
|
783
817
|
setFilterEnvelope(channel, note) {
|
|
784
|
-
const { instrumentKey,
|
|
818
|
+
const { instrumentKey, noteNumber, startTime } = note;
|
|
785
819
|
const softPedalFactor = 1 -
|
|
786
820
|
(0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
|
|
787
|
-
const maxFreq = this.audioContext.sampleRate / 2;
|
|
788
821
|
const baseFreq = this.centToHz(instrumentKey.initialFilterFc) *
|
|
789
822
|
softPedalFactor;
|
|
790
823
|
const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc) * softPedalFactor;
|
|
791
|
-
const sustainFreq =
|
|
792
|
-
(peekFreq - baseFreq) * (1 - instrumentKey.modSustain)
|
|
824
|
+
const sustainFreq = baseFreq +
|
|
825
|
+
(peekFreq - baseFreq) * (1 - instrumentKey.modSustain);
|
|
826
|
+
const adjustedBaseFreq = this.clampCutoffFrequency(baseFreq);
|
|
827
|
+
const adjustedPeekFreq = this.clampCutoffFrequency(peekFreq);
|
|
828
|
+
const adjustedSustainFreq = this.clampCutoffFrequency(sustainFreq);
|
|
793
829
|
const modDelay = startTime + instrumentKey.modDelay;
|
|
794
830
|
const modAttack = modDelay + instrumentKey.modAttack;
|
|
795
831
|
const modHold = modAttack + instrumentKey.modHold;
|
|
796
832
|
const modDecay = modHold + instrumentKey.modDecay;
|
|
797
|
-
const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
|
|
798
|
-
const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
|
|
799
|
-
const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
|
|
800
|
-
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
801
|
-
type: "lowpass",
|
|
802
|
-
Q: instrumentKey.initialFilterQ / 10, // dB
|
|
803
|
-
frequency: adjustedBaseFreq,
|
|
804
|
-
});
|
|
805
833
|
note.filterNode.frequency
|
|
834
|
+
.cancelScheduledValues(startTime)
|
|
835
|
+
.setValueAtTime(adjustedBaseFreq, startTime)
|
|
806
836
|
.setValueAtTime(adjustedBaseFreq, modDelay)
|
|
807
837
|
.exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
|
|
808
838
|
.setValueAtTime(adjustedPeekFreq, modHold)
|
|
809
839
|
.linearRampToValueAtTime(adjustedSustainFreq, modDecay);
|
|
810
|
-
note.bufferSource.detune.setValueAtTime(note.bufferSource.detune.value + instrumentKey.modEnvToPitch, modDelay);
|
|
811
840
|
}
|
|
812
|
-
startModulation(channel, note,
|
|
841
|
+
startModulation(channel, note, startTime) {
|
|
813
842
|
const { instrumentKey } = note;
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
});
|
|
817
|
-
note.modLFO = new OscillatorNode(this.audioContext, {
|
|
843
|
+
const { modLfoToPitch, modLfoToVolume } = instrumentKey;
|
|
844
|
+
note.modulationLFO = new OscillatorNode(this.audioContext, {
|
|
818
845
|
frequency: this.centToHz(instrumentKey.freqModLFO),
|
|
819
846
|
});
|
|
820
|
-
note.
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
847
|
+
note.filterDepth = new GainNode(this.audioContext, {
|
|
848
|
+
gain: instrumentKey.modLfoToFilterFc,
|
|
849
|
+
});
|
|
850
|
+
const modulationDepth = Math.abs(modLfoToPitch) + channel.modulationDepth;
|
|
851
|
+
const modulationDepthSign = (0 < modLfoToPitch) ? 1 : -1;
|
|
852
|
+
note.modulationDepth = new GainNode(this.audioContext, {
|
|
853
|
+
gain: modulationDepth * modulationDepthSign,
|
|
854
|
+
});
|
|
855
|
+
const volumeDepth = this.cbToRatio(Math.abs(modLfoToVolume)) - 1;
|
|
856
|
+
const volumeDepthSign = (0 < modLfoToVolume) ? 1 : -1;
|
|
857
|
+
note.volumeDepth = new GainNode(this.audioContext, {
|
|
858
|
+
gain: volumeDepth * volumeDepthSign,
|
|
859
|
+
});
|
|
860
|
+
note.modulationLFO.start(startTime + instrumentKey.delayModLFO);
|
|
861
|
+
note.modulationLFO.connect(note.filterDepth);
|
|
862
|
+
note.filterDepth.connect(note.filterNode.frequency);
|
|
863
|
+
note.modulationLFO.connect(note.modulationDepth);
|
|
864
|
+
note.modulationDepth.connect(note.bufferSource.detune);
|
|
865
|
+
note.modulationLFO.connect(note.volumeDepth);
|
|
866
|
+
note.volumeDepth.connect(note.volumeNode.gain);
|
|
867
|
+
}
|
|
868
|
+
startVibrato(channel, note, startTime) {
|
|
869
|
+
const { instrumentKey } = note;
|
|
870
|
+
const { vibLfoToPitch } = instrumentKey;
|
|
871
|
+
note.vibratoLFO = new OscillatorNode(this.audioContext, {
|
|
872
|
+
frequency: this.centToHz(instrumentKey.freqVibLFO) *
|
|
873
|
+
channel.vibratoRate,
|
|
874
|
+
});
|
|
875
|
+
const vibratoDepth = Math.abs(vibLfoToPitch) * channel.vibratoDepth;
|
|
876
|
+
const vibratoDepthSign = 0 < vibLfoToPitch;
|
|
877
|
+
note.vibratoDepth = new GainNode(this.audioContext, {
|
|
878
|
+
gain: vibratoDepth * vibratoDepthSign,
|
|
879
|
+
});
|
|
880
|
+
note.vibratoLFO.start(startTime + instrumentKey.delayVibLFO * channel.vibratoDelay);
|
|
881
|
+
note.vibratoLFO.connect(note.vibratoDepth);
|
|
882
|
+
note.vibratoDepth.connect(note.bufferSource.detune);
|
|
825
883
|
}
|
|
826
884
|
async createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3) {
|
|
827
885
|
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
828
886
|
const note = new Note(noteNumber, velocity, startTime, instrumentKey);
|
|
829
887
|
note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
|
|
830
|
-
note.
|
|
888
|
+
note.volumeNode = new GainNode(this.audioContext);
|
|
889
|
+
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
890
|
+
type: "lowpass",
|
|
891
|
+
Q: instrumentKey.initialFilterQ / 10 * channel.filterResonance, // dB
|
|
892
|
+
});
|
|
831
893
|
this.setVolumeEnvelope(note);
|
|
832
894
|
this.setFilterEnvelope(channel, note);
|
|
833
|
-
if (channel.
|
|
834
|
-
|
|
835
|
-
|
|
895
|
+
if (0 < channel.vibratoDepth) {
|
|
896
|
+
this.startVibrato(channel, note, startTime);
|
|
897
|
+
}
|
|
898
|
+
if (0 < channel.modulationDepth) {
|
|
899
|
+
this.setPitch(note, semitoneOffset);
|
|
900
|
+
this.startModulation(channel, note, startTime);
|
|
901
|
+
}
|
|
902
|
+
else {
|
|
903
|
+
note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
|
|
836
904
|
}
|
|
837
905
|
if (this.mono && channel.currentBufferSource) {
|
|
838
906
|
channel.currentBufferSource.stop(startTime);
|
|
839
907
|
channel.currentBufferSource = note.bufferSource;
|
|
840
908
|
}
|
|
841
909
|
note.bufferSource.connect(note.filterNode);
|
|
842
|
-
note.filterNode.connect(note.
|
|
910
|
+
note.filterNode.connect(note.volumeNode);
|
|
843
911
|
note.bufferSource.start(startTime, instrumentKey.start / instrumentKey.sampleRate);
|
|
844
912
|
return note;
|
|
845
913
|
}
|
|
@@ -864,8 +932,8 @@ class MidyGM2 {
|
|
|
864
932
|
if (!instrumentKey)
|
|
865
933
|
return;
|
|
866
934
|
const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
|
|
867
|
-
note.
|
|
868
|
-
note.
|
|
935
|
+
note.volumeNode.connect(channel.gainL);
|
|
936
|
+
note.volumeNode.connect(channel.gainR);
|
|
869
937
|
if (channel.sostenutoPedal) {
|
|
870
938
|
channel.sostenutoNotes.set(noteNumber, note);
|
|
871
939
|
}
|
|
@@ -881,7 +949,7 @@ class MidyGM2 {
|
|
|
881
949
|
const now = this.audioContext.currentTime;
|
|
882
950
|
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now);
|
|
883
951
|
}
|
|
884
|
-
scheduleNoteRelease(channelNumber, noteNumber,
|
|
952
|
+
scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, stopPedal = false) {
|
|
885
953
|
const channel = this.channels[channelNumber];
|
|
886
954
|
if (stopPedal && channel.sustainPedal)
|
|
887
955
|
return;
|
|
@@ -896,20 +964,14 @@ class MidyGM2 {
|
|
|
896
964
|
continue;
|
|
897
965
|
if (note.ending)
|
|
898
966
|
continue;
|
|
899
|
-
const
|
|
900
|
-
|
|
901
|
-
note.instrumentKey.volRelease * velocityRate;
|
|
902
|
-
note.gainNode.gain
|
|
967
|
+
const volEndTime = stopTime + note.instrumentKey.volRelease;
|
|
968
|
+
note.volumeNode.gain
|
|
903
969
|
.cancelScheduledValues(stopTime)
|
|
904
970
|
.linearRampToValueAtTime(0, volEndTime);
|
|
905
|
-
const
|
|
906
|
-
const baseFreq = this.centToHz(note.instrumentKey.initialFilterFc);
|
|
907
|
-
const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
|
|
908
|
-
const modEndTime = stopTime +
|
|
909
|
-
note.instrumentKey.modRelease * velocityRate;
|
|
971
|
+
const modRelease = stopTime + note.instrumentKey.modRelease;
|
|
910
972
|
note.filterNode.frequency
|
|
911
973
|
.cancelScheduledValues(stopTime)
|
|
912
|
-
.linearRampToValueAtTime(
|
|
974
|
+
.linearRampToValueAtTime(0, modRelease);
|
|
913
975
|
note.ending = true;
|
|
914
976
|
this.scheduleTask(() => {
|
|
915
977
|
note.bufferSource.loop = false;
|
|
@@ -918,16 +980,18 @@ class MidyGM2 {
|
|
|
918
980
|
note.bufferSource.onended = () => {
|
|
919
981
|
scheduledNotes[i] = null;
|
|
920
982
|
note.bufferSource.disconnect();
|
|
983
|
+
note.volumeNode.disconnect();
|
|
921
984
|
note.filterNode.disconnect();
|
|
922
|
-
note.
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
985
|
+
if (note.volumeDepth)
|
|
986
|
+
note.volumeDepth.disconnect();
|
|
987
|
+
if (note.modulationDepth)
|
|
988
|
+
note.modulationDepth.disconnect();
|
|
989
|
+
if (note.modulationLFO)
|
|
990
|
+
note.modulationLFO.stop();
|
|
991
|
+
if (note.vibratoDepth)
|
|
992
|
+
note.vibratoDepth.disconnect();
|
|
993
|
+
if (note.vibratoLFO)
|
|
994
|
+
note.vibratoLFO.stop();
|
|
931
995
|
resolve();
|
|
932
996
|
};
|
|
933
997
|
note.bufferSource.stop(volEndTime);
|
|
@@ -943,14 +1007,15 @@ class MidyGM2 {
|
|
|
943
1007
|
const channel = this.channels[channelNumber];
|
|
944
1008
|
const promises = [];
|
|
945
1009
|
channel.sustainPedal = false;
|
|
946
|
-
channel.scheduledNotes.forEach((
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
1010
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
1011
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
1012
|
+
const note = noteList[i];
|
|
1013
|
+
if (!note)
|
|
1014
|
+
continue;
|
|
1015
|
+
const { noteNumber } = note;
|
|
1016
|
+
const promise = this.releaseNote(channelNumber, noteNumber, velocity);
|
|
1017
|
+
promises.push(promise);
|
|
1018
|
+
}
|
|
954
1019
|
});
|
|
955
1020
|
return promises;
|
|
956
1021
|
}
|
|
@@ -1000,8 +1065,8 @@ class MidyGM2 {
|
|
|
1000
1065
|
const activeNotes = this.getActiveNotes(channel, now);
|
|
1001
1066
|
if (channel.channelPressure.amplitudeControl !== 1) {
|
|
1002
1067
|
activeNotes.forEach((activeNote) => {
|
|
1003
|
-
const gain = activeNote.
|
|
1004
|
-
activeNote.
|
|
1068
|
+
const gain = activeNote.volumeNode.gain.value;
|
|
1069
|
+
activeNote.volumeNode.gain
|
|
1005
1070
|
.cancelScheduledValues(now)
|
|
1006
1071
|
.setValueAtTime(gain * pressure, now);
|
|
1007
1072
|
});
|
|
@@ -1024,7 +1089,7 @@ class MidyGM2 {
|
|
|
1024
1089
|
case 0:
|
|
1025
1090
|
return this.setBankMSB(channelNumber, value);
|
|
1026
1091
|
case 1:
|
|
1027
|
-
return this.
|
|
1092
|
+
return this.setModulationDepth(channelNumber, value);
|
|
1028
1093
|
case 5:
|
|
1029
1094
|
return this.setPortamentoTime(channelNumber, value);
|
|
1030
1095
|
case 6:
|
|
@@ -1078,20 +1143,25 @@ class MidyGM2 {
|
|
|
1078
1143
|
}
|
|
1079
1144
|
updateModulation(channel) {
|
|
1080
1145
|
const now = this.audioContext.currentTime;
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1146
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
1147
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
1148
|
+
const note = noteList[i];
|
|
1149
|
+
if (!note)
|
|
1150
|
+
continue;
|
|
1151
|
+
if (note.modulationDepth) {
|
|
1152
|
+
note.modulationDepth.gain.setValueAtTime(channel.modulationDepth, now);
|
|
1153
|
+
}
|
|
1154
|
+
else {
|
|
1155
|
+
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
1156
|
+
this.setPitch(note, semitoneOffset);
|
|
1157
|
+
this.startModulation(channel, note, now);
|
|
1158
|
+
}
|
|
1089
1159
|
}
|
|
1090
1160
|
});
|
|
1091
1161
|
}
|
|
1092
|
-
|
|
1162
|
+
setModulationDepth(channelNumber, modulation) {
|
|
1093
1163
|
const channel = this.channels[channelNumber];
|
|
1094
|
-
channel.
|
|
1164
|
+
channel.modulationDepth = (modulation / 127) * channel.modulationDepthRange;
|
|
1095
1165
|
this.updateModulation(channel);
|
|
1096
1166
|
}
|
|
1097
1167
|
setPortamentoTime(channelNumber, portamentoTime) {
|
|
@@ -1249,13 +1319,17 @@ class MidyGM2 {
|
|
|
1249
1319
|
}
|
|
1250
1320
|
updateDetune(channel, detuneChange) {
|
|
1251
1321
|
const now = this.audioContext.currentTime;
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
.
|
|
1322
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
1323
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
1324
|
+
const note = noteList[i];
|
|
1325
|
+
if (!note)
|
|
1326
|
+
continue;
|
|
1327
|
+
const { bufferSource } = note;
|
|
1328
|
+
const detune = bufferSource.detune.value + detuneChange;
|
|
1329
|
+
bufferSource.detune
|
|
1330
|
+
.cancelScheduledValues(now)
|
|
1331
|
+
.setValueAtTime(detune, now);
|
|
1332
|
+
}
|
|
1259
1333
|
});
|
|
1260
1334
|
}
|
|
1261
1335
|
handlePitchBendRangeRPN(channelNumber) {
|
|
@@ -1301,47 +1375,23 @@ class MidyGM2 {
|
|
|
1301
1375
|
handleModulationDepthRangeRPN(channelNumber) {
|
|
1302
1376
|
const channel = this.channels[channelNumber];
|
|
1303
1377
|
this.limitData(channel, 0, 127, 0, 127);
|
|
1304
|
-
const modulationDepthRange = dataMSB + dataLSB / 128;
|
|
1378
|
+
const modulationDepthRange = (dataMSB + dataLSB / 128) * 100;
|
|
1305
1379
|
this.setModulationDepthRange(channelNumber, modulationDepthRange);
|
|
1306
1380
|
}
|
|
1307
1381
|
setModulationDepthRange(channelNumber, modulationDepthRange) {
|
|
1308
1382
|
const channel = this.channels[channelNumber];
|
|
1309
1383
|
channel.modulationDepthRange = modulationDepthRange;
|
|
1310
|
-
channel.
|
|
1384
|
+
channel.modulationDepth = (modulation / 127) * modulationDepthRange;
|
|
1311
1385
|
this.updateModulation(channel);
|
|
1312
1386
|
}
|
|
1313
1387
|
allSoundOff(channelNumber) {
|
|
1314
|
-
|
|
1315
|
-
const channel = this.channels[channelNumber];
|
|
1316
|
-
const velocity = 0;
|
|
1317
|
-
const stopPedal = true;
|
|
1318
|
-
const promises = [];
|
|
1319
|
-
channel.scheduledNotes.forEach((noteList) => {
|
|
1320
|
-
const activeNote = this.getActiveNote(noteList, now);
|
|
1321
|
-
if (activeNote) {
|
|
1322
|
-
const notePromise = this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, stopPedal);
|
|
1323
|
-
promises.push(notePromise);
|
|
1324
|
-
}
|
|
1325
|
-
});
|
|
1326
|
-
return promises;
|
|
1388
|
+
return this.stopChannelNotes(channelNumber, 0, true);
|
|
1327
1389
|
}
|
|
1328
1390
|
resetAllControllers(channelNumber) {
|
|
1329
1391
|
Object.assign(this.channels[channelNumber], this.effectSettings);
|
|
1330
1392
|
}
|
|
1331
1393
|
allNotesOff(channelNumber) {
|
|
1332
|
-
|
|
1333
|
-
const channel = this.channels[channelNumber];
|
|
1334
|
-
const velocity = 0;
|
|
1335
|
-
const stopPedal = false;
|
|
1336
|
-
const promises = [];
|
|
1337
|
-
channel.scheduledNotes.forEach((noteList) => {
|
|
1338
|
-
const activeNote = this.getActiveNote(noteList, now);
|
|
1339
|
-
if (activeNote) {
|
|
1340
|
-
const notePromise = this.scheduleNoteRelease(channelNumber, activeNote.noteNumber, velocity, now, stopPedal);
|
|
1341
|
-
promises.push(notePromise);
|
|
1342
|
-
}
|
|
1343
|
-
});
|
|
1344
|
-
return promises;
|
|
1394
|
+
return this.stopChannelNotes(channelNumber, 0, false);
|
|
1345
1395
|
}
|
|
1346
1396
|
omniOff() {
|
|
1347
1397
|
this.omni = false;
|
|
@@ -1702,6 +1752,9 @@ Object.defineProperty(MidyGM2, "channelSettings", {
|
|
|
1702
1752
|
portamentoTime: 0,
|
|
1703
1753
|
reverbSendLevel: 0,
|
|
1704
1754
|
chorusSendLevel: 0,
|
|
1755
|
+
vibratoRate: 1,
|
|
1756
|
+
vibratoDepth: 1,
|
|
1757
|
+
vibratoDelay: 1,
|
|
1705
1758
|
bank: 121 * 128,
|
|
1706
1759
|
bankMSB: 121,
|
|
1707
1760
|
bankLSB: 0,
|
|
@@ -1711,7 +1764,7 @@ Object.defineProperty(MidyGM2, "channelSettings", {
|
|
|
1711
1764
|
pitchBend: 0,
|
|
1712
1765
|
fineTuning: 0, // cb
|
|
1713
1766
|
coarseTuning: 0, // cb
|
|
1714
|
-
modulationDepthRange:
|
|
1767
|
+
modulationDepthRange: 50, // cent
|
|
1715
1768
|
}
|
|
1716
1769
|
});
|
|
1717
1770
|
Object.defineProperty(MidyGM2, "effectSettings", {
|
|
@@ -1720,7 +1773,7 @@ Object.defineProperty(MidyGM2, "effectSettings", {
|
|
|
1720
1773
|
writable: true,
|
|
1721
1774
|
value: {
|
|
1722
1775
|
expression: 1,
|
|
1723
|
-
|
|
1776
|
+
modulationDepth: 0,
|
|
1724
1777
|
sustainPedal: false,
|
|
1725
1778
|
portamento: false,
|
|
1726
1779
|
sostenutoPedal: false,
|
package/script/midy-GMLite.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export class MidyGMLite {
|
|
|
11
11
|
};
|
|
12
12
|
static effectSettings: {
|
|
13
13
|
expression: number;
|
|
14
|
-
|
|
14
|
+
modulationDepth: number;
|
|
15
15
|
sustainPedal: boolean;
|
|
16
16
|
rpnMSB: number;
|
|
17
17
|
rpnLSB: number;
|
|
@@ -60,7 +60,8 @@ export class MidyGMLite {
|
|
|
60
60
|
instruments: Set<any>;
|
|
61
61
|
timeline: any[];
|
|
62
62
|
};
|
|
63
|
-
|
|
63
|
+
stopChannelNotes(channelNumber: any, velocity: any, stopPedal: any): Promise<void>;
|
|
64
|
+
stopNotes(velocity: any, stopPedal: any): Promise<any[]>;
|
|
64
65
|
start(): Promise<void>;
|
|
65
66
|
stop(): void;
|
|
66
67
|
pause(): void;
|
|
@@ -75,21 +76,23 @@ export class MidyGMLite {
|
|
|
75
76
|
calcSemitoneOffset(channel: any): number;
|
|
76
77
|
calcPlaybackRate(instrumentKey: any, noteNumber: any, semitoneOffset: any): number;
|
|
77
78
|
setVolumeEnvelope(note: any): void;
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
setPitch(note: any, semitoneOffset: any): void;
|
|
80
|
+
clampCutoffFrequency(frequency: any): number;
|
|
81
|
+
setFilterEnvelope(note: any): void;
|
|
82
|
+
startModulation(channel: any, note: any, startTime: any): void;
|
|
80
83
|
createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
|
|
81
84
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
82
85
|
noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
|
|
83
|
-
scheduleNoteRelease(channelNumber: any, noteNumber: any,
|
|
86
|
+
scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
|
|
84
87
|
releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
|
|
85
88
|
releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
|
|
86
|
-
handleMIDIMessage(statusByte: any, data1: any, data2: any): void |
|
|
89
|
+
handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<any>;
|
|
87
90
|
handleProgramChange(channelNumber: any, program: any): void;
|
|
88
91
|
handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
|
|
89
92
|
setPitchBend(channelNumber: any, pitchBend: any): void;
|
|
90
|
-
handleControlChange(channelNumber: any, controller: any, value: any): void |
|
|
93
|
+
handleControlChange(channelNumber: any, controller: any, value: any): void | Promise<void>;
|
|
91
94
|
updateModulation(channel: any): void;
|
|
92
|
-
|
|
95
|
+
setModulationDepth(channelNumber: any, modulation: any): void;
|
|
93
96
|
setVolume(channelNumber: any, volume: any): void;
|
|
94
97
|
panToGain(pan: any): {
|
|
95
98
|
gainLeft: number;
|
|
@@ -107,9 +110,9 @@ export class MidyGMLite {
|
|
|
107
110
|
updateDetune(channel: any, detuneChange: any): void;
|
|
108
111
|
handlePitchBendRangeRPN(channelNumber: any): void;
|
|
109
112
|
setPitchBendRange(channelNumber: any, pitchBendRange: any): void;
|
|
110
|
-
allSoundOff(channelNumber: any):
|
|
113
|
+
allSoundOff(channelNumber: any): Promise<void>;
|
|
111
114
|
resetAllControllers(channelNumber: any): void;
|
|
112
|
-
allNotesOff(channelNumber: any):
|
|
115
|
+
allNotesOff(channelNumber: any): Promise<void>;
|
|
113
116
|
handleUniversalNonRealTimeExclusiveMessage(data: any): void;
|
|
114
117
|
GM1SystemOn(): void;
|
|
115
118
|
handleUniversalRealTimeExclusiveMessage(data: any): void;
|
|
@@ -122,10 +125,11 @@ export class MidyGMLite {
|
|
|
122
125
|
declare class Note {
|
|
123
126
|
constructor(noteNumber: any, velocity: any, startTime: any, instrumentKey: any);
|
|
124
127
|
bufferSource: any;
|
|
125
|
-
gainNode: any;
|
|
126
128
|
filterNode: any;
|
|
127
|
-
|
|
128
|
-
|
|
129
|
+
volumeNode: any;
|
|
130
|
+
volumeDepth: any;
|
|
131
|
+
modulationLFO: any;
|
|
132
|
+
modulationDepth: any;
|
|
129
133
|
noteNumber: any;
|
|
130
134
|
velocity: any;
|
|
131
135
|
startTime: any;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAsBA;IAmBE;;;;;;;;;MASE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IA5CD,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAuBhB,kBAAgC;IAChC,gBAA4C;IAC5C,gBAAiD;IAKnD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAUC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EA+CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA8DC;IAED,mFAmBC;IAED,yDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,2BAEC;IAED,4BAEC;IAED,yCAEC;IAED,mFAGC;IAED,mCAeC;IAED,+CAwBC;IAED,6CAIC;IAED,mCAsBC;IAED,+DA0BC;IAED,wHAmCC;IAED,kGA6BC;IAED,0EAGC;IAED,uIAyCC;IAED,0FAGC;IAED,kEAeC;IAED,gFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,uDAOC;IAED,2FA+BC;IAED,qCAkBC;IAED,8DAIC;IACD,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,mDAGC;IAED,sCAUC;IAED,sDAMC;IAED,oCAYC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,oDAaC;IAED,kDAKC;IAED,iEAOC;IAED,+CAEC;IAED,8CAEC;IAED,+CAEC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAl/BD;IAQE,gFAKC;IAZD,kBAAa;IACb,gBAAW;IACX,gBAAW;IACX,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
|