@marmooo/midy 0.1.3 → 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/midy-GM1.d.ts +3 -2
- package/esm/midy-GM1.d.ts.map +1 -1
- package/esm/midy-GM1.js +66 -55
- package/esm/midy-GM2.d.ts +3 -2
- package/esm/midy-GM2.d.ts.map +1 -1
- package/esm/midy-GM2.js +61 -47
- package/esm/midy-GMLite.d.ts +3 -2
- package/esm/midy-GMLite.d.ts.map +1 -1
- package/esm/midy-GMLite.js +64 -53
- package/esm/midy.d.ts +14 -3
- package/esm/midy.d.ts.map +1 -1
- package/esm/midy.js +140 -53
- package/package.json +1 -1
- package/script/midy-GM1.d.ts +3 -2
- package/script/midy-GM1.d.ts.map +1 -1
- package/script/midy-GM1.js +66 -55
- package/script/midy-GM2.d.ts +3 -2
- package/script/midy-GM2.d.ts.map +1 -1
- package/script/midy-GM2.js +61 -47
- package/script/midy-GMLite.d.ts +3 -2
- package/script/midy-GMLite.d.ts.map +1 -1
- package/script/midy-GMLite.js +64 -53
- package/script/midy.d.ts +14 -3
- package/script/midy.d.ts.map +1 -1
- package/script/midy.js +140 -53
package/script/midy-GM1.js
CHANGED
|
@@ -435,12 +435,13 @@ class MidyGM1 {
|
|
|
435
435
|
const now = this.audioContext.currentTime;
|
|
436
436
|
const channel = this.channels[channelNumber];
|
|
437
437
|
channel.scheduledNotes.forEach((noteList) => {
|
|
438
|
-
noteList.
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
438
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
439
|
+
const note = noteList[i];
|
|
440
|
+
if (!note)
|
|
441
|
+
continue;
|
|
442
|
+
const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, stopPedal);
|
|
443
|
+
this.notePromises.push(promise);
|
|
444
|
+
}
|
|
444
445
|
});
|
|
445
446
|
channel.scheduledNotes.clear();
|
|
446
447
|
await Promise.all(this.notePromises);
|
|
@@ -532,7 +533,6 @@ class MidyGM1 {
|
|
|
532
533
|
}
|
|
533
534
|
setVolumeEnvelope(note) {
|
|
534
535
|
const { instrumentKey, startTime } = note;
|
|
535
|
-
note.volumeNode = new GainNode(this.audioContext, { gain: 0 });
|
|
536
536
|
const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
|
|
537
537
|
const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
|
|
538
538
|
const volDelay = startTime + instrumentKey.volDelay;
|
|
@@ -540,6 +540,8 @@ class MidyGM1 {
|
|
|
540
540
|
const volHold = volAttack + instrumentKey.volHold;
|
|
541
541
|
const volDecay = volHold + instrumentKey.volDecay;
|
|
542
542
|
note.volumeNode.gain
|
|
543
|
+
.cancelScheduledValues(startTime)
|
|
544
|
+
.setValueAtTime(0, startTime)
|
|
543
545
|
.setValueAtTime(1e-6, volDelay) // exponentialRampToValueAtTime() requires a non-zero value
|
|
544
546
|
.exponentialRampToValueAtTime(attackVolume, volAttack)
|
|
545
547
|
.setValueAtTime(attackVolume, volHold)
|
|
@@ -563,29 +565,27 @@ class MidyGM1 {
|
|
|
563
565
|
.setValueAtTime(peekPitch, modHold)
|
|
564
566
|
.linearRampToValueAtTime(basePitch, modDecay);
|
|
565
567
|
}
|
|
566
|
-
|
|
567
|
-
const
|
|
568
|
-
const
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
const
|
|
574
|
-
const
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
const
|
|
578
|
-
const
|
|
568
|
+
clampCutoffFrequency(frequency) {
|
|
569
|
+
const minFrequency = 20; // min Hz of initialFilterFc
|
|
570
|
+
const maxFrequency = 20000; // max Hz of initialFilterFc
|
|
571
|
+
return Math.max(minFrequency, Math.min(frequency, maxFrequency));
|
|
572
|
+
}
|
|
573
|
+
setFilterEnvelope(note) {
|
|
574
|
+
const { instrumentKey, startTime } = note;
|
|
575
|
+
const baseFreq = this.centToHz(instrumentKey.initialFilterFc);
|
|
576
|
+
const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc);
|
|
577
|
+
const sustainFreq = baseFreq +
|
|
578
|
+
(peekFreq - baseFreq) * (1 - instrumentKey.modSustain);
|
|
579
|
+
const adjustedBaseFreq = this.clampCutoffFrequency(baseFreq);
|
|
580
|
+
const adjustedPeekFreq = this.clampCutoffFrequency(peekFreq);
|
|
581
|
+
const adjustedSustainFreq = this.clampCutoffFrequency(sustainFreq);
|
|
579
582
|
const modDelay = startTime + instrumentKey.modDelay;
|
|
580
583
|
const modAttack = modDelay + instrumentKey.modAttack;
|
|
581
584
|
const modHold = modAttack + instrumentKey.modHold;
|
|
582
585
|
const modDecay = modHold + instrumentKey.modDecay;
|
|
583
|
-
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
584
|
-
type: "lowpass",
|
|
585
|
-
Q: instrumentKey.initialFilterQ / 10, // dB
|
|
586
|
-
frequency: adjustedBaseFreq,
|
|
587
|
-
});
|
|
588
586
|
note.filterNode.frequency
|
|
587
|
+
.cancelScheduledValues(startTime)
|
|
588
|
+
.setValueAtTime(adjustedBaseFreq, startTime)
|
|
589
589
|
.setValueAtTime(adjustedBaseFreq, modDelay)
|
|
590
590
|
.exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
|
|
591
591
|
.setValueAtTime(adjustedPeekFreq, modHold)
|
|
@@ -622,8 +622,13 @@ class MidyGM1 {
|
|
|
622
622
|
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
623
623
|
const note = new Note(noteNumber, velocity, startTime, instrumentKey);
|
|
624
624
|
note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
|
|
625
|
-
this.
|
|
625
|
+
note.volumeNode = new GainNode(this.audioContext);
|
|
626
|
+
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
627
|
+
type: "lowpass",
|
|
628
|
+
Q: instrumentKey.initialFilterQ / 10 * channel.filterResonance, // dB
|
|
629
|
+
});
|
|
626
630
|
this.setVolumeEnvelope(note);
|
|
631
|
+
this.setFilterEnvelope(note);
|
|
627
632
|
if (0 < channel.modulationDepth) {
|
|
628
633
|
this.setPitch(note, semitoneOffset);
|
|
629
634
|
this.startModulation(channel, note, startTime);
|
|
@@ -662,7 +667,7 @@ class MidyGM1 {
|
|
|
662
667
|
const now = this.audioContext.currentTime;
|
|
663
668
|
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now);
|
|
664
669
|
}
|
|
665
|
-
scheduleNoteRelease(channelNumber, noteNumber,
|
|
670
|
+
scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, stopPedal = false) {
|
|
666
671
|
const channel = this.channels[channelNumber];
|
|
667
672
|
if (stopPedal && channel.sustainPedal)
|
|
668
673
|
return;
|
|
@@ -675,14 +680,11 @@ class MidyGM1 {
|
|
|
675
680
|
continue;
|
|
676
681
|
if (note.ending)
|
|
677
682
|
continue;
|
|
678
|
-
const
|
|
679
|
-
const volEndTime = stopTime +
|
|
680
|
-
note.instrumentKey.volRelease * velocityRate;
|
|
683
|
+
const volEndTime = stopTime + note.instrumentKey.volRelease;
|
|
681
684
|
note.volumeNode.gain
|
|
682
685
|
.cancelScheduledValues(stopTime)
|
|
683
686
|
.linearRampToValueAtTime(0, volEndTime);
|
|
684
|
-
const modRelease = stopTime +
|
|
685
|
-
note.instrumentKey.modRelease * velocityRate;
|
|
687
|
+
const modRelease = stopTime + note.instrumentKey.modRelease;
|
|
686
688
|
note.filterNode.frequency
|
|
687
689
|
.cancelScheduledValues(stopTime)
|
|
688
690
|
.linearRampToValueAtTime(0, modRelease);
|
|
@@ -718,13 +720,14 @@ class MidyGM1 {
|
|
|
718
720
|
const promises = [];
|
|
719
721
|
channel.sustainPedal = false;
|
|
720
722
|
channel.scheduledNotes.forEach((noteList) => {
|
|
721
|
-
noteList.
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
723
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
724
|
+
const note = noteList[i];
|
|
725
|
+
if (!note)
|
|
726
|
+
continue;
|
|
727
|
+
const { noteNumber } = note;
|
|
728
|
+
const promise = this.releaseNote(channelNumber, noteNumber, velocity);
|
|
729
|
+
promises.push(promise);
|
|
730
|
+
}
|
|
728
731
|
});
|
|
729
732
|
return promises;
|
|
730
733
|
}
|
|
@@ -794,15 +797,19 @@ class MidyGM1 {
|
|
|
794
797
|
}
|
|
795
798
|
updateModulation(channel) {
|
|
796
799
|
const now = this.audioContext.currentTime;
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
800
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
801
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
802
|
+
const note = noteList[i];
|
|
803
|
+
if (!note)
|
|
804
|
+
continue;
|
|
805
|
+
if (note.modulationDepth) {
|
|
806
|
+
note.modulationDepth.gain.setValueAtTime(channel.modulationDepth, now);
|
|
807
|
+
}
|
|
808
|
+
else {
|
|
809
|
+
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
810
|
+
this.setPitch(note, semitoneOffset);
|
|
811
|
+
this.startModulation(channel, note, now);
|
|
812
|
+
}
|
|
806
813
|
}
|
|
807
814
|
});
|
|
808
815
|
}
|
|
@@ -910,13 +917,17 @@ class MidyGM1 {
|
|
|
910
917
|
}
|
|
911
918
|
updateDetune(channel, detuneChange) {
|
|
912
919
|
const now = this.audioContext.currentTime;
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
.
|
|
920
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
921
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
922
|
+
const note = noteList[i];
|
|
923
|
+
if (!note)
|
|
924
|
+
continue;
|
|
925
|
+
const { bufferSource } = note;
|
|
926
|
+
const detune = bufferSource.detune.value + detuneChange;
|
|
927
|
+
bufferSource.detune
|
|
928
|
+
.cancelScheduledValues(now)
|
|
929
|
+
.setValueAtTime(detune, now);
|
|
930
|
+
}
|
|
920
931
|
});
|
|
921
932
|
}
|
|
922
933
|
handlePitchBendRangeRPN(channelNumber) {
|
package/script/midy-GM2.d.ts
CHANGED
|
@@ -167,14 +167,15 @@ export class MidyGM2 {
|
|
|
167
167
|
calcPlaybackRate(instrumentKey: any, noteNumber: any, semitoneOffset: any): number;
|
|
168
168
|
setVolumeEnvelope(note: any): void;
|
|
169
169
|
setPitch(note: any, semitoneOffset: any): void;
|
|
170
|
-
|
|
170
|
+
clampCutoffFrequency(frequency: any): number;
|
|
171
|
+
setFilterEnvelope(channel: any, note: any): void;
|
|
171
172
|
startModulation(channel: any, note: any, startTime: any): void;
|
|
172
173
|
startVibrato(channel: any, note: any, startTime: any): void;
|
|
173
174
|
createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
|
|
174
175
|
calcBank(channel: any, channelNumber: any): any;
|
|
175
176
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
176
177
|
noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
|
|
177
|
-
scheduleNoteRelease(channelNumber: any, noteNumber: any,
|
|
178
|
+
scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
|
|
178
179
|
releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
|
|
179
180
|
releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
|
|
180
181
|
releaseSostenutoPedal(channelNumber: any, halfVelocity: any): any[];
|
package/script/midy-GM2.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAwBA;IAkCE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAgCF;;;;;OAWC;IAtHD,qBAAmB;IACnB,kBAAc;IACd,yBAAqB;IACrB,2BAAuB;IACvB;;;MAGE;IACF;;;;;;MAME;IACF,cAAa;IACb,cAAa;IACb,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;IA8ClB;;;;;MA4BE;IAGA,kBAAgC;IAChC;;;;;MAAqD;IACrD,gBAA4C;IAC5C,gBAAiD;IACjD;;;MAA8D;IAC9D;;;;;;;;MAAyD;IAO3D,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAcC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EAkDC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAgGC;IAED,mFAmBC;IAED,yDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,kFAuBC;IAED;;;;MAWC;IAED,gFAUC;IAED,mFAYC;IAED,sGAcC;IAID;;;MA+BC;IAED;;;;;;;;MA0CC;IAED,2BAEC;IAED,4BAEC;IAED,sCAKC;IAED,mFAGC;IAED,
|
|
1
|
+
{"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"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"}
|
package/script/midy-GM2.js
CHANGED
|
@@ -548,12 +548,13 @@ class MidyGM2 {
|
|
|
548
548
|
const now = this.audioContext.currentTime;
|
|
549
549
|
const channel = this.channels[channelNumber];
|
|
550
550
|
channel.scheduledNotes.forEach((noteList) => {
|
|
551
|
-
noteList.
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
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
|
+
}
|
|
557
558
|
});
|
|
558
559
|
channel.scheduledNotes.clear();
|
|
559
560
|
await Promise.all(this.notePromises);
|
|
@@ -776,7 +777,6 @@ class MidyGM2 {
|
|
|
776
777
|
}
|
|
777
778
|
setVolumeEnvelope(note) {
|
|
778
779
|
const { instrumentKey, startTime } = note;
|
|
779
|
-
note.volumeNode = new GainNode(this.audioContext, { gain: 0 });
|
|
780
780
|
const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
|
|
781
781
|
const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
|
|
782
782
|
const volDelay = startTime + instrumentKey.volDelay;
|
|
@@ -784,6 +784,8 @@ class MidyGM2 {
|
|
|
784
784
|
const volHold = volAttack + instrumentKey.volHold;
|
|
785
785
|
const volDecay = volHold + instrumentKey.volDecay;
|
|
786
786
|
note.volumeNode.gain
|
|
787
|
+
.cancelScheduledValues(startTime)
|
|
788
|
+
.setValueAtTime(0, startTime)
|
|
787
789
|
.setValueAtTime(1e-6, volDelay) // exponentialRampToValueAtTime() requires a non-zero value
|
|
788
790
|
.exponentialRampToValueAtTime(attackVolume, volAttack)
|
|
789
791
|
.setValueAtTime(attackVolume, volHold)
|
|
@@ -807,29 +809,30 @@ class MidyGM2 {
|
|
|
807
809
|
.setValueAtTime(peekPitch, modHold)
|
|
808
810
|
.linearRampToValueAtTime(basePitch, modDecay);
|
|
809
811
|
}
|
|
810
|
-
|
|
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
|
+
}
|
|
817
|
+
setFilterEnvelope(channel, note) {
|
|
811
818
|
const { instrumentKey, noteNumber, startTime } = note;
|
|
812
819
|
const softPedalFactor = 1 -
|
|
813
820
|
(0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
|
|
814
|
-
const maxFreq = this.audioContext.sampleRate / 2;
|
|
815
821
|
const baseFreq = this.centToHz(instrumentKey.initialFilterFc) *
|
|
816
822
|
softPedalFactor;
|
|
817
823
|
const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc) * softPedalFactor;
|
|
818
824
|
const sustainFreq = baseFreq +
|
|
819
825
|
(peekFreq - baseFreq) * (1 - instrumentKey.modSustain);
|
|
820
|
-
const adjustedBaseFreq =
|
|
821
|
-
const adjustedPeekFreq =
|
|
822
|
-
const adjustedSustainFreq =
|
|
826
|
+
const adjustedBaseFreq = this.clampCutoffFrequency(baseFreq);
|
|
827
|
+
const adjustedPeekFreq = this.clampCutoffFrequency(peekFreq);
|
|
828
|
+
const adjustedSustainFreq = this.clampCutoffFrequency(sustainFreq);
|
|
823
829
|
const modDelay = startTime + instrumentKey.modDelay;
|
|
824
830
|
const modAttack = modDelay + instrumentKey.modAttack;
|
|
825
831
|
const modHold = modAttack + instrumentKey.modHold;
|
|
826
832
|
const modDecay = modHold + instrumentKey.modDecay;
|
|
827
|
-
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
828
|
-
type: "lowpass",
|
|
829
|
-
Q: instrumentKey.initialFilterQ / 10, // dB
|
|
830
|
-
frequency: adjustedBaseFreq,
|
|
831
|
-
});
|
|
832
833
|
note.filterNode.frequency
|
|
834
|
+
.cancelScheduledValues(startTime)
|
|
835
|
+
.setValueAtTime(adjustedBaseFreq, startTime)
|
|
833
836
|
.setValueAtTime(adjustedBaseFreq, modDelay)
|
|
834
837
|
.exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
|
|
835
838
|
.setValueAtTime(adjustedPeekFreq, modHold)
|
|
@@ -882,8 +885,13 @@ class MidyGM2 {
|
|
|
882
885
|
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
883
886
|
const note = new Note(noteNumber, velocity, startTime, instrumentKey);
|
|
884
887
|
note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
|
|
885
|
-
this.
|
|
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
|
+
});
|
|
886
893
|
this.setVolumeEnvelope(note);
|
|
894
|
+
this.setFilterEnvelope(channel, note);
|
|
887
895
|
if (0 < channel.vibratoDepth) {
|
|
888
896
|
this.startVibrato(channel, note, startTime);
|
|
889
897
|
}
|
|
@@ -941,7 +949,7 @@ class MidyGM2 {
|
|
|
941
949
|
const now = this.audioContext.currentTime;
|
|
942
950
|
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now);
|
|
943
951
|
}
|
|
944
|
-
scheduleNoteRelease(channelNumber, noteNumber,
|
|
952
|
+
scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, stopPedal = false) {
|
|
945
953
|
const channel = this.channels[channelNumber];
|
|
946
954
|
if (stopPedal && channel.sustainPedal)
|
|
947
955
|
return;
|
|
@@ -956,14 +964,11 @@ class MidyGM2 {
|
|
|
956
964
|
continue;
|
|
957
965
|
if (note.ending)
|
|
958
966
|
continue;
|
|
959
|
-
const
|
|
960
|
-
const volEndTime = stopTime +
|
|
961
|
-
note.instrumentKey.volRelease * velocityRate;
|
|
967
|
+
const volEndTime = stopTime + note.instrumentKey.volRelease;
|
|
962
968
|
note.volumeNode.gain
|
|
963
969
|
.cancelScheduledValues(stopTime)
|
|
964
970
|
.linearRampToValueAtTime(0, volEndTime);
|
|
965
|
-
const modRelease = stopTime +
|
|
966
|
-
note.instrumentKey.modRelease * velocityRate;
|
|
971
|
+
const modRelease = stopTime + note.instrumentKey.modRelease;
|
|
967
972
|
note.filterNode.frequency
|
|
968
973
|
.cancelScheduledValues(stopTime)
|
|
969
974
|
.linearRampToValueAtTime(0, modRelease);
|
|
@@ -1003,13 +1008,14 @@ class MidyGM2 {
|
|
|
1003
1008
|
const promises = [];
|
|
1004
1009
|
channel.sustainPedal = false;
|
|
1005
1010
|
channel.scheduledNotes.forEach((noteList) => {
|
|
1006
|
-
noteList.
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
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
|
+
}
|
|
1013
1019
|
});
|
|
1014
1020
|
return promises;
|
|
1015
1021
|
}
|
|
@@ -1137,15 +1143,19 @@ class MidyGM2 {
|
|
|
1137
1143
|
}
|
|
1138
1144
|
updateModulation(channel) {
|
|
1139
1145
|
const now = this.audioContext.currentTime;
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
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
|
+
}
|
|
1149
1159
|
}
|
|
1150
1160
|
});
|
|
1151
1161
|
}
|
|
@@ -1309,13 +1319,17 @@ class MidyGM2 {
|
|
|
1309
1319
|
}
|
|
1310
1320
|
updateDetune(channel, detuneChange) {
|
|
1311
1321
|
const now = this.audioContext.currentTime;
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
.
|
|
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
|
+
}
|
|
1319
1333
|
});
|
|
1320
1334
|
}
|
|
1321
1335
|
handlePitchBendRangeRPN(channelNumber) {
|
package/script/midy-GMLite.d.ts
CHANGED
|
@@ -77,12 +77,13 @@ export class MidyGMLite {
|
|
|
77
77
|
calcPlaybackRate(instrumentKey: any, noteNumber: any, semitoneOffset: any): number;
|
|
78
78
|
setVolumeEnvelope(note: any): void;
|
|
79
79
|
setPitch(note: any, semitoneOffset: any): void;
|
|
80
|
-
|
|
80
|
+
clampCutoffFrequency(frequency: any): number;
|
|
81
|
+
setFilterEnvelope(note: any): void;
|
|
81
82
|
startModulation(channel: any, note: any, startTime: any): void;
|
|
82
83
|
createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
|
|
83
84
|
scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
|
|
84
85
|
noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
|
|
85
|
-
scheduleNoteRelease(channelNumber: any, noteNumber: any,
|
|
86
|
+
scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
|
|
86
87
|
releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
|
|
87
88
|
releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
|
|
88
89
|
handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<any>;
|
|
@@ -1 +1 @@
|
|
|
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,
|
|
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"}
|
package/script/midy-GMLite.js
CHANGED
|
@@ -423,12 +423,13 @@ class MidyGMLite {
|
|
|
423
423
|
const now = this.audioContext.currentTime;
|
|
424
424
|
const channel = this.channels[channelNumber];
|
|
425
425
|
channel.scheduledNotes.forEach((noteList) => {
|
|
426
|
-
noteList.
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
426
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
427
|
+
const note = noteList[i];
|
|
428
|
+
if (!note)
|
|
429
|
+
continue;
|
|
430
|
+
const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, stopPedal);
|
|
431
|
+
this.notePromises.push(promise);
|
|
432
|
+
}
|
|
432
433
|
});
|
|
433
434
|
channel.scheduledNotes.clear();
|
|
434
435
|
await Promise.all(this.notePromises);
|
|
@@ -519,7 +520,6 @@ class MidyGMLite {
|
|
|
519
520
|
}
|
|
520
521
|
setVolumeEnvelope(note) {
|
|
521
522
|
const { instrumentKey, startTime } = note;
|
|
522
|
-
note.volumeNode = new GainNode(this.audioContext, { gain: 0 });
|
|
523
523
|
const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
|
|
524
524
|
const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
|
|
525
525
|
const volDelay = startTime + instrumentKey.volDelay;
|
|
@@ -527,6 +527,8 @@ class MidyGMLite {
|
|
|
527
527
|
const volHold = volAttack + instrumentKey.volHold;
|
|
528
528
|
const volDecay = volHold + instrumentKey.volDecay;
|
|
529
529
|
note.volumeNode.gain
|
|
530
|
+
.cancelScheduledValues(startTime)
|
|
531
|
+
.setValueAtTime(0, startTime)
|
|
530
532
|
.setValueAtTime(1e-6, volDelay) // exponentialRampToValueAtTime() requires a non-zero value
|
|
531
533
|
.exponentialRampToValueAtTime(attackVolume, volAttack)
|
|
532
534
|
.setValueAtTime(attackVolume, volHold)
|
|
@@ -550,29 +552,27 @@ class MidyGMLite {
|
|
|
550
552
|
.setValueAtTime(peekPitch, modHold)
|
|
551
553
|
.linearRampToValueAtTime(basePitch, modDecay);
|
|
552
554
|
}
|
|
553
|
-
|
|
554
|
-
const
|
|
555
|
-
const
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
const
|
|
555
|
+
clampCutoffFrequency(frequency) {
|
|
556
|
+
const minFrequency = 20; // min Hz of initialFilterFc
|
|
557
|
+
const maxFrequency = 20000; // max Hz of initialFilterFc
|
|
558
|
+
return Math.max(minFrequency, Math.min(frequency, maxFrequency));
|
|
559
|
+
}
|
|
560
|
+
setFilterEnvelope(note) {
|
|
561
|
+
const { instrumentKey, startTime } = note;
|
|
562
|
+
const baseFreq = this.centToHz(instrumentKey.initialFilterFc);
|
|
563
|
+
const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc);
|
|
561
564
|
const sustainFreq = baseFreq +
|
|
562
565
|
(peekFreq - baseFreq) * (1 - instrumentKey.modSustain);
|
|
563
|
-
const adjustedBaseFreq =
|
|
564
|
-
const adjustedPeekFreq =
|
|
565
|
-
const adjustedSustainFreq =
|
|
566
|
+
const adjustedBaseFreq = this.clampCutoffFrequency(baseFreq);
|
|
567
|
+
const adjustedPeekFreq = this.clampCutoffFrequency(peekFreq);
|
|
568
|
+
const adjustedSustainFreq = this.clampCutoffFrequency(sustainFreq);
|
|
566
569
|
const modDelay = startTime + instrumentKey.modDelay;
|
|
567
570
|
const modAttack = modDelay + instrumentKey.modAttack;
|
|
568
571
|
const modHold = modAttack + instrumentKey.modHold;
|
|
569
572
|
const modDecay = modHold + instrumentKey.modDecay;
|
|
570
|
-
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
571
|
-
type: "lowpass",
|
|
572
|
-
Q: instrumentKey.initialFilterQ / 10, // dB
|
|
573
|
-
frequency: adjustedBaseFreq,
|
|
574
|
-
});
|
|
575
573
|
note.filterNode.frequency
|
|
574
|
+
.cancelScheduledValues(startTime)
|
|
575
|
+
.setValueAtTime(adjustedBaseFreq, startTime)
|
|
576
576
|
.setValueAtTime(adjustedBaseFreq, modDelay)
|
|
577
577
|
.exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
|
|
578
578
|
.setValueAtTime(adjustedPeekFreq, modHold)
|
|
@@ -609,8 +609,13 @@ class MidyGMLite {
|
|
|
609
609
|
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
610
610
|
const note = new Note(noteNumber, velocity, startTime, instrumentKey);
|
|
611
611
|
note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
|
|
612
|
-
this.
|
|
612
|
+
note.volumeNode = new GainNode(this.audioContext);
|
|
613
|
+
note.filterNode = new BiquadFilterNode(this.audioContext, {
|
|
614
|
+
type: "lowpass",
|
|
615
|
+
Q: instrumentKey.initialFilterQ / 10 * channel.filterResonance, // dB
|
|
616
|
+
});
|
|
613
617
|
this.setVolumeEnvelope(note);
|
|
618
|
+
this.setFilterEnvelope(note);
|
|
614
619
|
if (0 < channel.modulationDepth) {
|
|
615
620
|
this.setPitch(note, semitoneOffset);
|
|
616
621
|
this.startModulation(channel, note, startTime);
|
|
@@ -649,7 +654,7 @@ class MidyGMLite {
|
|
|
649
654
|
const now = this.audioContext.currentTime;
|
|
650
655
|
return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now);
|
|
651
656
|
}
|
|
652
|
-
scheduleNoteRelease(channelNumber, noteNumber,
|
|
657
|
+
scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, stopPedal = false) {
|
|
653
658
|
const channel = this.channels[channelNumber];
|
|
654
659
|
if (stopPedal && channel.sustainPedal)
|
|
655
660
|
return;
|
|
@@ -662,14 +667,11 @@ class MidyGMLite {
|
|
|
662
667
|
continue;
|
|
663
668
|
if (note.ending)
|
|
664
669
|
continue;
|
|
665
|
-
const
|
|
666
|
-
const volEndTime = stopTime +
|
|
667
|
-
note.instrumentKey.volRelease * velocityRate;
|
|
670
|
+
const volEndTime = stopTime + note.instrumentKey.volRelease;
|
|
668
671
|
note.volumeNode.gain
|
|
669
672
|
.cancelScheduledValues(stopTime)
|
|
670
673
|
.linearRampToValueAtTime(0, volEndTime);
|
|
671
|
-
const modRelease = stopTime +
|
|
672
|
-
note.instrumentKey.modRelease * velocityRate;
|
|
674
|
+
const modRelease = stopTime + note.instrumentKey.modRelease;
|
|
673
675
|
note.filterNode.frequency
|
|
674
676
|
.cancelScheduledValues(stopTime)
|
|
675
677
|
.linearRampToValueAtTime(0, modRelease);
|
|
@@ -705,13 +707,14 @@ class MidyGMLite {
|
|
|
705
707
|
const promises = [];
|
|
706
708
|
channel.sustainPedal = false;
|
|
707
709
|
channel.scheduledNotes.forEach((noteList) => {
|
|
708
|
-
noteList.
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
710
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
711
|
+
const note = noteList[i];
|
|
712
|
+
if (!note)
|
|
713
|
+
continue;
|
|
714
|
+
const { noteNumber } = note;
|
|
715
|
+
const promise = this.releaseNote(channelNumber, noteNumber, velocity);
|
|
716
|
+
promises.push(promise);
|
|
717
|
+
}
|
|
715
718
|
});
|
|
716
719
|
return promises;
|
|
717
720
|
}
|
|
@@ -781,15 +784,19 @@ class MidyGMLite {
|
|
|
781
784
|
}
|
|
782
785
|
updateModulation(channel) {
|
|
783
786
|
const now = this.audioContext.currentTime;
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
787
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
788
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
789
|
+
const note = noteList[i];
|
|
790
|
+
if (!note)
|
|
791
|
+
continue;
|
|
792
|
+
if (note.modulationDepth) {
|
|
793
|
+
note.modulationDepth.gain.setValueAtTime(channel.modulationDepth, now);
|
|
794
|
+
}
|
|
795
|
+
else {
|
|
796
|
+
const semitoneOffset = this.calcSemitoneOffset(channel);
|
|
797
|
+
this.setPitch(note, semitoneOffset);
|
|
798
|
+
this.startModulation(channel, note, now);
|
|
799
|
+
}
|
|
793
800
|
}
|
|
794
801
|
});
|
|
795
802
|
}
|
|
@@ -865,13 +872,17 @@ class MidyGMLite {
|
|
|
865
872
|
}
|
|
866
873
|
updateDetune(channel, detuneChange) {
|
|
867
874
|
const now = this.audioContext.currentTime;
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
.
|
|
875
|
+
channel.scheduledNotes.forEach((noteList) => {
|
|
876
|
+
for (let i = 0; i < noteList.length; i++) {
|
|
877
|
+
const note = noteList[i];
|
|
878
|
+
if (!note)
|
|
879
|
+
continue;
|
|
880
|
+
const { bufferSource } = note;
|
|
881
|
+
const detune = bufferSource.detune.value + detuneChange;
|
|
882
|
+
bufferSource.detune
|
|
883
|
+
.cancelScheduledValues(now)
|
|
884
|
+
.setValueAtTime(detune, now);
|
|
885
|
+
}
|
|
875
886
|
});
|
|
876
887
|
}
|
|
877
888
|
handlePitchBendRangeRPN(channelNumber) {
|