@marmooo/midy 0.0.9 → 0.1.0

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.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAuBA;IAwBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IASF;;;;;;;OAOC;IAjFD,qBAAmB;IACnB,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;IA8ClB;;;;;;;MAKE;IAGA,kBAAgC;IAChC;;;;;;;MAAqD;IACrD,gBAA4C;IAE5C,gBAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;;;;MAkBC;IAED,yCAiBC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EAyDC;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;;;;;;MA4CC;IAED,gFAUC;IAED,mFAYC;IAID;;;;;MAuCC;IAED;;;;;;MAoCC;IAED,kDAuBC;IAED,2BAEC;IAED,4BAEC;IAED,sCAKC;IAED,mFAGC;IAED,iDAiBC;IAED,iDAiCC;IAED,0DAmBC;IAED,uDAcC;IAED,wHAqCC;IAED,gDAQC;IAED,kGAgCC;IAED,0EAGC;IAED,sIAiDC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,wFAqBC;IAED,sFAcC;IAED,4DAIC;IAED,+DAcC;IAED,qEAGC;IAED,uDAOC;IAED,mFAkEC;IAED,+CAEC;IAED,qCAcC;IAED,yDAIC;IAED,iEAEC;IAED,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,+CAEC;IAED,mDAGC;IAED,sCAUC;IAED,sDAMC;IAED,oDAEC;IAED,0DASC;IAED,0DAIC;IAED,wDAWC;IAED,uDAGC;IAED,2DAGC;IAED,6DAGC;IAED,6DASC;IAED,kFAeC;IAED,2DAMC;IAED,gDAyBC;IAED,wCAEC;IAED,wCAEC;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,yDAgDC;IAED,yCAGC;IAED,mCAQC;IAED,6CAGC;IAED,2CAMC;IAED,+CAGC;IAED,+CAMC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AA5nDD;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.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
package/script/midy.js CHANGED
@@ -67,12 +67,6 @@ class Midy {
67
67
  writable: true,
68
68
  value: 0
69
69
  });
