@marmooo/midy 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/esm/midy.js CHANGED
@@ -82,7 +82,7 @@ export class Midy {
82
82
  writable: true,
83
83
  value: {
84
84
  time: this.getReverbTime(64),
85
- feedback: 0.2,
85
+ feedback: 0.25,
86
86
  }
87
87
  });
88
88
  Object.defineProperty(this, "chorus", {
@@ -90,10 +90,11 @@ export class Midy {
90
90
  configurable: true,
91
91
  writable: true,
92
92
  value: {
93
- modRate: 3 * 0.122,
94
- modDepth: (3 + 1) / 3.2,
95
- feedback: 8 * 0.763,
96
- sendToReverb: 0 * 0.787,
93
+ modRate: this.getChorusModRate(3),
94
+ modDepth: this.getChorusModDepth(19),
95
+ feedback: this.getChorusFeedback(8),
96
+ sendToReverb: this.getChorusSendToReverb(0),
97
+ delayTimes: this.generateDistributedArray(0.02, 2, 0.5),
97
98
  }
98
99
  });
99
100
  Object.defineProperty(this, "mono", {
@@ -694,9 +695,7 @@ export class Midy {
694
695
  createSchroederReverb(audioContext, combDelays, combFeedbacks, allpassDelays, allpassFeedbacks) {
695
696
  const input = new GainNode(audioContext);
696
697
  const output = new GainNode(audioContext);
697
- const mergerGain = new GainNode(audioContext, {
698
- gain: 1 / (combDelays.length * 2),
699
- });
698
+ const mergerGain = new GainNode(audioContext);
700
699
  for (let i = 0; i < combDelays.length; i++) {
701
700
  const comb = this.createCombFilter(audioContext, input, combDelays[i], combFeedbacks[i]);
702
701
  comb.connect(mergerGain);
@@ -709,60 +708,62 @@ export class Midy {
709
708
  allpasses.at(-1).connect(output);
710
709
  return { input, output };
711
710
  }
712
- createChorusEffect(audioContext, options = {}) {
713
- const { chorusCount = 2, chorusRate = 0.6, chorusDepth = 0.15, delay = 0.01, variance = delay * 0.1, } = options;
714
- const lfo = new OscillatorNode(audioContext, { frequency: chorusRate });
715
- const lfoGain = new GainNode(audioContext, { gain: chorusDepth });
711
+ createChorusEffect(audioContext) {
712
+ const input = new GainNode(audioContext);
716
713
  const output = new GainNode(audioContext);
717
- const chorusGains = [];
714
+ const sendGain = new GainNode(audioContext);
715
+ const lfo = new OscillatorNode(audioContext, {
716
+ frequency: this.chorus.modRate,
717
+ });
718
+ const lfoGain = new GainNode(audioContext, {
719
+ gain: this.chorus.modDepth / 2,
720
+ });
721
+ const delayTimes = this.chorus.delayTimes;
718
722
  const delayNodes = [];
719
- const baseGain = 1 / chorusCount;
720
- for (let i = 0; i < chorusCount; i++) {
721
- const randomDelayFactor = (Math.random() - 0.5) * variance;
722
- const delayTime = (i + 1) * delay + randomDelayFactor;
723
+ const feedbackGains = [];
724
+ for (let i = 0; i < delayTimes.length; i++) {
725
+ const delayTime = delayTimes[i];
723
726
  const delayNode = new DelayNode(audioContext, {
724
- maxDelayTime: delayTime,
727
+ maxDelayTime: 0.1, // generally, 5ms < delayTime < 50ms
728
+ delayTime,
729
+ });
730
+ const feedbackGain = new GainNode(audioContext, {
731
+ gain: this.chorus.feedback,
725
732
  });
726
- const chorusGain = new GainNode(audioContext, { gain: baseGain });
727
733
  delayNodes.push(delayNode);
728
- chorusGains.push(chorusGain);
734
+ feedbackGains.push(feedbackGain);
735
+ input.connect(delayNode);
729
736
  lfoGain.connect(delayNode.delayTime);
730
- delayNode.connect(chorusGain);
731
- chorusGain.connect(output);
737
+ delayNode.connect(feedbackGain);
738
+ feedbackGain.connect(delayNode);
739
+ delayNode.connect(output);
732
740
  }
741
+ output.connect(sendGain);
733
742
  lfo.connect(lfoGain);
734
743
  lfo.start();
735
744
  return {
745
+ input,
746
+ output,
747
+ sendGain,
736
748
  lfo,
737
749
  lfoGain,
738
750
  delayNodes,
739
- chorusGains,
740
- output,
751
+ feedbackGains,
741
752
  };
742
753
  }
743
754
  connectEffects(channel, gainNode) {
744
755
  gainNode.connect(channel.merger);
745
756
  channel.merger.connect(this.masterGain);
746
- if (channel.reverbSendLevel === 0) {
747
- if (channel.chorusSendLevel !== 0) { // chorus
748
- channel.chorusEffect.delayNodes.forEach((delayNode) => {
749
- channel.merger.connect(delayNode);
750
- });
751
- channel.chorusEffect.output.connect(this.masterGain);
752
- }
757
+ if (0 < channel.reverbSendLevel) {
758
+ channel.merger.connect(channel.reverbEffect.input);
759
+ channel.reverbEffect.output.connect(this.masterGain);
753
760
  }
754
- else {
755
- if (channel.chorusSendLevel === 0) { // reverb
756
- channel.merger.connect(channel.reverbEffect.input);
757
- channel.reverbEffect.output.connect(this.masterGain);
758
- }
759
- else { // reverb + chorus
760
- channel.chorusEffect.delayNodes.forEach((delayNode) => {
761
- channel.merger.connect(delayNode);
762
- });
763
- channel.merger.connect(channel.reverbEffect.input);
764
- channel.reverbEffect.output.connect(this.masterGain);
765
- }
761
+ if (0 < channel.chorusSendLevel) {
762
+ channel.merger.connect(channel.chorusEffect.input);
763
+ channel.reverbEffect.output.connect(this.masterGain);
764
+ }
765
+ if (0 < this.chorus.sendToReverb) {
766
+ channel.chorusEffect.sendGain.connect(channel.reverbEffect.input);
766
767
  }
767
768
  }
768
769
  cbToRatio(cb) {
@@ -1221,9 +1222,12 @@ export class Midy {
1221
1222
  reverbEffect.output.gain.setValueAtTime(channel.reverbSendLevel, now);
1222
1223
  }
1223
1224
  setChorusSendLevel(channelNumber, chorusSendLevel) {
1225
+ const now = this.audioContext.currentTime;
1224
1226
  const channel = this.channels[channelNumber];
1227
+ const chorusEffect = channel.chorusEffect;
1225
1228
  channel.chorusSendLevel = chorusSendLevel / 127;
1226
- channel.chorusEffect.lfoGain = channel.chorusSendLevel;
1229
+ chorusEffect.output.gain.cancelScheduledValues(now);
1230
+ chorusEffect.output.gain.setValueAtTime(channel.chorusSendLevel, now);
1227
1231
  }
1228
1232
  setSostenutoPedal(channelNumber, value) {
1229
1233
  const isOn = value >= 64;
@@ -1483,7 +1487,7 @@ export class Midy {
1483
1487
  case 4: // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/ca25.pdf
1484
1488
  return this.handleMasterCoarseTuningSysEx(data);
1485
1489
  case 5:
1486
- return this.handleGlobalParameterControl(data);
1490
+ return this.handleGlobalParameterControlSysEx(data);
1487
1491
  default:
1488
1492
  console.warn(`Unsupported Exclusive Message: ${data}`);
1489
1493
  }
@@ -1560,13 +1564,13 @@ export class Midy {
1560
1564
  this.masterCoarseTuning = coarseTuning - 64;
1561
1565
  }
1562
1566
  }
1563
- handleGlobalParameterControl(data) {
1564
- if (data[5] === 1) {
1565
- switch (data[6]) {
1567
+ handleGlobalParameterControlSysEx(data) {
1568
+ if (data[7] === 1) {
1569
+ switch (data[8]) {
1566
1570
  case 1:
1567
- return this.handleReverbParameter(data);
1571
+ return this.handleReverbParameterSysEx(data);
1568
1572
  case 2:
1569
- return this.handleChorusParameter(data);
1573
+ return this.handleChorusParameterSysEx(data);
1570
1574
  default:
1571
1575
  console.warn(`Unsupported Global Parameter Control Message: ${data}`);
1572
1576
  }
@@ -1575,12 +1579,12 @@ export class Midy {
1575
1579
  console.warn(`Unsupported Global Parameter Control Message: ${data}`);
1576
1580
  }
1577
1581
  }
1578
- handleReverbParameter(data) {
1579
- switch (data[7]) {
1582
+ handleReverbParameterSysEx(data) {
1583
+ switch (data[9]) {
1580
1584
  case 0:
1581
- return this.setReverbType(data[8]);
1585
+ return this.setReverbType(data[10]);
1582
1586
  case 1:
1583
- return this.setReverbTime(data[8]);
1587
+ return this.setReverbTime(data[10]);
1584
1588
  }
1585
1589
  }
1586
1590
  setReverbType(type) {
@@ -1640,41 +1644,109 @@ export class Midy {
1640
1644
  // RT60 = -3 * delay / Math.log10(feedback)
1641
1645
  // feedback = Math.pow(10, -3 * delay / RT60)
1642
1646
  // delay estimation using ideal feedback
1643
- // A suitable average sound absorption coefficient is 0.18-0.28.
1644
- // Since the structure of the hall is complex,
1645
- // It would be easier to determine the delay based on the ideal feedback.
1647
+ // The structure of a concert hall is complex,
1648
+ // so estimates based on mean free path are unstable.
1649
+ // It is easier to determine the delay based on ideal feedback.
1650
+ // The average sound absorption coefficient
1651
+ // suitable for playing musical instruments is 0.18 to 0.28.
1646
1652
  // delay = -RT60 * Math.log10(feedback) / 3
1647
1653
  calcDelay(rt60, feedback) {
1648
1654
  return -rt60 * Math.log10(feedback) / 3;
1649
1655
  }
1650
- handleChorusParameter(data) {
1651
- switch (data[7]) {
1656
+ handleChorusParameterSysEx(data) {
1657
+ switch (data[9]) {
1652
1658
  case 0:
1653
- return this.setChorusType(data[8]);
1659
+ return this.setChorusType(data[10]);
1654
1660
  case 1:
1655
- return this.setChorusModRate(data[8]);
1661
+ return this.setChorusModRate(data[10]);
1656
1662
  case 2:
1657
- return this.setChorusModDepth(data[8]);
1663
+ return this.setChorusModDepth(data[10]);
1658
1664
  case 3:
1659
- return this.setChorusFeedback(data[8]);
1665
+ return this.setChorusFeedback(data[10]);
1660
1666
  case 4:
1661
- return this.setChorusSendToReverb(data[8]);
1667
+ return this.setChorusSendToReverb(data[10]);
1662
1668
  }
1663
1669
  }
1664
1670
  setChorusType(type) {
1665
- // TODO
1671
+ switch (type) {
1672
+ case 0:
1673
+ return this.setChorusParameter(3, 5, 0, 0);
1674
+ case 1:
1675
+ return this.setChorusParameter(9, 19, 5, 0);
1676
+ case 2:
1677
+ return this.setChorusParameter(3, 19, 8, 0);
1678
+ case 3:
1679
+ return this.setChorusParameter(9, 16, 16, 0);
1680
+ case 4:
1681
+ return this.setChorusParameter(2, 24, 64, 0);
1682
+ case 5:
1683
+ return this.setChorusParameter(1, 5, 112, 0);
1684
+ default:
1685
+ console.warn(`Unsupported Chorus Type: ${type}`);
1686
+ }
1687
+ }
1688
+ setChorusParameter(modRate, modDepth, feedback, sendToReverb) {
1689
+ this.setChorusModRate(modRate);
1690
+ this.setChorusModDepth(modDepth);
1691
+ this.setChorusFeedback(feedback);
1692
+ this.setChorusSendToReverb(sendToReverb);
1666
1693
  }
1667
1694
  setChorusModRate(value) {
1668
- // TODO
1695
+ const now = this.audioContext.currentTime;
1696
+ const modRate = this.getChorusModRate(value);
1697
+ this.chorus.modRate = modRate;
1698
+ for (let i = 0; i < this.channels.length; i++) {
1699
+ const lfo = this.channels[i].chorusEffect.lfo;
1700
+ lfo.frequency.setValueAtTime(modRate, now);
1701
+ }
1702
+ }
1703
+ getChorusModRate(value) {
1704
+ return value * 0.122; // Hz
1669
1705
  }
1670
1706
  setChorusModDepth(value) {
1671
- // TODO
1707
+ const now = this.audioContext.currentTime;
1708
+ const modDepth = this.getChorusModDepth(value);
1709
+ this.chorus.modDepth = modDepth;
1710
+ for (let i = 0; i < this.channels.length; i++) {
1711
+ const chorusEffect = this.channels[i].chorusEffect;
1712
+ chorusEffect.lfoGain.gain
1713
+ .cancelScheduledValues(now)
1714
+ .setValueAtTime(modDepth / 2, now);
1715
+ }
1716
+ }
1717
+ getChorusModDepth(value) {
1718
+ return (value + 1) / 3200; // second
1672
1719
  }
1673
1720
  setChorusFeedback(value) {
1674
- // TODO
1721
+ const now = this.audioContext.currentTime;
1722
+ const feedback = this.getChorusFeedback(value);
1723
+ this.chorus.feedback = feedback;
1724
+ for (let i = 0; i < this.channels.length; i++) {
1725
+ const chorusEffect = this.channels[i].chorusEffect;
1726
+ for (let j = 0; j < chorusEffect.feedbackGains.length; j++) {
1727
+ const feedbackGain = chorusEffect.feedbackGains[j];
1728
+ feedbackGain.gain
1729
+ .cancelScheduledValues(now)
1730
+ .setValueAtTime(feedback, now);
1731
+ }
1732
+ }
1733
+ }
1734
+ getChorusFeedback(value) {
1735
+ return value * 0.00763;
1675
1736
  }
1676
1737
  setChorusSendToReverb(value) {
1677
- // TODO
1738
+ const now = this.audioContext.currentTime;
1739
+ const sendToReverb = this.getChorusSendToReverb(value);
1740
+ this.chorus.sendToReverb = sendToReverb;
1741
+ for (let i = 0; i < this.channels.length; i++) {
1742
+ const chorusEffect = this.channels[i].chorusEffect;
1743
+ chorusEffect.sendGain.gain
1744
+ .cancelScheduledValues(now)
1745
+ .setValueAtTime(sendToReverb, now);
1746
+ }
1747
+ }
1748
+ getChorusSendToReverb(value) {
1749
+ return value * 0.00787;
1678
1750
  }
1679
1751
  handleExclusiveMessage(data) {
1680
1752
  console.warn(`Unsupported Exclusive Message: ${data}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marmooo/midy",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
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",
@@ -56,6 +56,7 @@ export class MidyGM2 {
56
56
  modDepth: number;
57
57
  feedback: number;
58
58
  sendToReverb: number;
59
+ delayTimes: any[];
59
60
  };
60
61
  mono: boolean;
61
62
  omni: boolean;
@@ -102,11 +103,13 @@ export class MidyGM2 {
102
103
  output: any;
103
104
  };
104
105
  chorusEffect: {
106
+ input: any;
107
+ output: any;
108
+ sendGain: any;
105
109
  lfo: any;
106
110
  lfoGain: any;
107
111
  delayNodes: any[];
108
- chorusGains: any[];
109
- output: any;
112
+ feedbackGains: any[];
110
113
  };
111
114
  };
112
115
  createChannels(audioContext: any): any[];
@@ -145,12 +148,14 @@ export class MidyGM2 {
145
148
  input: any;
146
149
  output: any;
147
150
  };
148
- createChorusEffect(audioContext: any, options?: {}): {
151
+ createChorusEffect(audioContext: any): {
152
+ input: any;
153
+ output: any;
154
+ sendGain: any;
149
155
  lfo: any;
150
156
  lfoGain: any;
151
157
  delayNodes: any[];
152
- chorusGains: any[];
153
- output: any;
158
+ feedbackGains: any[];
154
159
  };
155
160
  connectEffects(channel: any, gainNode: any): void;
156
161
  cbToRatio(cb: any): number;
@@ -226,19 +231,24 @@ export class MidyGM2 {
226
231
  setMasterFineTuning(fineTuning: any): void;
227
232
  handleMasterCoarseTuningSysEx(data: any): void;
228
233
  setMasterCoarseTuning(coarseTuning: any): void;
229
- handleGlobalParameterControl(data: any): void;
230
- handleReverbParameter(data: any): void;
234
+ handleGlobalParameterControlSysEx(data: any): void;
235
+ handleReverbParameterSysEx(data: any): void;
231
236
  setReverbType(type: any): void;
232
237
  getReverbTimeFromType(type: any): number | undefined;
233
238
  setReverbTime(value: any): void;
234
239
  getReverbTime(value: any): number;
235
240
  calcDelay(rt60: any, feedback: any): number;
236
- handleChorusParameter(data: any): void;
241
+ handleChorusParameterSysEx(data: any): void;
237
242
  setChorusType(type: any): void;
243
+ setChorusParameter(modRate: any, modDepth: any, feedback: any, sendToReverb: any): void;
238
244
  setChorusModRate(value: any): void;
245
+ getChorusModRate(value: any): number;
239
246
  setChorusModDepth(value: any): void;
247
+ getChorusModDepth(value: any): number;
240
248
  setChorusFeedback(value: any): void;
249
+ getChorusFeedback(value: any): number;
241
250
  setChorusSendToReverb(value: any): void;
251
+ getChorusSendToReverb(value: any): number;
242
252
  handleExclusiveMessage(data: any): void;
243
253
  handleSysEx(data: any): void;
244
254
  scheduleTask(callback: any, startTime: any): Promise<any>;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"AAuBA;IAiCE;;;;;;;;;;;;;;;;;MAiBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAgCF;;;;;OAOC;IA9GD,qBAAmB;IACnB,kBAAc;IACd,yBAAqB;IACrB,2BAAuB;IACvB;;;MAGE;IACF;;;;;MAKE;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;IA2ClB;;;;;MA4BE;IAGA,kBAAgC;IAChC;;;;;MAAqD;IACrD,gBAA4C;IAE5C,gBAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;MAkBC;IAED,yCAcC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EAkDC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAgGC;IAED,4BAsBC;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;;;MAiCC;IAED;;;;;;MAoCC;IAED,kDAsBC;IAED,2BAEC;IAED,4BAEC;IAED,sCAKC;IAED,mFAGC;IAED,iDAiBC;IAED,iDAiCC;IAED,0DAmBC;IAED,wHAiCC;IAED,gDAQC;IAED,kGAgCC;IAED,0EAGC;IAED,sIAiDC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,wFAmBC;IAED,4DAIC;IAED,+DAcC;IAED,qEAGC;IAED,uDAOC;IAED,mFAuDC;IAED,+CAEC;IAED,qCAcC;IAED,yDAIC;IAED,iEAEC;IAED,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,+CAEC;IAED,mDAGC;IAED,sCAUC;IAED,sDAMC;IAGD,oDAEC;IAED,mEAOC;IAED,mEAIC;IAED,wDAWC;IAED,uDAGC;IAED,kFAeC;IAED,2DAMC;IAED,oCAqBC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,oDAUC;IAED,kDAKC;IAED,iEAOC;IAED,8CAKC;IAED,yDAMC;IAED,gDAKC;IAED,6DAMC;IAED,wDAKC;IAED,6EAKC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAiDC;IAED,yCAGC;IAED,mCAQC;IAED,6CAGC;IAED,2CAMC;IAED,+CAGC;IAED,+CAMC;IAED,8CAeC;IAED,uCAOC;IAED,+BAOC;IAED,qDAiBC;IAED,gCAMC;IAED,kCAEC;IA2BD,4CAEC;IAED,uCAaC;IAED,+BAEC;IAED,mCAEC;IAED,oCAEC;IAED,oCAEC;IAED,wCAEC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAhsDD;IASE,gFAKC;IAbD,kBAAa;IACb,cAAS;IACT,gBAAW;IACX,YAAO;IACP,gBAAW;IACX,YAAO;IACP,gBAAW;IAGT,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
1
+ {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"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"}