@marmooo/midy 0.0.1 → 0.0.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAMA;IAoBE;;;;;;;;;;;;;;MAcE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAlDD,qBAAmB;IACnB,uBAAqB;IACrB,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;IA4BhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;MAgBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA0DC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OAoEC;IAED,kGAsCC;IAED,0EAGC;IAED,sIAuCC;IAED,0FAGC;IAED,8CAmBC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAGC;IAED,+DAEC;IAED,8DAGC;IAED,mFA+BC;IAED,yDAQC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,sCAKC;IAED,sDAKC;IAED,gDAEC;IAED,gDAEC;IAED,+DAoBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,sCAIC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
1
+ {"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAMA;IAoBE;;;;;;;;;;;;;;MAcE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAlDD,qBAAmB;IACnB,uBAAqB;IACrB,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;IA4BhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;MAgBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA0DC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OAwEC;IAED,kGAsCC;IAED,0EAGC;IAED,sIA0CC;IAED,0FAGC;IAED,8CAuBC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAGC;IAED,+DAEC;IAED,8DAGC;IAED,mFA+BC;IAED,yDAQC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,sCAKC;IAED,sDAMC;IAED,gDAEC;IAED,gDAEC;IAED,+DAoBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,sCAIC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
package/esm/midy-GM1.js CHANGED
@@ -464,7 +464,7 @@ export class MidyGM1 {
464
464
  }
465
465
  getActiveNotes(channel) {
466
466
  const activeNotes = new Map();
467
- channel.scheduledNotes.forEeach((scheduledNotes) => {
467
+ channel.scheduledNotes.forEach((scheduledNotes) => {
468
468
  const activeNote = this.getActiveChannelNotes(scheduledNotes);
469
469
  if (activeNote) {
470
470
  activeNotes.set(activeNote.noteNumber, activeNote);
@@ -563,24 +563,28 @@ export class MidyGM1 {
563
563
  lfoGain.gain.setValueAtTime(channel.modulation, startTime + channel.vibratoDelay);
564
564
  }
565
565
  // filter envelope
566
+ const maxFreq = this.audioContext.sampleRate / 2;
566
567
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
567
568
  const peekFreq = this.centToHz(noteInfo.initialFilterFc + noteInfo.modEnvToFilterFc);
568
569
  const sustainFreq = baseFreq +
569
570
  (peekFreq - baseFreq) * (1 - noteInfo.modSustain);
571
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
572
+ const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
573
+ const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
570
574
  const filterNode = new BiquadFilterNode(this.audioContext, {
571
575
  type: "lowpass",
572
- Q: this.cbToRatio(noteInfo.initialFilterQ),
573
- frequency: baseFreq,
576
+ Q: noteInfo.initialFilterQ / 10, // dB
577
+ frequency: adjustedBaseFreq,
574
578
  });
575
579
  const modDelay = startTime + noteInfo.modDelay;
576
580
  const modAttack = modDelay + noteInfo.modAttack;
577
581
  const modHold = modAttack + noteInfo.modHold;
578
582
  const modDecay = modHold + noteInfo.modDecay;
579
583
  filterNode.frequency
580
- .setValueAtTime(baseFreq, modDelay)
581
- .exponentialRampToValueAtTime(peekFreq, modAttack)
582
- .setValueAtTime(peekFreq, modHold)
583
- .linearRampToValueAtTime(sustainFreq, modDecay);
584
+ .setValueAtTime(adjustedBaseFreq, modDelay)
585
+ .exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
586
+ .setValueAtTime(adjustedPeekFreq, modHold)
587
+ .linearRampToValueAtTime(adjustedSustainFreq, modDecay);
584
588
  bufferSource.connect(filterNode);
585
589
  filterNode.connect(gainNode);
586
590
  bufferSource.start(startTime, noteInfo.start / noteInfo.sampleRate);
@@ -638,10 +642,13 @@ export class MidyGM1 {
638
642
  const volEndTime = stopTime + noteInfo.volRelease * velocityRate;
639
643
  gainNode.gain.cancelScheduledValues(stopTime);
640
644
  gainNode.gain.linearRampToValueAtTime(0, volEndTime);
645
+ const maxFreq = this.audioContext.sampleRate / 2;
641
646
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
647
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
642
648
  const modEndTime = stopTime + noteInfo.modRelease * velocityRate;
643
- filterNode.frequency.cancelScheduledValues(stopTime);
644
- filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
649
+ filterNode.frequency
650
+ .cancelScheduledValues(stopTime)
651
+ .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
645
652
  targetNote.ending = true;
646
653
  this.scheduleTask(() => {
647
654
  bufferSource.loop = false;
@@ -669,14 +676,17 @@ export class MidyGM1 {
669
676
  channel.scheduledNotes.forEach((scheduledNotes) => {
670
677
  scheduledNotes.forEach((scheduledNote) => {
671
678
  if (scheduledNote) {
672
- const { gainNode, bufferSource, noteInfo } = scheduledNote;
679
+ const { bufferSource, gainNode, filterNode, noteInfo } = scheduledNote;
673
680
  const volEndTime = now + noteInfo.volRelease;
674
681
  gainNode.gain.cancelScheduledValues(now);
675
682
  gainNode.gain.linearRampToValueAtTime(0, volEndTime);
683
+ const maxFreq = this.audioContext.sampleRate / 2;
676
684
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
677
- const modEndTime = stopTime + noteInfo.modRelease;
678
- filterNode.frequency.cancelScheduledValues(stopTime);
679
- filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
685
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
686
+ const modEndTime = now + noteInfo.modRelease;
687
+ filterNode.frequency
688
+ .cancelScheduledValues(stopTime)
689
+ .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
680
690
  bufferSource.stop(volEndTime);
681
691
  }
682
692
  });
@@ -713,7 +723,7 @@ export class MidyGM1 {
713
723
  scheduledNotes.forEach((scheduledNote) => {
714
724
  if (scheduledNote) {
715
725
  const { initialAttenuation } = scheduledNote.noteInfo;
716
- const gain = this.cbToRatio(initialAttenuation) * pressure;
726
+ const gain = this.cbToRatio(-initialAttenuation) * pressure;
717
727
  scheduledNote.gainNode.gain.cancelScheduledValues(now);
718
728
  scheduledNote.gainNode.gain.setValueAtTime(gain, now);
719
729
  }
@@ -794,7 +804,8 @@ export class MidyGM1 {
794
804
  channel.gainNode.gain.setValueAtTime(volume, now);
795
805
  }
796
806
  setSustainPedal(channelNumber, value) {
797
- this.channels[channelNumber].sustainPedal = value >= 64;
807
+ const isOn = value >= 64;
808
+ this.channels[channelNumber].sustainPedal = isOn;
798
809
  if (!isOn) {
799
810
  this.releaseSustainPedal(channelNumber);
800
811
  }
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAMA;IAyBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF,+BAMC;IAjED,qBAAmB;IACnB,uBAAqB;IACrB,kBAAc;IACd,qBAAmB;IACnB,yBAAqB;IACrB,2BAAuB;IACvB,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;IAsChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;;;;MAuBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA4FC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED;;;;;MA2CC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OA6EC;IAED,gDAQC;IAED,kGA+CC;IAED,0EAGC;IAED,sIAwCC;IAED,0FAGC;IAED,8CAmBC;IAED,2CAYC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAIC;IAED,+DAEC;IAED,8DAGC;IAED,mFAuDC;IAED,+CAGC;IAED,yDAQC;IAED,iEAEC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,+CAEC;IAED,sCAKC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAQC;IAED,uDAIC;IAED,gDAEC;IAED,gDAEC;IAED,+DAuBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAgDC;IAED,yCAGC;IAED,sCAIC;IAED,6CAGC;IAED,8CAMC;IAED,+CAGC;IAED,kDAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
1
+ {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAMA;IAyBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF,+BAMC;IAjED,qBAAmB;IACnB,uBAAqB;IACrB,kBAAc;IACd,qBAAmB;IACnB,yBAAqB;IACrB,2BAAuB;IACvB,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;IAsChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;;;;MAuBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA4FC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED;;;;;MA2CC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OAiFC;IAED,gDAQC;IAED,kGA+CC;IAED,0EAGC;IAED,sIA2CC;IAED,0FAGC;IAED,8CAuBC;IAED,2CAYC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAIC;IAED,+DAEC;IAED,8DAGC;IAED,mFAuDC;IAED,+CAEC;IAED,yDAQC;IAED,iEAEC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,+CAEC;IAED,sCAKC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAQC;IAED,uDAIC;IAED,gDAEC;IAED,gDAEC;IAED,+DAuBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAgDC;IAED,yCAGC;IAED,sCAIC;IAED,6CAGC;IAED,8CAMC;IAED,+CAGC;IAED,kDAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
package/esm/midy-GM2.js CHANGED
@@ -699,24 +699,28 @@ export class MidyGM2 {
699
699
  // filter envelope
700
700
  const softPedalFactor = 1 -
701
701
  (0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
702
+ const maxFreq = this.audioContext.sampleRate / 2;
702
703
  const baseFreq = this.centToHz(noteInfo.initialFilterFc) * softPedalFactor;
703
704
  const peekFreq = this.centToHz(noteInfo.initialFilterFc + noteInfo.modEnvToFilterFc) * softPedalFactor;
704
705
  const sustainFreq = (baseFreq +
705
706
  (peekFreq - baseFreq) * (1 - noteInfo.modSustain)) * softPedalFactor;
707
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
708
+ const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
709
+ const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
706
710
  const filterNode = new BiquadFilterNode(this.audioContext, {
707
711
  type: "lowpass",
708
- Q: this.cbToRatio(noteInfo.initialFilterQ),
709
- frequency: baseFreq,
712
+ Q: noteInfo.initialFilterQ / 10, // dB
713
+ frequency: adjustedBaseFreq,
710
714
  });
711
715
  const modDelay = startTime + noteInfo.modDelay;
712
716
  const modAttack = modDelay + noteInfo.modAttack;
713
717
  const modHold = modAttack + noteInfo.modHold;
714
718
  const modDecay = modHold + noteInfo.modDecay;
715
719
  filterNode.frequency
716
- .setValueAtTime(baseFreq, modDelay)
717
- .exponentialRampToValueAtTime(peekFreq, modAttack)
718
- .setValueAtTime(peekFreq, modHold)
719
- .linearRampToValueAtTime(sustainFreq, modDecay);
720
+ .setValueAtTime(adjustedBaseFreq, modDelay)
721
+ .exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
722
+ .setValueAtTime(adjustedPeekFreq, modHold)
723
+ .linearRampToValueAtTime(adjustedSustainFreq, modDecay);
720
724
  bufferSource.connect(filterNode);
721
725
  filterNode.connect(gainNode);
722
726
  if (this.mono && channel.currentBufferSource) {
@@ -798,10 +802,13 @@ export class MidyGM2 {
798
802
  const volEndTime = stopTime + noteInfo.volRelease * velocityRate;
799
803
  gainNode.gain.cancelScheduledValues(stopTime);
800
804
  gainNode.gain.linearRampToValueAtTime(0, volEndTime);
805
+ const maxFreq = this.audioContext.sampleRate / 2;
801
806
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
807
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
802
808
  const modEndTime = stopTime + noteInfo.modRelease * velocityRate;
803
- filterNode.frequency.cancelScheduledValues(stopTime);
804
- filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
809
+ filterNode.frequency
810
+ .cancelScheduledValues(stopTime)
811
+ .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
805
812
  targetNote.ending = true;
806
813
  this.scheduleTask(() => {
807
814
  bufferSource.loop = false;
@@ -829,14 +836,17 @@ export class MidyGM2 {
829
836
  channel.scheduledNotes.forEach((scheduledNotes) => {
830
837
  scheduledNotes.forEach((scheduledNote) => {
831
838
  if (scheduledNote) {
832
- const { gainNode, filterNode, bufferSource, noteInfo } = scheduledNote;
839
+ const { bufferSource, gainNode, filterNode, noteInfo } = scheduledNote;
833
840
  const volEndTime = now + noteInfo.volRelease;
834
841
  gainNode.gain.cancelScheduledValues(now);
835
842
  gainNode.gain.linearRampToValueAtTime(0, volEndTime);
843
+ const maxFreq = this.audioContext.sampleRate / 2;
836
844
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
845
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
837
846
  const modEndTime = now + noteInfo.modRelease;
838
- filterNode.frequency.cancelScheduledValues(now);
839
- filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
847
+ filterNode.frequency
848
+ .cancelScheduledValues(stopTime)
849
+ .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
840
850
  bufferSource.stop(volEndTime);
841
851
  }
842
852
  });
@@ -886,7 +896,7 @@ export class MidyGM2 {
886
896
  scheduledNotes.forEach((scheduledNote) => {
887
897
  if (scheduledNote) {
888
898
  const { initialAttenuation } = scheduledNote.noteInfo;
889
- const gain = this.cbToRatio(initialAttenuation) * pressure;
899
+ const gain = this.cbToRatio(-initialAttenuation) * pressure;
890
900
  scheduledNote.gainNode.gain.cancelScheduledValues(now);
891
901
  scheduledNote.gainNode.gain.setValueAtTime(gain, now);
892
902
  }
@@ -960,8 +970,7 @@ export class MidyGM2 {
960
970
  }
961
971
  }
962
972
  setBankMSB(channelNumber, msb) {
963
- const channel = this.channels[channelNumber];
964
- channel.bankMSB = msb;
973
+ this.channels[channelNumber].bankMSB = msb;
965
974
  }
966
975
  setModulation(channelNumber, modulation) {
967
976
  const now = this.audioContext.currentTime;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAMA;IAoBE;;;;;;;;;;;;MAYE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAhDD,qBAAmB;IACnB,uBAAqB;IACrB,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;IA0BhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;MAgBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA0DC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OAmEC;IAED,kGAsCC;IAED,0EAGC;IAED,sIAuCC;IAED,0FAGC;IAED,8CAmBC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAGC;IAED,+DAEC;IAED,8DAGC;IAED,mFA+BC;IAED,yDAQC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,sCAKC;IAED,sDAKC;IAED,gDAEC;IAED,gDAEC;IAED,+DAcC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,sCAIC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
1
+ {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAMA;IAoBE;;;;;;;;;;;;MAYE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAhDD,qBAAmB;IACnB,uBAAqB;IACrB,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;IA0BhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;MAgBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA0DC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OAuEC;IAED,kGAsCC;IAED,0EAGC;IAED,sIA0CC;IAED,0FAGC;IAED,8CAuBC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAGC;IAED,+DAEC;IAED,8DAGC;IAED,mFA+BC;IAED,yDAQC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,sCAKC;IAED,sDAMC;IAED,gDAEC;IAED,gDAEC;IAED,+DAcC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,sCAIC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
@@ -464,7 +464,7 @@ export class MidyGMLite {
464
464
  }
465
465
  getActiveNotes(channel) {
466
466
  const activeNotes = new Map();
467
- channel.scheduledNotes.forEeach((scheduledNotes) => {
467
+ channel.scheduledNotes.forEach((scheduledNotes) => {
468
468
  const activeNote = this.getActiveChannelNotes(scheduledNotes);
469
469
  if (activeNote) {
470
470
  activeNotes.set(activeNote.noteNumber, activeNote);
@@ -562,24 +562,28 @@ export class MidyGMLite {
562
562
  lfoGain.gain.setValueAtTime(channel.modulation, startTime + channel.vibratoDelay);
563
563
  }
564
564
  // filter envelope
565
+ const maxFreq = this.audioContext.sampleRate / 2;
565
566
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
566
567
  const peekFreq = this.centToHz(noteInfo.initialFilterFc + noteInfo.modEnvToFilterFc);
567
568
  const sustainFreq = baseFreq +
568
569
  (peekFreq - baseFreq) * (1 - noteInfo.modSustain);
570
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
571
+ const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
572
+ const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
569
573
  const filterNode = new BiquadFilterNode(this.audioContext, {
570
574
  type: "lowpass",
571
- Q: this.cbToRatio(noteInfo.initialFilterQ),
572
- frequency: baseFreq,
575
+ Q: noteInfo.initialFilterQ / 10, // dB
576
+ frequency: adjustedBaseFreq,
573
577
  });
574
578
  const modDelay = startTime + noteInfo.modDelay;
575
579
  const modAttack = modDelay + noteInfo.modAttack;
576
580
  const modHold = modAttack + noteInfo.modHold;
577
581
  const modDecay = modHold + noteInfo.modDecay;
578
582
  filterNode.frequency
579
- .setValueAtTime(baseFreq, modDelay)
580
- .exponentialRampToValueAtTime(peekFreq, modAttack)
581
- .setValueAtTime(peekFreq, modHold)
582
- .linearRampToValueAtTime(sustainFreq, modDecay);
583
+ .setValueAtTime(adjustedBaseFreq, modDelay)
584
+ .exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
585
+ .setValueAtTime(adjustedPeekFreq, modHold)
586
+ .linearRampToValueAtTime(adjustedSustainFreq, modDecay);
583
587
  bufferSource.connect(filterNode);
584
588
  filterNode.connect(gainNode);
585
589
  bufferSource.start(startTime, noteInfo.start / noteInfo.sampleRate);
@@ -637,10 +641,13 @@ export class MidyGMLite {
637
641
  const volEndTime = stopTime + noteInfo.volRelease * velocityRate;
638
642
  gainNode.gain.cancelScheduledValues(stopTime);
639
643
  gainNode.gain.linearRampToValueAtTime(0, volEndTime);
644
+ const maxFreq = this.audioContext.sampleRate / 2;
640
645
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
646
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
641
647
  const modEndTime = stopTime + noteInfo.modRelease * velocityRate;
642
- filterNode.frequency.cancelScheduledValues(stopTime);
643
- filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
648
+ filterNode.frequency
649
+ .cancelScheduledValues(stopTime)
650
+ .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
644
651
  targetNote.ending = true;
645
652
  this.scheduleTask(() => {
646
653
  bufferSource.loop = false;
@@ -668,14 +675,17 @@ export class MidyGMLite {
668
675
  channel.scheduledNotes.forEach((scheduledNotes) => {
669
676
  scheduledNotes.forEach((scheduledNote) => {
670
677
  if (scheduledNote) {
671
- const { gainNode, bufferSource, noteInfo } = scheduledNote;
678
+ const { bufferSource, gainNode, filterNode, noteInfo } = scheduledNote;
672
679
  const volEndTime = now + noteInfo.volRelease;
673
680
  gainNode.gain.cancelScheduledValues(now);
674
681
  gainNode.gain.linearRampToValueAtTime(0, volEndTime);
682
+ const maxFreq = this.audioContext.sampleRate / 2;
675
683
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
676
- const modEndTime = stopTime + noteInfo.modRelease;
677
- filterNode.frequency.cancelScheduledValues(stopTime);
678
- filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
684
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
685
+ const modEndTime = now + noteInfo.modRelease;
686
+ filterNode.frequency
687
+ .cancelScheduledValues(stopTime)
688
+ .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
679
689
  bufferSource.stop(volEndTime);
680
690
  }
681
691
  });
@@ -712,7 +722,7 @@ export class MidyGMLite {
712
722
  scheduledNotes.forEach((scheduledNote) => {
713
723
  if (scheduledNote) {
714
724
  const { initialAttenuation } = scheduledNote.noteInfo;
715
- const gain = this.cbToRatio(initialAttenuation) * pressure;
725
+ const gain = this.cbToRatio(-initialAttenuation) * pressure;
716
726
  scheduledNote.gainNode.gain.cancelScheduledValues(now);
717
727
  scheduledNote.gainNode.gain.setValueAtTime(gain, now);
718
728
  }
@@ -793,7 +803,8 @@ export class MidyGMLite {
793
803
  channel.gainNode.gain.setValueAtTime(volume, now);
794
804
  }
795
805
  setSustainPedal(channelNumber, value) {
796
- this.channels[channelNumber].sustainPedal = value >= 64;
806
+ const isOn = value >= 64;
807
+ this.channels[channelNumber].sustainPedal = isOn;
797
808
  if (!isOn) {
798
809
  this.releaseSustainPedal(channelNumber);
799
810
  }
package/esm/midy.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAMA;IAyBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF,+BAMC;IAjED,qBAAmB;IACnB,uBAAqB;IACrB,kBAAc;IACd,qBAAmB;IACnB,yBAAqB;IACrB,2BAAuB;IACvB,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;IAsChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;;;;MAuBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA4FC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED;;;;;MA2CC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OA6EC;IAED,gDAQC;IAED,kGA+CC;IAED,0EAGC;IAED,sIAwCC;IAED,0FAGC;IAED,8CAmBC;IAED,2CAYC;IAED,gEAqBC;IAED,sFAeC;IAED,4DAIC;IAED,+DAEC;IAED,8DAGC;IAED,0EAkEC;IAED,+CAEC;IAED,yDAQC;IAED,iEAEC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,+CAEC;IAED,sCAKC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAQC;IAED,uDAIC;IAED,2DAMC;IAED,6DAMC;IAED,6DASC;IAED,4CAkBC;IAED,4CAkBC;IAED,gDAEC;IAED,gDAEC;IAGD,+DAuBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAgDC;IAED,yCAGC;IAED,sCAIC;IAED,6CAGC;IAED,8CAMC;IAED,+CAGC;IAED,kDAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
1
+ {"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAMA;IAyBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF,+BAMC;IAjED,qBAAmB;IACnB,uBAAqB;IACrB,kBAAc;IACd,qBAAmB;IACnB,yBAAqB;IACrB,2BAAuB;IACvB,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;IAsChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;;;;MAuBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA4FC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED;;;;;MA2CC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OAiFC;IAED,gDAQC;IAED,kGA+CC;IAED,0EAGC;IAED,sIA2CC;IAED,0FAGC;IAED,8CAuBC;IAED,2CAYC;IAED,gEAqBC;IAED,sFAeC;IAED,4DAIC;IAED,+DAEC;IAED,8DAGC;IAED,0EAkEC;IAED,+CAEC;IAED,yDAQC;IAED,iEAEC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,+CAEC;IAED,sCAKC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAQC;IAED,uDAIC;IAED,2DAMC;IAED,6DAMC;IAED,6DASC;IAED,4CAkBC;IAED,4CAkBC;IAED,gDAEC;IAED,gDAEC;IAGD,+DAuBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAgDC;IAED,yCAGC;IAED,sCAIC;IAED,6CAGC;IAED,8CAMC;IAED,+CAGC;IAED,kDAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
package/esm/midy.js CHANGED
@@ -699,24 +699,28 @@ export class Midy {
699
699
  // filter envelope
700
700
  const softPedalFactor = 1 -
701
701
  (0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
702
+ const maxFreq = this.audioContext.sampleRate / 2;
702
703
  const baseFreq = this.centToHz(noteInfo.initialFilterFc) * softPedalFactor;
703
704
  const peekFreq = this.centToHz(noteInfo.initialFilterFc + noteInfo.modEnvToFilterFc) * softPedalFactor;
704
705
  const sustainFreq = (baseFreq +
705
706
  (peekFreq - baseFreq) * (1 - noteInfo.modSustain)) * softPedalFactor;
707
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
708
+ const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
709
+ const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
706
710
  const filterNode = new BiquadFilterNode(this.audioContext, {
707
711
  type: "lowpass",
708
- Q: this.cbToRatio(noteInfo.initialFilterQ),
709
- frequency: baseFreq,
712
+ Q: noteInfo.initialFilterQ / 10, // dB
713
+ frequency: adjustedBaseFreq,
710
714
  });
711
715
  const modDelay = startTime + noteInfo.modDelay;
712
716
  const modAttack = modDelay + noteInfo.modAttack;
713
717
  const modHold = modAttack + noteInfo.modHold;
714
718
  const modDecay = modHold + noteInfo.modDecay;
715
719
  filterNode.frequency
716
- .setValueAtTime(baseFreq, modDelay)
717
- .exponentialRampToValueAtTime(peekFreq, modAttack)
718
- .setValueAtTime(peekFreq, modHold)
719
- .linearRampToValueAtTime(sustainFreq, modDecay);
720
+ .setValueAtTime(adjustedBaseFreq, modDelay)
721
+ .exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
722
+ .setValueAtTime(adjustedPeekFreq, modHold)
723
+ .linearRampToValueAtTime(adjustedSustainFreq, modDecay);
720
724
  bufferSource.connect(filterNode);
721
725
  filterNode.connect(gainNode);
722
726
  if (this.mono && channel.currentBufferSource) {
@@ -798,10 +802,13 @@ export class Midy {
798
802
  const volEndTime = stopTime + noteInfo.volRelease * velocityRate;
799
803
  gainNode.gain.cancelScheduledValues(stopTime);
800
804
  gainNode.gain.linearRampToValueAtTime(0, volEndTime);
805
+ const maxFreq = this.audioContext.sampleRate / 2;
801
806
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
807
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
802
808
  const modEndTime = stopTime + noteInfo.modRelease * velocityRate;
803
- filterNode.frequency.cancelScheduledValues(stopTime);
804
- filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
809
+ filterNode.frequency
810
+ .cancelScheduledValues(stopTime)
811
+ .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
805
812
  targetNote.ending = true;
806
813
  this.scheduleTask(() => {
807
814
  bufferSource.loop = false;
@@ -829,14 +836,17 @@ export class Midy {
829
836
  channel.scheduledNotes.forEach((scheduledNotes) => {
830
837
  scheduledNotes.forEach((scheduledNote) => {
831
838
  if (scheduledNote) {
832
- const { gainNode, filterNode, bufferSource, noteInfo } = scheduledNote;
839
+ const { bufferSource, gainNode, filterNode, noteInfo } = scheduledNote;
833
840
  const volEndTime = now + noteInfo.volRelease;
834
841
  gainNode.gain.cancelScheduledValues(now);
835
842
  gainNode.gain.linearRampToValueAtTime(0, volEndTime);
843
+ const maxFreq = this.audioContext.sampleRate / 2;
836
844
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
845
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
837
846
  const modEndTime = now + noteInfo.modRelease;
838
- filterNode.frequency.cancelScheduledValues(now);
839
- filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
847
+ filterNode.frequency
848
+ .cancelScheduledValues(stopTime)
849
+ .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
840
850
  bufferSource.stop(volEndTime);
841
851
  }
842
852
  });
@@ -886,7 +896,7 @@ export class Midy {
886
896
  scheduledNotes.forEach((scheduledNote) => {
887
897
  if (scheduledNote) {
888
898
  const { initialAttenuation } = scheduledNote.noteInfo;
889
- const gain = this.cbToRatio(initialAttenuation) * pressure;
899
+ const gain = this.cbToRatio(-initialAttenuation) * pressure;
890
900
  scheduledNote.gainNode.gain.cancelScheduledValues(now);
891
901
  scheduledNote.gainNode.gain.setValueAtTime(gain, now);
892
902
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marmooo/midy",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "A MIDI player/synthesizer written in JavaScript that supports GM-Lite/GM1 and SF2/SF3.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAMA;IAoBE;;;;;;;;;;;;;;MAcE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAlDD,qBAAmB;IACnB,uBAAqB;IACrB,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;IA4BhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;MAgBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA0DC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OAoEC;IAED,kGAsCC;IAED,0EAGC;IAED,sIAuCC;IAED,0FAGC;IAED,8CAmBC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAGC;IAED,+DAEC;IAED,8DAGC;IAED,mFA+BC;IAED,yDAQC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,sCAKC;IAED,sDAKC;IAED,gDAEC;IAED,gDAEC;IAED,+DAoBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,sCAIC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
1
+ {"version":3,"file":"midy-GM1.d.ts","sourceRoot":"","sources":["../src/midy-GM1.js"],"names":[],"mappings":"AAMA;IAoBE;;;;;;;;;;;;;;MAcE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAlDD,qBAAmB;IACnB,uBAAqB;IACrB,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;IA4BhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;MAgBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA0DC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OAwEC;IAED,kGAsCC;IAED,0EAGC;IAED,sIA0CC;IAED,0FAGC;IAED,8CAuBC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAGC;IAED,+DAEC;IAED,8DAGC;IAED,mFA+BC;IAED,yDAQC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,sCAKC;IAED,sDAMC;IAED,gDAEC;IAED,gDAEC;IAED,+DAoBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,sCAIC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
@@ -467,7 +467,7 @@ class MidyGM1 {
467
467
  }
468
468
  getActiveNotes(channel) {
469
469
  const activeNotes = new Map();
470
- channel.scheduledNotes.forEeach((scheduledNotes) => {
470
+ channel.scheduledNotes.forEach((scheduledNotes) => {
471
471
  const activeNote = this.getActiveChannelNotes(scheduledNotes);
472
472
  if (activeNote) {
473
473
  activeNotes.set(activeNote.noteNumber, activeNote);
@@ -566,24 +566,28 @@ class MidyGM1 {
566
566
  lfoGain.gain.setValueAtTime(channel.modulation, startTime + channel.vibratoDelay);
567
567
  }
568
568
  // filter envelope
569
+ const maxFreq = this.audioContext.sampleRate / 2;
569
570
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
570
571
  const peekFreq = this.centToHz(noteInfo.initialFilterFc + noteInfo.modEnvToFilterFc);
571
572
  const sustainFreq = baseFreq +
572
573
  (peekFreq - baseFreq) * (1 - noteInfo.modSustain);
574
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
575
+ const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
576
+ const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
573
577
  const filterNode = new BiquadFilterNode(this.audioContext, {
574
578
  type: "lowpass",
575
- Q: this.cbToRatio(noteInfo.initialFilterQ),
576
- frequency: baseFreq,
579
+ Q: noteInfo.initialFilterQ / 10, // dB
580
+ frequency: adjustedBaseFreq,
577
581
  });
578
582
  const modDelay = startTime + noteInfo.modDelay;
579
583
  const modAttack = modDelay + noteInfo.modAttack;
580
584
  const modHold = modAttack + noteInfo.modHold;
581
585
  const modDecay = modHold + noteInfo.modDecay;
582
586
  filterNode.frequency
583
- .setValueAtTime(baseFreq, modDelay)
584
- .exponentialRampToValueAtTime(peekFreq, modAttack)
585
- .setValueAtTime(peekFreq, modHold)
586
- .linearRampToValueAtTime(sustainFreq, modDecay);
587
+ .setValueAtTime(adjustedBaseFreq, modDelay)
588
+ .exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
589
+ .setValueAtTime(adjustedPeekFreq, modHold)
590
+ .linearRampToValueAtTime(adjustedSustainFreq, modDecay);
587
591
  bufferSource.connect(filterNode);
588
592
  filterNode.connect(gainNode);
589
593
  bufferSource.start(startTime, noteInfo.start / noteInfo.sampleRate);
@@ -641,10 +645,13 @@ class MidyGM1 {
641
645
  const volEndTime = stopTime + noteInfo.volRelease * velocityRate;
642
646
  gainNode.gain.cancelScheduledValues(stopTime);
643
647
  gainNode.gain.linearRampToValueAtTime(0, volEndTime);
648
+ const maxFreq = this.audioContext.sampleRate / 2;
644
649
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
650
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
645
651
  const modEndTime = stopTime + noteInfo.modRelease * velocityRate;
646
- filterNode.frequency.cancelScheduledValues(stopTime);
647
- filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
652
+ filterNode.frequency
653
+ .cancelScheduledValues(stopTime)
654
+ .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
648
655
  targetNote.ending = true;
649
656
  this.scheduleTask(() => {
650
657
  bufferSource.loop = false;
@@ -672,14 +679,17 @@ class MidyGM1 {
672
679
  channel.scheduledNotes.forEach((scheduledNotes) => {
673
680
  scheduledNotes.forEach((scheduledNote) => {
674
681
  if (scheduledNote) {
675
- const { gainNode, bufferSource, noteInfo } = scheduledNote;
682
+ const { bufferSource, gainNode, filterNode, noteInfo } = scheduledNote;
676
683
  const volEndTime = now + noteInfo.volRelease;
677
684
  gainNode.gain.cancelScheduledValues(now);
678
685
  gainNode.gain.linearRampToValueAtTime(0, volEndTime);
686
+ const maxFreq = this.audioContext.sampleRate / 2;
679
687
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
680
- const modEndTime = stopTime + noteInfo.modRelease;
681
- filterNode.frequency.cancelScheduledValues(stopTime);
682
- filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
688
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
689
+ const modEndTime = now + noteInfo.modRelease;
690
+ filterNode.frequency
691
+ .cancelScheduledValues(stopTime)
692
+ .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
683
693
  bufferSource.stop(volEndTime);
684
694
  }
685
695
  });
@@ -716,7 +726,7 @@ class MidyGM1 {
716
726
  scheduledNotes.forEach((scheduledNote) => {
717
727
  if (scheduledNote) {
718
728
  const { initialAttenuation } = scheduledNote.noteInfo;
719
- const gain = this.cbToRatio(initialAttenuation) * pressure;
729
+ const gain = this.cbToRatio(-initialAttenuation) * pressure;
720
730
  scheduledNote.gainNode.gain.cancelScheduledValues(now);
721
731
  scheduledNote.gainNode.gain.setValueAtTime(gain, now);
722
732
  }
@@ -797,7 +807,8 @@ class MidyGM1 {
797
807
  channel.gainNode.gain.setValueAtTime(volume, now);
798
808
  }
799
809
  setSustainPedal(channelNumber, value) {
800
- this.channels[channelNumber].sustainPedal = value >= 64;
810
+ const isOn = value >= 64;
811
+ this.channels[channelNumber].sustainPedal = isOn;
801
812
  if (!isOn) {
802
813
  this.releaseSustainPedal(channelNumber);
803
814
  }
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAMA;IAyBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF,+BAMC;IAjED,qBAAmB;IACnB,uBAAqB;IACrB,kBAAc;IACd,qBAAmB;IACnB,yBAAqB;IACrB,2BAAuB;IACvB,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;IAsChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;;;;MAuBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA4FC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED;;;;;MA2CC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OA6EC;IAED,gDAQC;IAED,kGA+CC;IAED,0EAGC;IAED,sIAwCC;IAED,0FAGC;IAED,8CAmBC;IAED,2CAYC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAIC;IAED,+DAEC;IAED,8DAGC;IAED,mFAuDC;IAED,+CAGC;IAED,yDAQC;IAED,iEAEC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,+CAEC;IAED,sCAKC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAQC;IAED,uDAIC;IAED,gDAEC;IAED,gDAEC;IAED,+DAuBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAgDC;IAED,yCAGC;IAED,sCAIC;IAED,6CAGC;IAED,8CAMC;IAED,+CAGC;IAED,kDAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
1
+ {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAMA;IAyBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF,+BAMC;IAjED,qBAAmB;IACnB,uBAAqB;IACrB,kBAAc;IACd,qBAAmB;IACnB,yBAAqB;IACrB,2BAAuB;IACvB,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;IAsChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;;;;MAuBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA4FC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED;;;;;MA2CC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OAiFC;IAED,gDAQC;IAED,kGA+CC;IAED,0EAGC;IAED,sIA2CC;IAED,0FAGC;IAED,8CAuBC;IAED,2CAYC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAIC;IAED,+DAEC;IAED,8DAGC;IAED,mFAuDC;IAED,+CAEC;IAED,yDAQC;IAED,iEAEC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,+CAEC;IAED,sCAKC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAQC;IAED,uDAIC;IAED,gDAEC;IAED,gDAEC;IAED,+DAuBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAgDC;IAED,yCAGC;IAED,sCAIC;IAED,6CAGC;IAED,8CAMC;IAED,+CAGC;IAED,kDAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
@@ -702,24 +702,28 @@ class MidyGM2 {
702
702
  // filter envelope
703
703
  const softPedalFactor = 1 -
704
704
  (0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
705
+ const maxFreq = this.audioContext.sampleRate / 2;
705
706
  const baseFreq = this.centToHz(noteInfo.initialFilterFc) * softPedalFactor;
706
707
  const peekFreq = this.centToHz(noteInfo.initialFilterFc + noteInfo.modEnvToFilterFc) * softPedalFactor;
707
708
  const sustainFreq = (baseFreq +
708
709
  (peekFreq - baseFreq) * (1 - noteInfo.modSustain)) * softPedalFactor;
710
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
711
+ const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
712
+ const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
709
713
  const filterNode = new BiquadFilterNode(this.audioContext, {
710
714
  type: "lowpass",
711
- Q: this.cbToRatio(noteInfo.initialFilterQ),
712
- frequency: baseFreq,
715
+ Q: noteInfo.initialFilterQ / 10, // dB
716
+ frequency: adjustedBaseFreq,
713
717
  });
714
718
  const modDelay = startTime + noteInfo.modDelay;
715
719
  const modAttack = modDelay + noteInfo.modAttack;
716
720
  const modHold = modAttack + noteInfo.modHold;
717
721
  const modDecay = modHold + noteInfo.modDecay;
718
722
  filterNode.frequency
719
- .setValueAtTime(baseFreq, modDelay)
720
- .exponentialRampToValueAtTime(peekFreq, modAttack)
721
- .setValueAtTime(peekFreq, modHold)
722
- .linearRampToValueAtTime(sustainFreq, modDecay);
723
+ .setValueAtTime(adjustedBaseFreq, modDelay)
724
+ .exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
725
+ .setValueAtTime(adjustedPeekFreq, modHold)
726
+ .linearRampToValueAtTime(adjustedSustainFreq, modDecay);
723
727
  bufferSource.connect(filterNode);
724
728
  filterNode.connect(gainNode);
725
729
  if (this.mono && channel.currentBufferSource) {
@@ -801,10 +805,13 @@ class MidyGM2 {
801
805
  const volEndTime = stopTime + noteInfo.volRelease * velocityRate;
802
806
  gainNode.gain.cancelScheduledValues(stopTime);
803
807
  gainNode.gain.linearRampToValueAtTime(0, volEndTime);
808
+ const maxFreq = this.audioContext.sampleRate / 2;
804
809
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
810
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
805
811
  const modEndTime = stopTime + noteInfo.modRelease * velocityRate;
806
- filterNode.frequency.cancelScheduledValues(stopTime);
807
- filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
812
+ filterNode.frequency
813
+ .cancelScheduledValues(stopTime)
814
+ .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
808
815
  targetNote.ending = true;
809
816
  this.scheduleTask(() => {
810
817
  bufferSource.loop = false;
@@ -832,14 +839,17 @@ class MidyGM2 {
832
839
  channel.scheduledNotes.forEach((scheduledNotes) => {
833
840
  scheduledNotes.forEach((scheduledNote) => {
834
841
  if (scheduledNote) {
835
- const { gainNode, filterNode, bufferSource, noteInfo } = scheduledNote;
842
+ const { bufferSource, gainNode, filterNode, noteInfo } = scheduledNote;
836
843
  const volEndTime = now + noteInfo.volRelease;
837
844
  gainNode.gain.cancelScheduledValues(now);
838
845
  gainNode.gain.linearRampToValueAtTime(0, volEndTime);
846
+ const maxFreq = this.audioContext.sampleRate / 2;
839
847
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
848
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
840
849
  const modEndTime = now + noteInfo.modRelease;
841
- filterNode.frequency.cancelScheduledValues(now);
842
- filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
850
+ filterNode.frequency
851
+ .cancelScheduledValues(stopTime)
852
+ .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
843
853
  bufferSource.stop(volEndTime);
844
854
  }
845
855
  });
@@ -889,7 +899,7 @@ class MidyGM2 {
889
899
  scheduledNotes.forEach((scheduledNote) => {
890
900
  if (scheduledNote) {
891
901
  const { initialAttenuation } = scheduledNote.noteInfo;
892
- const gain = this.cbToRatio(initialAttenuation) * pressure;
902
+ const gain = this.cbToRatio(-initialAttenuation) * pressure;
893
903
  scheduledNote.gainNode.gain.cancelScheduledValues(now);
894
904
  scheduledNote.gainNode.gain.setValueAtTime(gain, now);
895
905
  }
@@ -963,8 +973,7 @@ class MidyGM2 {
963
973
  }
964
974
  }
965
975
  setBankMSB(channelNumber, msb) {
966
- const channel = this.channels[channelNumber];
967
- channel.bankMSB = msb;
976
+ this.channels[channelNumber].bankMSB = msb;
968
977
  }
969
978
  setModulation(channelNumber, modulation) {
970
979
  const now = this.audioContext.currentTime;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAMA;IAoBE;;;;;;;;;;;;MAYE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAhDD,qBAAmB;IACnB,uBAAqB;IACrB,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;IA0BhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;MAgBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA0DC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OAmEC;IAED,kGAsCC;IAED,0EAGC;IAED,sIAuCC;IAED,0FAGC;IAED,8CAmBC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAGC;IAED,+DAEC;IAED,8DAGC;IAED,mFA+BC;IAED,yDAQC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,sCAKC;IAED,sDAKC;IAED,gDAEC;IAED,gDAEC;IAED,+DAcC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,sCAIC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
1
+ {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAMA;IAoBE;;;;;;;;;;;;MAYE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAhDD,qBAAmB;IACnB,uBAAqB;IACrB,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;IA0BhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;MAgBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA0DC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OAuEC;IAED,kGAsCC;IAED,0EAGC;IAED,sIA0CC;IAED,0FAGC;IAED,8CAuBC;IAED,wFAqBC;IAED,sFAeC;IAED,4DAGC;IAED,+DAEC;IAED,8DAGC;IAED,mFA+BC;IAED,yDAQC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,sCAKC;IAED,sDAMC;IAED,gDAEC;IAED,gDAEC;IAED,+DAcC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,sCAIC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
@@ -467,7 +467,7 @@ class MidyGMLite {
467
467
  }
468
468
  getActiveNotes(channel) {
469
469
  const activeNotes = new Map();
470
- channel.scheduledNotes.forEeach((scheduledNotes) => {
470
+ channel.scheduledNotes.forEach((scheduledNotes) => {
471
471
  const activeNote = this.getActiveChannelNotes(scheduledNotes);
472
472
  if (activeNote) {
473
473
  activeNotes.set(activeNote.noteNumber, activeNote);
@@ -565,24 +565,28 @@ class MidyGMLite {
565
565
  lfoGain.gain.setValueAtTime(channel.modulation, startTime + channel.vibratoDelay);
566
566
  }
567
567
  // filter envelope
568
+ const maxFreq = this.audioContext.sampleRate / 2;
568
569
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
569
570
  const peekFreq = this.centToHz(noteInfo.initialFilterFc + noteInfo.modEnvToFilterFc);
570
571
  const sustainFreq = baseFreq +
571
572
  (peekFreq - baseFreq) * (1 - noteInfo.modSustain);
573
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
574
+ const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
575
+ const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
572
576
  const filterNode = new BiquadFilterNode(this.audioContext, {
573
577
  type: "lowpass",
574
- Q: this.cbToRatio(noteInfo.initialFilterQ),
575
- frequency: baseFreq,
578
+ Q: noteInfo.initialFilterQ / 10, // dB
579
+ frequency: adjustedBaseFreq,
576
580
  });
577
581
  const modDelay = startTime + noteInfo.modDelay;
578
582
  const modAttack = modDelay + noteInfo.modAttack;
579
583
  const modHold = modAttack + noteInfo.modHold;
580
584
  const modDecay = modHold + noteInfo.modDecay;
581
585
  filterNode.frequency
582
- .setValueAtTime(baseFreq, modDelay)
583
- .exponentialRampToValueAtTime(peekFreq, modAttack)
584
- .setValueAtTime(peekFreq, modHold)
585
- .linearRampToValueAtTime(sustainFreq, modDecay);
586
+ .setValueAtTime(adjustedBaseFreq, modDelay)
587
+ .exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
588
+ .setValueAtTime(adjustedPeekFreq, modHold)
589
+ .linearRampToValueAtTime(adjustedSustainFreq, modDecay);
586
590
  bufferSource.connect(filterNode);
587
591
  filterNode.connect(gainNode);
588
592
  bufferSource.start(startTime, noteInfo.start / noteInfo.sampleRate);
@@ -640,10 +644,13 @@ class MidyGMLite {
640
644
  const volEndTime = stopTime + noteInfo.volRelease * velocityRate;
641
645
  gainNode.gain.cancelScheduledValues(stopTime);
642
646
  gainNode.gain.linearRampToValueAtTime(0, volEndTime);
647
+ const maxFreq = this.audioContext.sampleRate / 2;
643
648
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
649
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
644
650
  const modEndTime = stopTime + noteInfo.modRelease * velocityRate;
645
- filterNode.frequency.cancelScheduledValues(stopTime);
646
- filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
651
+ filterNode.frequency
652
+ .cancelScheduledValues(stopTime)
653
+ .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
647
654
  targetNote.ending = true;
648
655
  this.scheduleTask(() => {
649
656
  bufferSource.loop = false;
@@ -671,14 +678,17 @@ class MidyGMLite {
671
678
  channel.scheduledNotes.forEach((scheduledNotes) => {
672
679
  scheduledNotes.forEach((scheduledNote) => {
673
680
  if (scheduledNote) {
674
- const { gainNode, bufferSource, noteInfo } = scheduledNote;
681
+ const { bufferSource, gainNode, filterNode, noteInfo } = scheduledNote;
675
682
  const volEndTime = now + noteInfo.volRelease;
676
683
  gainNode.gain.cancelScheduledValues(now);
677
684
  gainNode.gain.linearRampToValueAtTime(0, volEndTime);
685
+ const maxFreq = this.audioContext.sampleRate / 2;
678
686
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
679
- const modEndTime = stopTime + noteInfo.modRelease;
680
- filterNode.frequency.cancelScheduledValues(stopTime);
681
- filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
687
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
688
+ const modEndTime = now + noteInfo.modRelease;
689
+ filterNode.frequency
690
+ .cancelScheduledValues(stopTime)
691
+ .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
682
692
  bufferSource.stop(volEndTime);
683
693
  }
684
694
  });
@@ -715,7 +725,7 @@ class MidyGMLite {
715
725
  scheduledNotes.forEach((scheduledNote) => {
716
726
  if (scheduledNote) {
717
727
  const { initialAttenuation } = scheduledNote.noteInfo;
718
- const gain = this.cbToRatio(initialAttenuation) * pressure;
728
+ const gain = this.cbToRatio(-initialAttenuation) * pressure;
719
729
  scheduledNote.gainNode.gain.cancelScheduledValues(now);
720
730
  scheduledNote.gainNode.gain.setValueAtTime(gain, now);
721
731
  }
@@ -796,7 +806,8 @@ class MidyGMLite {
796
806
  channel.gainNode.gain.setValueAtTime(volume, now);
797
807
  }
798
808
  setSustainPedal(channelNumber, value) {
799
- this.channels[channelNumber].sustainPedal = value >= 64;
809
+ const isOn = value >= 64;
810
+ this.channels[channelNumber].sustainPedal = isOn;
800
811
  if (!isOn) {
801
812
  this.releaseSustainPedal(channelNumber);
802
813
  }
@@ -1 +1 @@
1
- {"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAMA;IAyBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF,+BAMC;IAjED,qBAAmB;IACnB,uBAAqB;IACrB,kBAAc;IACd,qBAAmB;IACnB,yBAAqB;IACrB,2BAAuB;IACvB,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;IAsChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;;;;MAuBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA4FC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED;;;;;MA2CC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OA6EC;IAED,gDAQC;IAED,kGA+CC;IAED,0EAGC;IAED,sIAwCC;IAED,0FAGC;IAED,8CAmBC;IAED,2CAYC;IAED,gEAqBC;IAED,sFAeC;IAED,4DAIC;IAED,+DAEC;IAED,8DAGC;IAED,0EAkEC;IAED,+CAEC;IAED,yDAQC;IAED,iEAEC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,+CAEC;IAED,sCAKC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAQC;IAED,uDAIC;IAED,2DAMC;IAED,6DAMC;IAED,6DASC;IAED,4CAkBC;IAED,4CAkBC;IAED,gDAEC;IAED,gDAEC;IAGD,+DAuBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAgDC;IAED,yCAGC;IAED,sCAIC;IAED,6CAGC;IAED,8CAMC;IAED,+CAGC;IAED,kDAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
1
+ {"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAMA;IAyBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF,+BAMC;IAjED,qBAAmB;IACnB,uBAAqB;IACrB,kBAAc;IACd,qBAAmB;IACnB,yBAAqB;IACrB,2BAAuB;IACvB,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;IAsChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;;;;MAuBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAWC;IAED,0DAyBC;IAED,8DAUC;IAED,qDAOC;IAED,2EA6CC;IAED,mCAQC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA4FC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBA2BC;IAED,sBAGC;IAED,4CASC;IAED,gDAKC;IAED;;;MAUC;IAED;;;;MAoCC;IAED;;;;;MA2CC;IAED,sDA2BC;IAED,2BAEC;IAED,4BAEC;IAED;;;;OAiFC;IAED,gDAQC;IAED,kGA+CC;IAED,0EAGC;IAED,sIA2CC;IAED,0FAGC;IAED,8CAuBC;IAED,2CAYC;IAED,gEAqBC;IAED,sFAeC;IAED,4DAIC;IAED,+DAEC;IAED,8DAGC;IAED,0EAkEC;IAED,+CAEC;IAED,yDAQC;IAED,iEAEC;IAED,iDAIC;IAED,2CAMC;IAED,yDAIC;IAED,+CAEC;IAED,sCAKC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAQC;IAED,uDAIC;IAED,2DAMC;IAED,6DAMC;IAED,6DASC;IAED,4CAkBC;IAED,4CAkBC;IAED,gDAEC;IAED,gDAEC;IAGD,+DAuBC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAgDC;IAED,yCAGC;IAED,sCAIC;IAED,6CAGC;IAED,8CAMC;IAED,+CAGC;IAED,kDAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF"}
package/script/midy.js CHANGED
@@ -702,24 +702,28 @@ class Midy {
702
702
  // filter envelope
703
703
  const softPedalFactor = 1 -
704
704
  (0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
705
+ const maxFreq = this.audioContext.sampleRate / 2;
705
706
  const baseFreq = this.centToHz(noteInfo.initialFilterFc) * softPedalFactor;
706
707
  const peekFreq = this.centToHz(noteInfo.initialFilterFc + noteInfo.modEnvToFilterFc) * softPedalFactor;
707
708
  const sustainFreq = (baseFreq +
708
709
  (peekFreq - baseFreq) * (1 - noteInfo.modSustain)) * softPedalFactor;
710
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
711
+ const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
712
+ const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
709
713
  const filterNode = new BiquadFilterNode(this.audioContext, {
710
714
  type: "lowpass",
711
- Q: this.cbToRatio(noteInfo.initialFilterQ),
712
- frequency: baseFreq,
715
+ Q: noteInfo.initialFilterQ / 10, // dB
716
+ frequency: adjustedBaseFreq,
713
717
  });
714
718
  const modDelay = startTime + noteInfo.modDelay;
715
719
  const modAttack = modDelay + noteInfo.modAttack;
716
720
  const modHold = modAttack + noteInfo.modHold;
717
721
  const modDecay = modHold + noteInfo.modDecay;
718
722
  filterNode.frequency
719
- .setValueAtTime(baseFreq, modDelay)
720
- .exponentialRampToValueAtTime(peekFreq, modAttack)
721
- .setValueAtTime(peekFreq, modHold)
722
- .linearRampToValueAtTime(sustainFreq, modDecay);
723
+ .setValueAtTime(adjustedBaseFreq, modDelay)
724
+ .exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
725
+ .setValueAtTime(adjustedPeekFreq, modHold)
726
+ .linearRampToValueAtTime(adjustedSustainFreq, modDecay);
723
727
  bufferSource.connect(filterNode);
724
728
  filterNode.connect(gainNode);
725
729
  if (this.mono && channel.currentBufferSource) {
@@ -801,10 +805,13 @@ class Midy {
801
805
  const volEndTime = stopTime + noteInfo.volRelease * velocityRate;
802
806
  gainNode.gain.cancelScheduledValues(stopTime);
803
807
  gainNode.gain.linearRampToValueAtTime(0, volEndTime);
808
+ const maxFreq = this.audioContext.sampleRate / 2;
804
809
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
810
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
805
811
  const modEndTime = stopTime + noteInfo.modRelease * velocityRate;
806
- filterNode.frequency.cancelScheduledValues(stopTime);
807
- filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
812
+ filterNode.frequency
813
+ .cancelScheduledValues(stopTime)
814
+ .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
808
815
  targetNote.ending = true;
809
816
  this.scheduleTask(() => {
810
817
  bufferSource.loop = false;
@@ -832,14 +839,17 @@ class Midy {
832
839
  channel.scheduledNotes.forEach((scheduledNotes) => {
833
840
  scheduledNotes.forEach((scheduledNote) => {
834
841
  if (scheduledNote) {
835
- const { gainNode, filterNode, bufferSource, noteInfo } = scheduledNote;
842
+ const { bufferSource, gainNode, filterNode, noteInfo } = scheduledNote;
836
843
  const volEndTime = now + noteInfo.volRelease;
837
844
  gainNode.gain.cancelScheduledValues(now);
838
845
  gainNode.gain.linearRampToValueAtTime(0, volEndTime);
846
+ const maxFreq = this.audioContext.sampleRate / 2;
839
847
  const baseFreq = this.centToHz(noteInfo.initialFilterFc);
848
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
840
849
  const modEndTime = now + noteInfo.modRelease;
841
- filterNode.frequency.cancelScheduledValues(now);
842
- filterNode.frequency.linearRampToValueAtTime(baseFreq, modEndTime);
850
+ filterNode.frequency
851
+ .cancelScheduledValues(stopTime)
852
+ .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
843
853
  bufferSource.stop(volEndTime);
844
854
  }
845
855
  });
@@ -889,7 +899,7 @@ class Midy {
889
899
  scheduledNotes.forEach((scheduledNote) => {
890
900
  if (scheduledNote) {
891
901
  const { initialAttenuation } = scheduledNote.noteInfo;
892
- const gain = this.cbToRatio(initialAttenuation) * pressure;
902
+ const gain = this.cbToRatio(-initialAttenuation) * pressure;
893
903
  scheduledNote.gainNode.gain.cancelScheduledValues(now);
894
904
  scheduledNote.gainNode.gain.setValueAtTime(gain, now);
895
905
  }