70
- Object.defineProperty(this, "reverbFactor", {
71
- enumerable: true,
72
- configurable: true,
73
- writable: true,
74
- value: 0.1
75
- });
76
70
  Object.defineProperty(this, "masterFineTuning", {
77
71
  enumerable: true,
78
72
  configurable: true,
@@ -85,6 +79,26 @@ class Midy {
85
79
  writable: true,
86
80
  value: 0
87
81
  }); // cb
82
+ Object.defineProperty(this, "reverb", {
83
+ enumerable: true,
84
+ configurable: true,
85
+ writable: true,
86
+ value: {
87
+ time: this.getReverbTime(64),
88
+ feedback: 0.2,
89
+ }
90
+ });
91
+ Object.defineProperty(this, "chorus", {
92
+ enumerable: true,
93
+ configurable: true,
94
+ writable: true,
95
+ value: {
96
+ modRate: 3 * 0.122,
97
+ modDepth: (3 + 1) / 3.2,
98
+ feedback: 8 * 0.763,
99
+ sendToReverb: 0 * 0.787,
100
+ }
101
+ });
88
102
  Object.defineProperty(this, "mono", {
89
103
  enumerable: true,
90
104
  configurable: true,
@@ -193,8 +207,19 @@ class Midy {
193
207
  writable: true,
194
208
  value: {
195
209
  reverbAlgorithm: (audioContext) => {
196
- // return this.createConvolutionReverb(audioContext);
197
- return this.createSchroederReverb(audioContext);
210
+ const { time: rt60, feedback } = this.reverb;
211
+ // const delay = this.calcDelay(rt60, feedback);
212
+ // const impulse = this.createConvolutionReverbImpulse(
213
+ // audioContext,
214
+ // rt60,
215
+ // delay,
216
+ // );
217
+ // return this.createConvolutionReverb(audioContext, impulse);
218
+ const combFeedbacks = this.generateDistributedArray(feedback, 4);
219
+ const combDelays = combFeedbacks.map((feedback) => this.calcDelay(rt60, feedback));
220
+ const allpassFeedbacks = this.generateDistributedArray(feedback, 4);
221
+ const allpassDelays = allpassFeedbacks.map((feedback) => this.calcDelay(rt60, feedback));
222
+ return this.createSchroederReverb(audioContext, combFeedbacks, combDelays, allpassFeedbacks, allpassDelays);
198
223
  },
199
224
  }
200
225
  });
@@ -599,12 +624,7 @@ class Midy {
599
624
  }
600
625
  return noteList[0];
601
626
  }
602
- createConvolutionReverb(audioContext, options = {}) {
603
- const { decay = 0.8, preDecay = 0, } = options;
604
- const input = new GainNode(audioContext);
605
- const output = new GainNode(audioContext);
606
- const dryGain = new GainNode(audioContext);
607
- const wetGain = new GainNode(audioContext);
627
+ createConvolutionReverbImpulse(audioContext, decay, preDecay) {
608
628
  const sampleRate = audioContext.sampleRate;
609
629
  const length = sampleRate * decay;
610
630
  const impulse = new AudioBuffer({
@@ -624,18 +644,17 @@ class Midy {
624
644
  channelData[i] = (Math.random() * 2 - 1) * attenuation;
625
645
  }
626
646
  }
647
+ return impulse;
648
+ }
649
+ createConvolutionReverb(audioContext, impulse) {
650
+ const output = new GainNode(audioContext);
627
651
  const convolverNode = new ConvolverNode(audioContext, {
628
652
  buffer: impulse,
629
653
  });
630
- input.connect(convolverNode);
631
- convolverNode.connect(wetGain);
632
- wetGain.connect(output);
633
- dryGain.connect(output);
654
+ convolverNode.connect(output);
634
655
  return {
635
- input,
656
+ input: convolverNode,
636
657
  output,
637
- dryGain,
638
- wetGain,
639
658
  convolverNode,
640
659
  };
641
660
  }
@@ -663,17 +682,24 @@ class Midy {
663
682
  delayNode.connect(passGain);
664
683
  return passGain;
665
684
  }
685
+ generateDistributedArray(center, count, varianceRatio = 0.1, randomness = 0.05) {
686
+ const variance = center * varianceRatio;
687
+ const array = new Array(count);
688
+ for (let i = 0; i < count; i++) {
689
+ const fraction = i / (count - 1 || 1);
690
+ const value = center - variance + fraction * 2 * variance;
691
+ array[i] = value * (1 - (Math.random() * 2 - 1) * randomness);
692
+ }
693
+ return array;
694
+ }
666
695
  // https://hajim.rochester.edu/ece/sites/zduan/teaching/ece472/reading/Schroeder_1962.pdf
667
696
  // M.R.Schroeder, "Natural Sounding Artificial Reverberation", J.Audio Eng. Soc., vol.10, p.219, 1962
668
- createSchroederReverb(audioContext, options = {}) {
669
- const { combDelays = [0.31, 0.34, 0.37, 0.40], combFeedbacks = [0.86, 0.87, 0.88, 0.89], allpassDelays = [0.02, 0.05], allpassFeedbacks = [0.7, 0.7], mix = 0.5, } = options;
697
+ createSchroederReverb(audioContext, combDelays, combFeedbacks, allpassDelays, allpassFeedbacks) {
670
698
  const input = new GainNode(audioContext);
671
699
  const output = new GainNode(audioContext);
672
700
  const mergerGain = new GainNode(audioContext, {
673
701
  gain: 1 / (combDelays.length * 2),
674
702
  });
675
- const dryGain = new GainNode(audioContext, { gain: 1 - mix });
676
- const wetGain = new GainNode(audioContext, { gain: mix });
677
703
  for (let i = 0; i < combDelays.length; i++) {
678
704
  const comb = this.createCombFilter(audioContext, input, combDelays[i], combFeedbacks[i]);
679
705
  comb.connect(mergerGain);
@@ -683,11 +709,8 @@ class Midy {
683
709
  const allpass = this.createAllpassFilter(audioContext, (i === 0) ? mergerGain : allpasses.at(-1), allpassDelays[i], allpassFeedbacks[i]);
684
710
  allpasses.push(allpass);
685
711
  }
686
- allpasses.at(-1).connect(wetGain);
687
- input.connect(dryGain);
688
- dryGain.connect(output);
689
- wetGain.connect(output);
690
- return { input, output, dryGain, wetGain };
712
+ allpasses.at(-1).connect(output);
713
+ return { input, output };
691
714
  }
692
715
  createChorusEffect(audioContext, options = {}) {
693
716
  const { chorusCount = 2, chorusRate = 0.6, chorusDepth = 0.15, delay = 0.01, variance = delay * 0.1, } = options;
@@ -722,11 +745,9 @@ class Midy {
722
745
  }
723
746
  connectEffects(channel, gainNode) {
724
747
  gainNode.connect(channel.merger);
725
- if (channel.reverb === 0) {
726
- if (channel.chorus === 0) { // no effect
727
- channel.merger.connect(this.masterGain);
728
- }
729
- else { // chorus
748
+ channel.merger.connect(this.masterGain);
749
+ if (channel.reverbSendLevel === 0) {
750
+ if (channel.chorusSendLevel !== 0) { // chorus
730
751
  channel.chorusEffect.delayNodes.forEach((delayNode) => {
731
752
  channel.merger.connect(delayNode);
732
753
  });
@@ -734,7 +755,7 @@ class Midy {
734
755
  }
735
756
  }
736
757
  else {
737
- if (channel.chorus === 0) { // reverb
758
+ if (channel.chorusSendLevel === 0) { // reverb
738
759
  channel.merger.connect(channel.reverbEffect.input);
739
760
  channel.reverbEffect.output.connect(this.masterGain);
740
761
  }
@@ -1190,23 +1211,22 @@ class Midy {
1190
1211
  this.releaseSustainPedal(channelNumber, value);
1191
1212
  }
1192
1213
  }
1214
+ // TODO
1193
1215
  setPortamento(channelNumber, value) {
1194
1216
  this.channels[channelNumber].portamento = value >= 64;
1195
1217
  }
1196
- setReverbSendLevel(channelNumber, reverb) {
1218
+ setReverbSendLevel(channelNumber, reverbSendLevel) {
1197
1219
  const now = this.audioContext.currentTime;
1198
1220
  const channel = this.channels[channelNumber];
1199
1221
  const reverbEffect = channel.reverbEffect;
1200
- channel.reverb = reverb / 127 * this.reverbFactor;
1201
- reverbEffect.dryGain.gain.cancelScheduledValues(now);
1202
- reverbEffect.dryGain.gain.setValueAtTime(1 - channel.reverb, now);
1203
- reverbEffect.wetGain.gain.cancelScheduledValues(now);
1204
- reverbEffect.wetGain.gain.setValueAtTime(channel.reverb, now);
1222
+ channel.reverbSendLevel = reverbSendLevel / 127;
1223
+ reverbEffect.output.gain.cancelScheduledValues(now);
1224
+ reverbEffect.output.gain.setValueAtTime(channel.reverbSendLevel, now);
1205
1225
  }
1206
- setChorusSendLevel(channelNumber, chorus) {
1226
+ setChorusSendLevel(channelNumber, chorusSendLevel) {
1207
1227
  const channel = this.channels[channelNumber];
1208
- channel.chorus = chorus / 127;
1209
- channel.chorusEffect.lfoGain = channel.chorus;
1228
+ channel.chorusSendLevel = chorusSendLevel / 127;
1229
+ channel.chorusEffect.lfoGain = channel.chorusSendLevel;
1210
1230
  }
1211
1231
  setSostenutoPedal(channelNumber, value) {
1212
1232
  const isOn = value >= 64;
@@ -1430,11 +1450,11 @@ class Midy {
1430
1450
  this.GM2SystemOn();
1431
1451
  break;
1432
1452
  default:
1433
- console.warn(`Unsupported Exclusive Message ${data}`);
1453
+ console.warn(`Unsupported Exclusive Message: ${data}`);
1434
1454
  }
1435
1455
  break;
1436
1456
  default:
1437
- console.warn(`Unsupported Exclusive Message ${data}`);
1457
+ console.warn(`Unsupported Exclusive Message: ${data}`);
1438
1458
  }
1439
1459
  }
1440
1460
  GM1SystemOn() {
@@ -1465,9 +1485,10 @@ class Midy {
1465
1485
  return this.handleMasterFineTuningSysEx(data);
1466
1486
  case 4: // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/ca25.pdf
1467
1487
  return this.handleMasterCoarseTuningSysEx(data);
1468
- // case 5: // TODO: Global Parameter Control
1488
+ case 5:
1489
+ return this.handleGlobalParameterControl(data);
1469
1490
  default:
1470
- console.warn(`Unsupported Exclusive Message ${data}`);
1491
+ console.warn(`Unsupported Exclusive Message: ${data}`);
1471
1492
  }
1472
1493
  break;
1473
1494
  case 8:
@@ -1476,7 +1497,7 @@ class Midy {
1476
1497
  // // TODO
1477
1498
  // return this.handleScaleOctaveTuning1ByteFormat();
1478
1499
  default:
1479
- console.warn(`Unsupported Exclusive Message ${data}`);
1500
+ console.warn(`Unsupported Exclusive Message: ${data}`);
1480
1501
  }
1481
1502
  break;
1482
1503
  case 9:
@@ -1488,7 +1509,7 @@ class Midy {
1488
1509
  // // TODO
1489
1510
  // return this.setControlChange();
1490
1511
  default:
1491
- console.warn(`Unsupported Exclusive Message ${data}`);
1512
+ console.warn(`Unsupported Exclusive Message: ${data}`);
1492
1513
  }
1493
1514
  break;
1494
1515
  case 10:
@@ -1497,11 +1518,11 @@ class Midy {
1497
1518
  // // TODO
1498
1519
  // return this.handleKeyBasedInstrumentControl();
1499
1520
  default:
1500
- console.warn(`Unsupported Exclusive Message ${data}`);
1521
+ console.warn(`Unsupported Exclusive Message: ${data}`);
1501
1522
  }
1502
1523
  break;
1503
1524
  default:
1504
- console.warn(`Unsupported Exclusive Message ${data}`);
1525
+ console.warn(`Unsupported Exclusive Message: ${data}`);
1505
1526
  }
1506
1527
  }
1507
1528
  handleMasterVolumeSysEx(data) {
@@ -1542,8 +1563,124 @@ class Midy {
1542
1563
  this.masterCoarseTuning = coarseTuning - 64;
1543
1564
  }
1544
1565
  }
1566
+ handleGlobalParameterControl(data) {
1567
+ if (data[5] === 1) {
1568
+ switch (data[6]) {
1569
+ case 1:
1570
+ return this.handleReverbParameter(data);
1571
+ case 2:
1572
+ return this.handleChorusParameter(data);
1573
+ default:
1574
+ console.warn(`Unsupported Global Parameter Control Message: ${data}`);
1575
+ }
1576
+ }
1577
+ else {
1578
+ console.warn(`Unsupported Global Parameter Control Message: ${data}`);
1579
+ }
1580
+ }
1581
+ handleReverbParameter(data) {
1582
+ switch (data[7]) {
1583
+ case 0:
1584
+ return this.setReverbType(data[8]);
1585
+ case 1:
1586
+ return this.setReverbTime(data[8]);
1587
+ }
1588
+ }
1589
+ setReverbType(type) {
1590
+ this.reverb.time = this.getReverbTimeFromType(type);
1591
+ this.reverb.feedback = (type === 8) ? 0.1 : 0.2;
1592
+ const { audioContext, channels, options } = this;
1593
+ for (let i = 0; i < channels.length; i++) {
1594
+ channels[i].reverbEffect = options.reverbAlgorithm(audioContext);
1595
+ }
1596
+ }
1597
+ getReverbTimeFromType(type) {
1598
+ switch (type) {
1599
+ case 0:
1600
+ return this.getReverbTime(44);
1601
+ case 1:
1602
+ return this.getReverbTime(50);
1603
+ case 2:
1604
+ return this.getReverbTime(56);
1605
+ case 3:
1606
+ return this.getReverbTime(64);
1607
+ case 4:
1608
+ return this.getReverbTime(64);
1609
+ case 8:
1610
+ return this.getReverbTime(50);
1611
+ default:
1612
+ console.warn(`Unsupported Reverb Time: ${type}`);
1613
+ }
1614
+ }
1615
+ setReverbTime(value) {
1616
+ this.reverb.time = this.getReverbTime(value);
1617
+ const { audioContext, channels, options } = this;
1618
+ for (let i = 0; i < channels.length; i++) {
1619
+ channels[i].reverbEffect = options.reverbAlgorithm(audioContext);
1620
+ }
1621
+ }
1622
+ getReverbTime(value) {
1623
+ return Math.pow(Math.E, (value - 40) * 0.025);
1624
+ }
1625
+ // mean free path equation
1626
+ // https://repository.dl.itc.u-tokyo.ac.jp/record/8550/files/A31912.pdf
1627
+ // 江田和司, 拡散性制御に基づく室内音響設計に向けた音場解析に関する研究, 2015
1628
+ // V: room size (m^3)
1629
+ // S: room surface area (m^2)
1630
+ // meanFreePath = 4V / S (m)
1631
+ // delay estimation using mean free path
1632
+ // t: degree Celsius, generally used 20
1633
+ // c: speed of sound = 331.5 + 0.61t = 331.5 * 0.61 * 20 = 343.7 (m/s)
1634
+ // delay = meanFreePath / c (s)
1635
+ // feedback equation
1636
+ // RT60 means that the energy is reduced to Math.pow(10, -6).
1637
+ // Since energy is proportional to the square of the amplitude,
1638
+ // the amplitude is reduced to Math.pow(10, -3).
1639
+ // When this is done through n feedbacks,
1640
+ // Math.pow(feedback, n) = Math.pow(10, -3)
1641
+ // Math.pow(feedback, RT60 / delay) = Math.pow(10, -3)
1642
+ // RT60 / delay * Math.log10(feedback) = -3
1643
+ // RT60 = -3 * delay / Math.log10(feedback)
1644
+ // feedback = Math.pow(10, -3 * delay / RT60)
1645
+ // delay estimation using ideal feedback
1646
+ // A suitable average sound absorption coefficient is 0.18-0.28.
1647
+ // Since the structure of the hall is complex,
1648
+ // It would be easier to determine the delay based on the ideal feedback.
1649
+ // delay = -RT60 * Math.log10(feedback) / 3
1650
+ calcDelay(rt60, feedback) {
1651
+ return -rt60 * Math.log10(feedback) / 3;
1652
+ }
1653
+ handleChorusParameter(data) {
1654
+ switch (data[7]) {
1655
+ case 0:
1656
+ return this.setChorusType(data[8]);
1657
+ case 1:
1658
+ return this.setChorusModRate(data[8]);
1659
+ case 2:
1660
+ return this.setChorusModDepth(data[8]);
1661
+ case 3:
1662
+ return this.setChorusFeedback(data[8]);
1663
+ case 4:
1664
+ return this.setChorusSendToReverb(data[8]);
1665
+ }
1666
+ }
1667
+ setChorusType(type) {
1668
+ // TODO
1669
+ }
1670
+ setChorusModRate(value) {
1671
+ // TODO
1672
+ }
1673
+ setChorusModDepth(value) {
1674
+ // TODO
1675
+ }
1676
+ setChorusFeedback(value) {
1677
+ // TODO
1678
+ }
1679
+ setChorusSendToReverb(value) {
1680
+ // TODO
1681
+ }
1545
1682
  handleExclusiveMessage(data) {
1546
- console.warn(`Unsupported Exclusive Message ${data}`);
1683
+ console.warn(`Unsupported Exclusive Message: ${data}`);
1547
1684
  }
1548
1685
  handleSysEx(data) {
1549
1686
  switch (data[0]) {
@@ -1577,8 +1714,8 @@ Object.defineProperty(Midy, "channelSettings", {
1577
1714
  volume: 100 / 127,
1578
1715
  pan: 64,
1579
1716
  portamentoTime: 0,
1580
- reverb: 0,
1581
- chorus: 0,
1717
+ reverbSendLevel: 0,
1718
+ chorusSendLevel: 0,
1582
1719
  vibratoRate: 5,
1583
1720
  vibratoDepth: 0.5,
1584
1721
  vibratoDelay: 2.5,