@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/esm/midy-GM2.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parseMidi } from "./deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js";
|
|
2
|
-
import { parse, SoundFont, } from "./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.
|
|
2
|
+
import { parse, SoundFont, } from "./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.js";
|
|
3
3
|
class Note {
|
|
4
4
|
constructor(noteNumber, velocity, startTime, instrumentKey) {
|
|
5
5
|
Object.defineProperty(this, "bufferSource", {
|
|
@@ -8,37 +8,43 @@ class Note {
|
|
|
8
8
|
writable: true,
|
|
9
9
|
value: void 0
|
|
10
10
|
});
|
|
11
|
-
Object.defineProperty(this, "
|
|
11
|
+
Object.defineProperty(this, "filterNode", {
|
|
12
12
|
enumerable: true,
|
|
13
13
|
configurable: true,
|
|
14
14
|
writable: true,
|
|
15
15
|
value: void 0
|
|
16
16
|
});
|
|
17
|
-
Object.defineProperty(this, "
|
|
17
|
+
Object.defineProperty(this, "volumeNode", {
|
|
18
18
|
enumerable: true,
|
|
19
19
|
configurable: true,
|
|
20
20
|
writable: true,
|
|
21
21
|
value: void 0
|
|
22
22
|
});
|
|
23
|
-
Object.defineProperty(this, "
|
|
23
|
+
Object.defineProperty(this, "volumeDepth", {
|
|
24
24
|
enumerable: true,
|
|
25
25
|
configurable: true,
|
|
26
26
|
writable: true,
|
|
27
27
|
value: void 0
|
|
28
28
|
});
|
|
29
|
-
Object.defineProperty(this, "
|
|
29
|
+
Object.defineProperty(this, "modulationLFO", {
|
|
30
30
|
enumerable: true,
|
|
31
31
|
configurable: true,
|
|
32
32
|
writable: true,
|
|
33
33
|
value: void 0
|
|
34
34
|
});
|
|
35
|
-
Object.defineProperty(this, "
|
|
35
|
+
Object.defineProperty(this, "modulationDepth", {
|
|
36
36
|
enumerable: true,
|
|
37
37
|
configurable: true,
|
|
38
38
|
writable: true,
|
|
39
39
|
value: void 0
|
|
40
40
|
});
|
|
41
|
-
Object.defineProperty(this, "
|
|
41
|
+
Object.defineProperty(this, "vibratoLFO", {
|
|
42
|
+
enumerable: true,
|
|
43
|
+
configurable: true,
|
|
44
|
+
writable: true,
|
|
45
|
+
value: void 0
|
|
46
|
+
});
|
|
47
|
+
Object.defineProperty(this, "vibratoDepth", {
|
|
42
48
|
enumerable: true,
|
|
43
49
|
configurable: true,
|
|
44
50
|
writable: true,
|
|
@@ -404,7 +410,7 @@ export class MidyGM2 {
|
|
|
404
410
|
const t = this.audioContext.currentTime + offset;
|
|
405
411
|
queueIndex = await this.scheduleTimelineEvents(t, offset, queueIndex);
|
|
406
412
|
if (this.isPausing) {
|
|
407
|
-
await this.stopNotes();
|
|
413
|
+
await this.stopNotes(0, true);
|
|
408
414
|
this.notePromises = [];
|
|
409
415
|
resolve();
|
|
410
416
|
this.isPausing = false;
|
|
@@ -412,7 +418,7 @@ export class MidyGM2 {
|
|
|
412
418
|
return;
|
|
413
419
|
}
|
|
414
420
|
else if (this.isStopping) {
|
|
415
|
-
await this.stopNotes();
|
|
421
|
+
await this.stopNotes(0, true);
|
|
416
422
|
this.notePromises = [];
|
|
417
423
|
resolve();
|
|
418
424
|
this.isStopping = false;
|
|
@@ -420,7 +426,7 @@ export class MidyGM2 {
|
|
|
420
426
|
return;
|
|
421
427
|
}
|
|
422
428
|
else if (this.isSeeking) {
|
|
423
|
-
this.stopNotes();
|
|
429
|
+
this.stopNotes(0, true);
|
|
424
430
|
this.startTime = this.audioContext.currentTime;
|
|
425
431
|
queueIndex = this.getQueueIndex(this.resumeTime);
|
|
426
432
|
offset = this.resumeTime - this.startTime;
|
|
@@ -535,21 +541,25 @@ export class MidyGM2 {
|
|
|
535
541
|
}
|
|
536
542
|
return { instruments, timeline };
|
|
537
543
|
}
|
|
538
|
-
|
|
544
|
+
async stopChannelNotes(channelNumber, velocity, stopPedal) {
|
|
539
545
|
const now = this.audioContext.currentTime;
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
});
|
|
550
|
-
});
|
|
551
|
-
channel.scheduledNotes.clear();
|
|
546
|
+
const channel = this.channels[channelNumber];
|
|
547
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
548
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
549
|
+
const note = noteList[i];
|
|
550
|
+
if (!note)
|
|
551
|
+
continue;
|
|
552
|
+
const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, stopPedal);
|
|
553
|
+
this.notePromises.push(promise);
|
|
554
|
+
}
|
|
552
555
|
});
|
|
556
|
+
channel.scheduledNotes.clear();
|
|
557
|
+
await Promise.all(this.notePromises);
|
|
558
|
+
}
|
|
559
|
+
stopNotes(velocity, stopPedal) {
|
|
560
|
+
for (let i = 0; i < this.channels.length; i++) {
|
|
561
|
+
this.stopChannelNotes(i, velocity, stopPedal);
|
|
562
|
+
}
|
|
553
563
|
return Promise.all(this.notePromises);
|
|
554
564
|
}
|
|
555
565
|
async start() {
|
|
@@ -764,79 +774,137 @@ export class MidyGM2 {
|
|
|
764
774
|
}
|
|
765
775
|
setVolumeEnvelope(note) {
|
|
766
776
|
const { instrumentKey, startTime } = note;
|
|
767
|
-
note.gainNode = new GainNode(this.audioContext, { gain: 0 });
|
|
768
777
|
const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
|
|
769
778
|
const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
|
|
770
779
|
const volDelay = startTime + instrumentKey.volDelay;
|
|
771
780
|
const volAttack = volDelay + instrumentKey.volAttack;
|
|
772
781
|
const volHold = volAttack + instrumentKey.volHold;
|
|
773
782
|
const volDecay = volHold + instrumentKey.volDecay;
|
|
774
|
-
note.
|
|
783
|
+
note.volumeNode.gain
|
|
784
|
+
.cancelScheduledValues(startTime)
|
|
785
|
+
.setValueAtTime(0, startTime)
|
|
775
786
|
.setValueAtTime(1e-6, volDelay) // exponentialRampToValueAtTime() requires a non-zero value
|
|
776
787
|
.exponentialRampToValueAtTime(attackVolume, volAttack)
|
|
777
788
|
.setValueAtTime(attackVolume, volHold)
|
|
778
789
|
.linearRampToValueAtTime(sustainVolume, volDecay);
|
|
779
790
|
}
|
|
791
|
+
setPitch(note, semitoneOffset) {
|
|
792
|
+
const { instrumentKey, noteNumber, startTime } = note;
|
|
793
|
+
const modEnvToPitch = instrumentKey.modEnvToPitch / 100;
|
|
794
|
+
note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
|
|
795
|
+
if (modEnvToPitch === 0)
|
|
796
|
+
return;
|
|
797
|
+
const basePitch = note.bufferSource.playbackRate.value;
|
|
798
|
+
const peekPitch = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset + modEnvToPitch);
|
|
799
|
+
const modDelay = startTime + instrumentKey.modDelay;
|
|
800
|
+
const modAttack = modDelay + instrumentKey.modAttack;
|
|
801
|
+
const modHold = modAttack + instrumentKey.modHold;
|
|
802
|
+
const modDecay = modHold + instrumentKey.modDecay;
|
|
803
|
+
note.bufferSource.playbackRate.value
|
|
804
|
+
.setValueAtTime(basePitch, modDelay)
|
|
805
|
+
.exponentialRampToValueAtTime(peekPitch, modAttack)
|
|
806
|
+
.setValueAtTime(peekPitch, modHold)
|
|
807
|
+
.linearRampToValueAtTime(basePitch, modDecay);
|
|
808
|
+
}
|
|
809
|
+
clampCutoffFrequency(frequency) {
|
|
810
|
+
const minFrequency = 20; // min Hz of initialFilterFc
|
|
811
|
+
const maxFrequency = 20000; // max Hz of initialFilterFc
|
|
812
|
+
return Math.max(minFrequency, Math.min(frequency, maxFrequency));
|
|
813
|
+
}
|
|
780
814
|
setFilterEnvelope(channel, note) {
|
|
781
|
-
const { instrumentKey,
|
|
815
|
+
const { instrumentKey, noteNumber, startTime } = note;
|
|
782
816
|
const softPedalFactor = 1 -
|
|
783
817
|
(0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
|
|
784
|
-
const maxFreq = this.audioContext.sampleRate / 2;
|
|
785
818
|
const baseFreq = this.centToHz(instrumentKey.initialFilterFc) *
|
|
786
819
|
softPedalFactor;
|
|
787
820
|
const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc) * softPedalFactor;
|
|
788
|
-
const sustainFreq =
|
|
789
|
-
(peekFreq - baseFreq) * (1 - instrumentKey.modSustain)
|
|
821
|
+
const sustainFreq = baseFreq +
|
|
822
|
+
(peekFreq - baseFreq) * (1 - instrumentKey.modSustain);
|
|
823
|
+
const adjustedBaseFreq = this.clampCutoffFrequency(baseFreq);
|
|
824
|
+
const adjustedPeekFreq = this.clampCutoffFrequency(peekFreq);
|
|
825
|
+
const adjustedSustainFreq = this.clampCutoffFrequency(sustainFreq);
|
|
790
826
|
const modDelay = startTime + instrumentKey.modDelay;
|
|
791
827
|
const modAttack = modDelay + instrumentKey.modAttack;
|
|
792
828
|
const modHold = modAttack + instrumentKey.modHold;
|
|
793
829
|
const modDecay = modHold + instrumentKey.modDecay;
|
|
794
|
-
const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
|
|
795
|
-
const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
|
|
796
|
-
const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
|
|
797
|
-
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
798
|
-
type: "lowpass",
|
|
799
|
-
Q: instrumentKey.initialFilterQ / 10, // dB
|
|
800
|
-
frequency: adjustedBaseFreq,
|
|
801
|
-
});
|
|
802
830
|
note.filterNode.frequency
|
|
831
|
+
.cancelScheduledValues(startTime)
|
|
832
|
+
.setValueAtTime(adjustedBaseFreq, startTime)
|
|
803
833
|
.setValueAtTime(adjustedBaseFreq, modDelay)
|
|
804
834
|
.exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
|
|
805
835
|
.setValueAtTime(adjustedPeekFreq, modHold)
|
|
806
836
|
.linearRampToValueAtTime(adjustedSustainFreq, modDecay);
|
|
807
|
-
note.bufferSource.detune.setValueAtTime(note.bufferSource.detune.value + instrumentKey.modEnvToPitch, modDelay);
|
|
808
837
|
}
|
|
809
|
-
startModulation(channel, note,
|
|
838
|
+
startModulation(channel, note, startTime) {
|
|
810
839
|
const { instrumentKey } = note;
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
});
|
|
814
|
-
note.modLFO = new OscillatorNode(this.audioContext, {
|
|
840
|
+
const { modLfoToPitch, modLfoToVolume } = instrumentKey;
|
|
841
|
+
note.modulationLFO = new OscillatorNode(this.audioContext, {
|
|
815
842
|
frequency: this.centToHz(instrumentKey.freqModLFO),
|
|
816
843
|
});
|
|
817
|
-
note.
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
844
|
+
note.filterDepth = new GainNode(this.audioContext, {
|
|
845
|
+
gain: instrumentKey.modLfoToFilterFc,
|
|
846
|
+
});
|
|
847
|
+
const modulationDepth = Math.abs(modLfoToPitch) + channel.modulationDepth;
|
|
848
|
+
const modulationDepthSign = (0 < modLfoToPitch) ? 1 : -1;
|
|
849
|
+
note.modulationDepth = new GainNode(this.audioContext, {
|
|
850
|
+
gain: modulationDepth * modulationDepthSign,
|
|
851
|
+
});
|
|
852
|
+
const volumeDepth = this.cbToRatio(Math.abs(modLfoToVolume)) - 1;
|
|
853
|
+
const volumeDepthSign = (0 < modLfoToVolume) ? 1 : -1;
|
|
854
|
+
note.volumeDepth = new GainNode(this.audioContext, {
|
|
855
|
+
gain: volumeDepth * volumeDepthSign,
|
|
856
|
+
});
|
|
857
|
+
note.modulationLFO.start(startTime + instrumentKey.delayModLFO);
|
|
858
|
+
note.modulationLFO.connect(note.filterDepth);
|
|
859
|
+
note.filterDepth.connect(note.filterNode.frequency);
|
|
860
|
+
note.modulationLFO.connect(note.modulationDepth);
|
|
861
|
+
note.modulationDepth.connect(note.bufferSource.detune);
|
|
862
|
+
note.modulationLFO.connect(note.volumeDepth);
|
|
863
|
+
note.volumeDepth.connect(note.volumeNode.gain);
|
|
864
|
+
}
|
|
865
|
+
startVibrato(channel, note, startTime) {
|
|
866
|
+
const { instrumentKey } = note;
|
|
867
|
+
const { vibLfoToPitch } = instrumentKey;
|
|
868
|
+
note.vibratoLFO = new OscillatorNode(this.audioContext, {
|
|
869
|
+
frequency: this.centToHz(instrumentKey.freqVibLFO) *
|
|
870
|
+
channel.vibratoRate,
|
|
871
|
+
});
|
|
872
|
+
const vibratoDepth = Math.abs(vibLfoToPitch) * channel.vibratoDepth;
|
|
873
|
+
const vibratoDepthSign = 0 < vibLfoToPitch;
|
|
874
|
+
note.vibratoDepth = new GainNode(this.audioContext, {
|
|
875
|
+
gain: vibratoDepth * vibratoDepthSign,
|
|
876
|
+
});
|
|
877
|
+
note.vibratoLFO.start(startTime + instrumentKey.delayVibLFO * channel.vibratoDelay);
|
|
878
|
+
note.vibratoLFO.connect(note.vibratoDepth);
|
|
879
|
+
note.vibratoDepth.connect(note.bufferSource.detune);
|
|
822
880
|
}
|
|
823
881
|
async createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3) {
|
|
824
882
|
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
825
883
|
const note = new Note(noteNumber, velocity, startTime, instrumentKey);
|
|
826
884
|
note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
|
|
827
|
-
note.
|
|
885
|
+
note.volumeNode = new GainNode(this.audioContext);
|
|
886
|
+
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
887
|
+
type: "lowpass",
|
|
888
|
+
Q: instrumentKey.initialFilterQ / 10 * channel.filterResonance, // dB
|
|
889
|
+
});
|
|
828
890
|
this.setVolumeEnvelope(note);
|
|
829
891
|
this.setFilterEnvelope(channel, note);
|
|
830
|
-
if (channel.
|
|
831
|
-
|
|
832
|
-
|
|
892
|
+
if (0 < channel.vibratoDepth) {
|
|
893
|
+
this.startVibrato(channel, note, startTime);
|
|
894
|
+
}
|
|
895
|
+
if (0 < channel.modulationDepth) {
|
|
896
|
+
this.setPitch(note, semitoneOffset);
|
|
897
|
+
this.startModulation(channel, note, startTime);
|
|
898
|
+
}
|
|
899
|
+
else {
|
|
900
|
+
note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
|
|
833
901
|
}
|
|
834
902
|
if (this.mono && channel.currentBufferSource) {
|
|
835
903
|
channel.currentBufferSource.stop(startTime);
|
|
836
904
|
channel.currentBufferSource = note.bufferSource;
|
|
837
905
|
}
|
|
838
906
|
note.bufferSource.connect(note.filterNode);
|
|
839
|
-
note.filterNode.connect(note.
|
|
907
|
+
note.filterNode.connect(note.volumeNode);
|
|
840
908
|
note.bufferSource.start(startTime, instrumentKey.start / instrumentKey.sampleRate);
|
|
841
909
|
return note;
|
|
842
910
|
}
|
|
@@ -861,8 +929,8 @@ export class MidyGM2 {
|
|
|
861
929
|
if (!instrumentKey)
|
|
862
930
|
return;
|
|
863
931
|
const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
|
|
864
|
-
note.
|
|
865
|
-
note.
|
|
932
|
+
note.volumeNode.connect(channel.gainL);
|
|
933
|
+
note.volumeNode.connect(channel.gainR);
|
|
866
934
|
if (channel.sostenutoPedal) {
|
|
867
935
|
channel.sostenutoNotes.set(noteNumber, note);
|
|
868
936
|
}
|
|
@@ -878,7 +946,7 @@ export class MidyGM2 {
|
|
|
878
946
|
const now = this.audioContext.currentTime;
|
|
879
947
|
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now);
|
|
880
948
|
}
|
|
881
|
-
scheduleNoteRelease(channelNumber, noteNumber,
|
|
949
|
+
scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, stopPedal = false) {
|
|
882
950
|
const channel = this.channels[channelNumber];
|
|
883
951
|
if (stopPedal && channel.sustainPedal)
|
|
884
952
|
return;
|
|
@@ -893,20 +961,14 @@ export class MidyGM2 {
|
|
|
893
961
|
continue;
|
|
894
962
|
if (note.ending)
|
|
895
963
|
continue;
|
|
896
|
-
const
|
|
897
|
-
|
|
898
|
-
note.instrumentKey.volRelease * velocityRate;
|
|
899
|
-
note.gainNode.gain
|
|
964
|
+
const volEndTime = stopTime + note.instrumentKey.volRelease;
|
|
965
|
+
note.volumeNode.gain
|
|
900
966
|
.cancelScheduledValues(stopTime)
|
|
901
967
|
.linearRampToValueAtTime(0, volEndTime);
|
|
902
|
-
const
|
|
903
|
-
const baseFreq = this.centToHz(note.instrumentKey.initialFilterFc);
|
|
904
|
-
const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
|
|
905
|
-
const modEndTime = stopTime +
|
|
906
|
-
note.instrumentKey.modRelease * velocityRate;
|
|
968
|
+
const modRelease = stopTime + note.instrumentKey.modRelease;
|
|
907
969
|
note.filterNode.frequency
|
|
908
970
|
.cancelScheduledValues(stopTime)
|
|
909
|
-
.linearRampToValueAtTime(
|
|
971
|
+
.linearRampToValueAtTime(0, modRelease);
|
|
910
972
|
note.ending = true;
|
|
911
973
|
this.scheduleTask(() => {
|
|
912
974
|
note.bufferSource.loop = false;
|
|
@@ -915,16 +977,18 @@ export class MidyGM2 {
|
|
|
915
977
|
note.bufferSource.onended = () => {
|
|
916
978
|
scheduledNotes[i] = null;
|
|
917
979
|
note.bufferSource.disconnect();
|
|
980
|
+
note.volumeNode.disconnect();
|
|
918
981
|
note.filterNode.disconnect();
|
|
919
|
-
note.
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
982
|
+
if (note.volumeDepth)
|
|
983
|
+
note.volumeDepth.disconnect();
|
|
984
|
+
if (note.modulationDepth)
|
|
985
|
+
note.modulationDepth.disconnect();
|
|
986
|
+
if (note.modulationLFO)
|
|
987
|
+
note.modulationLFO.stop();
|
|
988
|
+
if (note.vibratoDepth)
|
|
989
|
+
note.vibratoDepth.disconnect();
|
|
990
|
+
if (note.vibratoLFO)
|
|
991
|
+
note.vibratoLFO.stop();
|
|
928
992
|
resolve();
|
|
929
993
|
};
|
|
930
994
|
note.bufferSource.stop(volEndTime);
|
|
@@ -940,14 +1004,15 @@ export class MidyGM2 {
|
|
|
940
1004
|
const channel = this.channels[channelNumber];
|
|
941
1005
|
const promises = [];
|
|
942
1006
|
channel.sustainPedal = false;
|
|
943
|
-
channel.scheduledNotes.forEach((
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
1007
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
1008
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
1009
|
+
const note = noteList[i];
|
|
1010
|
+
if (!note)
|
|
1011
|
+
continue;
|
|
1012
|
+
const { noteNumber } = note;
|
|
1013
|
+
const promise = this.releaseNote(channelNumber, noteNumber, velocity);
|
|
1014
|
+
promises.push(promise);
|
|
1015
|
+
}
|
|
951
1016
|
});
|
|
952
1017
|
return promises;
|
|
953
1018
|
}
|
|
@@ -997,8 +1062,8 @@ export class MidyGM2 {
|
|
|
997
1062
|
const activeNotes = this.getActiveNotes(channel, now);
|
|
998
1063
|
if (channel.channelPressure.amplitudeControl !== 1) {
|
|
999
1064
|
activeNotes.forEach((activeNote) => {
|
|
1000
|
-
const gain = activeNote.
|
|
1001
|
-
activeNote.
|
|
1065
|
+
const gain = activeNote.volumeNode.gain.value;
|
|
1066
|
+
activeNote.volumeNode.gain
|
|
1002
1067
|
.cancelScheduledValues(now)
|
|
1003
1068
|
.setValueAtTime(gain * pressure, now);
|
|
1004
1069
|
});
|
|
@@ -1021,7 +1086,7 @@ export class MidyGM2 {
|
|
|
1021
1086
|
case 0:
|
|
1022
1087
|
return this.setBankMSB(channelNumber, value);
|
|
1023
1088
|
case 1:
|
|
1024
|
-
return this.
|
|
1089
|
+
return this.setModulationDepth(channelNumber, value);
|
|
1025
1090
|
case 5:
|
|
1026
1091
|
return this.setPortamentoTime(channelNumber, value);
|
|
1027
1092
|
case 6:
|
|
@@ -1075,20 +1140,25 @@ export class MidyGM2 {
|
|
|
1075
1140
|
}
|
|
1076
1141
|
updateModulation(channel) {
|
|
1077
1142
|
const now = this.audioContext.currentTime;
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1143
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
1144
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
1145
|
+
const note = noteList[i];
|
|
1146
|
+
if (!note)
|
|
1147
|
+
continue;
|
|
1148
|
+
if (note.modulationDepth) {
|
|
1149
|
+
note.modulationDepth.gain.setValueAtTime(channel.modulationDepth, now);
|
|
1150
|
+
}
|
|
1151
|
+
else {
|
|
1152
|
+
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
1153
|
+
this.setPitch(note, semitoneOffset);
|
|
1154
|
+
this.startModulation(channel, note, now);
|
|
1155
|
+
}
|
|
1086
1156
|
}
|
|
1087
1157
|
});
|
|
1088
1158
|
}
|
|
1089
|
-
|
|
1159
|
+
setModulationDepth(channelNumber, modulation) {
|
|
1090
1160
|
const channel = this.channels[channelNumber];
|
|
1091
|
-
channel.
|
|
1161
|
+
channel.modulationDepth = (modulation / 127) * channel.modulationDepthRange;
|
|
1092
1162
|
this.updateModulation(channel);
|
|
1093
1163
|
}
|
|
1094
1164
|
setPortamentoTime(channelNumber, portamentoTime) {
|
|
@@ -1246,13 +1316,17 @@ export class MidyGM2 {
|
|
|
1246
1316
|
}
|
|
1247
1317
|
updateDetune(channel, detuneChange) {
|
|
1248
1318
|
const now = this.audioContext.currentTime;
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
.
|
|
1319
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
1320
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
1321
|
+
const note = noteList[i];
|
|
1322
|
+
if (!note)
|
|
1323
|
+
continue;
|
|
1324
|
+
const { bufferSource } = note;
|
|
1325
|
+
const detune = bufferSource.detune.value + detuneChange;
|
|
1326
|
+
bufferSource.detune
|
|
1327
|
+
.cancelScheduledValues(now)
|
|
1328
|
+
.setValueAtTime(detune, now);
|
|
1329
|
+
}
|
|
1256
1330
|
});
|
|
1257
1331
|
}
|
|
1258
1332
|
handlePitchBendRangeRPN(channelNumber) {
|
|
@@ -1298,47 +1372,23 @@ export class MidyGM2 {
|
|
|
1298
1372
|
handleModulationDepthRangeRPN(channelNumber) {
|
|
1299
1373
|
const channel = this.channels[channelNumber];
|
|
1300
1374
|
this.limitData(channel, 0, 127, 0, 127);
|
|
1301
|
-
const modulationDepthRange = dataMSB + dataLSB / 128;
|
|
1375
|
+
const modulationDepthRange = (dataMSB + dataLSB / 128) * 100;
|
|
1302
1376
|
this.setModulationDepthRange(channelNumber, modulationDepthRange);
|
|
1303
1377
|
}
|
|
1304
1378
|
setModulationDepthRange(channelNumber, modulationDepthRange) {
|
|
1305
1379
|
const channel = this.channels[channelNumber];
|
|
1306
1380
|
channel.modulationDepthRange = modulationDepthRange;
|
|
1307
|
-
channel.
|
|
1381
|
+
channel.modulationDepth = (modulation / 127) * modulationDepthRange;
|
|
1308
1382
|
this.updateModulation(channel);
|
|
1309
1383
|
}
|
|
1310
1384
|
allSoundOff(channelNumber) {
|
|
1311
|
-
|
|
1312
|
-
const channel = this.channels[channelNumber];
|
|
1313
|
-
const velocity = 0;
|
|
1314
|
-
const stopPedal = true;
|
|
1315
|
-
const promises = [];
|
|
1316
|
-
channel.scheduledNotes.forEach((noteList) => {
|
|
1317
|
-
const activeNote = this.getActiveNote(noteList, now);
|
|
1318
|
-
if (activeNote) {
|
|
1319
|
-
const notePromise = this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, stopPedal);
|
|
1320
|
-
promises.push(notePromise);
|
|
1321
|
-
}
|
|
1322
|
-
});
|
|
1323
|
-
return promises;
|
|
1385
|
+
return this.stopChannelNotes(channelNumber, 0, true);
|
|
1324
1386
|
}
|
|
1325
1387
|
resetAllControllers(channelNumber) {
|
|
1326
1388
|
Object.assign(this.channels[channelNumber], this.effectSettings);
|
|
1327
1389
|
}
|
|
1328
1390
|
allNotesOff(channelNumber) {
|
|
1329
|
-
|
|
1330
|
-
const channel = this.channels[channelNumber];
|
|
1331
|
-
const velocity = 0;
|
|
1332
|
-
const stopPedal = false;
|
|
1333
|
-
const promises = [];
|
|
1334
|
-
channel.scheduledNotes.forEach((noteList) => {
|
|
1335
|
-
const activeNote = this.getActiveNote(noteList, now);
|
|
1336
|
-
if (activeNote) {
|
|
1337
|
-
const notePromise = this.scheduleNoteRelease(channelNumber, activeNote.noteNumber, velocity, now, stopPedal);
|
|
1338
|
-
promises.push(notePromise);
|
|
1339
|
-
}
|
|
1340
|
-
});
|
|
1341
|
-
return promises;
|
|
1391
|
+
return this.stopChannelNotes(channelNumber, 0, false);
|
|
1342
1392
|
}
|
|
1343
1393
|
omniOff() {
|
|
1344
1394
|
this.omni = false;
|
|
@@ -1698,6 +1748,9 @@ Object.defineProperty(MidyGM2, "channelSettings", {
|
|
|
1698
1748
|
portamentoTime: 0,
|
|
1699
1749
|
reverbSendLevel: 0,
|
|
1700
1750
|
chorusSendLevel: 0,
|
|
1751
|
+
vibratoRate: 1,
|
|
1752
|
+
vibratoDepth: 1,
|
|
1753
|
+
vibratoDelay: 1,
|
|
1701
1754
|
bank: 121 * 128,
|
|
1702
1755
|
bankMSB: 121,
|
|
1703
1756
|
bankLSB: 0,
|
|
@@ -1707,7 +1760,7 @@ Object.defineProperty(MidyGM2, "channelSettings", {
|
|
|
1707
1760
|
pitchBend: 0,
|
|
1708
1761
|
fineTuning: 0, // cb
|
|
1709
1762
|
coarseTuning: 0, // cb
|
|
1710
|
-
modulationDepthRange:
|
|
1763
|
+
modulationDepthRange: 50, // cent
|
|
1711
1764
|
}
|
|
1712
1765
|
});
|
|
1713
1766
|
Object.defineProperty(MidyGM2, "effectSettings", {
|
|
@@ -1716,7 +1769,7 @@ Object.defineProperty(MidyGM2, "effectSettings", {
|
|
|
1716
1769
|
writable: true,
|
|
1717
1770
|
value: {
|
|
1718
1771
|
expression: 1,
|
|
1719
|
-
|
|
1772
|
+
modulationDepth: 0,
|
|
1720
1773
|
sustainPedal: false,
|
|
1721
1774
|
portamento: false,
|
|
1722
1775
|
sostenutoPedal: false,
|
package/esm/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;
|
package/esm/midy-GMLite.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"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"}
|