@marmooo/midy 0.2.5 → 0.2.6

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-GM2.js CHANGED
@@ -66,31 +66,37 @@ class Note {
66
66
  writable: true,
67
67
  value: void 0
68
68
  });
69
+ Object.defineProperty(this, "filterDepth", {
70
+ enumerable: true,
71
+ configurable: true,
72
+ writable: true,
73
+ value: void 0
74
+ });
69
75
  Object.defineProperty(this, "volumeEnvelopeNode", {
70
76
  enumerable: true,
71
77
  configurable: true,
72
78
  writable: true,
73
79
  value: void 0
74
80
  });
75
- Object.defineProperty(this, "volumeNode", {
81
+ Object.defineProperty(this, "volumeDepth", {
76
82
  enumerable: true,
77
83
  configurable: true,
78
84
  writable: true,
79
85
  value: void 0
80
86
  });
81
- Object.defineProperty(this, "gainL", {
87
+ Object.defineProperty(this, "volumeNode", {
82
88
  enumerable: true,
83
89
  configurable: true,
84
90
  writable: true,
85
91
  value: void 0
86
92
  });
87
- Object.defineProperty(this, "gainR", {
93
+ Object.defineProperty(this, "gainL", {
88
94
  enumerable: true,
89
95
  configurable: true,
90
96
  writable: true,
91
97
  value: void 0
92
98
  });
93
- Object.defineProperty(this, "volumeDepth", {
99
+ Object.defineProperty(this, "gainR", {
94
100
  enumerable: true,
95
101
  configurable: true,
96
102
  writable: true,
@@ -492,6 +498,9 @@ export class MidyGM2 {
492
498
  ...this.setChannelAudioNodes(audioContext),
493
499
  scheduledNotes: new SparseMap(128),
494
500
  sostenutoNotes: new SparseMap(128),
501
+ scaleOctaveTuningTable: new Int8Array(12), // [-64, 63] cent
502
+ channelPressureTable: new Uint8Array([64, 64, 64, 0, 0, 0]),
503
+ keyBasedInstrumentControlTable: new Int8Array(128 * 128), // [-64, 63]
495
504
  };
496
505
  });
497
506
  return channels;
@@ -558,10 +567,11 @@ export class MidyGM2 {
558
567
  const event = this.timeline[queueIndex];
559
568
  if (event.startTime > t + this.lookAhead)
560
569
  break;
570
+ const startTime = event.startTime + this.startDelay - offset;
561
571
  switch (event.type) {
562
572
  case "noteOn":
563
573
  if (event.velocity !== 0) {
564
- await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset, event.portamento);
574
+ await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime, event.portamento);
565
575
  break;
566
576
  }
567
577
  /* falls through */
@@ -569,26 +579,26 @@ export class MidyGM2 {
569
579
  const portamentoTarget = this.findPortamentoTarget(queueIndex);
570
580
  if (portamentoTarget)
571
581
  portamentoTarget.portamento = true;
572
- const notePromise = this.scheduleNoteRelease(this.omni ? 0 : event.channel, event.noteNumber, event.velocity, event.startTime + this.startDelay - offset, portamentoTarget?.noteNumber, false);
582
+ const notePromise = this.scheduleNoteRelease(this.omni ? 0 : event.channel, event.noteNumber, event.velocity, startTime, portamentoTarget?.noteNumber, false);
573
583
  if (notePromise) {
574
584
  this.notePromises.push(notePromise);
575
585
  }
576
586
  break;
577
587
  }
578
588
  case "controller":
579
- this.handleControlChange(this.omni ? 0 : event.channel, event.controllerType, event.value);
589
+ this.handleControlChange(this.omni ? 0 : event.channel, event.controllerType, event.value, startTime);
580
590
  break;
581
591
  case "programChange":
582
- this.handleProgramChange(event.channel, event.programNumber);
592
+ this.handleProgramChange(event.channel, event.programNumber, startTime);
583
593
  break;
584
594
  case "channelAftertouch":
585
- this.handleChannelPressure(event.channel, event.amount);
595
+ this.handleChannelPressure(event.channel, event.amount, startTime);
586
596
  break;
587
597
  case "pitchBend":
588
- this.setPitchBend(event.channel, event.value + 8192);
598
+ this.setPitchBend(event.channel, event.value + 8192, startTime);
589
599
  break;
590
600
  case "sysEx":
591
- this.handleSysEx(event.data);
601
+ this.handleSysEx(event.data, startTime);
592
602
  }
593
603
  queueIndex++;
594
604
  }
@@ -835,6 +845,18 @@ export class MidyGM2 {
835
845
  const now = this.audioContext.currentTime;
836
846
  return this.resumeTime + now - this.startTime - this.startDelay;
837
847
  }
848
+ processScheduledNotes(channel, scheduleTime, callback) {
849
+ channel.scheduledNotes.forEach((noteList) => {
850
+ for (let i = 0; i < noteList.length; i++) {
851
+ const note = noteList[i];
852
+ if (!note)
853
+ continue;
854
+ if (scheduleTime < note.startTime)
855
+ continue;
856
+ callback(note);
857
+ }
858
+ });
859
+ }
838
860
  getActiveNotes(channel, time) {
839
861
  const activeNotes = new SparseMap(128);
840
862
  channel.scheduledNotes.forEach((noteList) => {
@@ -1016,14 +1038,14 @@ export class MidyGM2 {
1016
1038
  const note = noteList[i];
1017
1039
  if (!note)
1018
1040
  continue;
1019
- this.updateDetune(channel, note, 0);
1041
+ this.updateDetune(channel, note);
1020
1042
  }
1021
1043
  });
1022
1044
  }
1023
- updateDetune(channel, note, pressure) {
1045
+ updateDetune(channel, note) {
1024
1046
  const now = this.audioContext.currentTime;
1025
1047
  const noteDetune = this.calcNoteDetune(channel, note);
1026
- const detune = channel.detune + noteDetune + pressure;
1048
+ const detune = channel.detune + noteDetune;
1027
1049
  note.bufferSource.detune
1028
1050
  .cancelScheduledValues(now)
1029
1051
  .setValueAtTime(detune, now);
@@ -1045,11 +1067,11 @@ export class MidyGM2 {
1045
1067
  .setValueAtTime(0, volDelay)
1046
1068
  .linearRampToValueAtTime(sustainVolume, portamentoTime);
1047
1069
  }
1048
- setVolumeEnvelope(note, pressure) {
1070
+ setVolumeEnvelope(channel, note) {
1049
1071
  const now = this.audioContext.currentTime;
1050
1072
  const { voiceParams, startTime } = note;
1051
1073
  const attackVolume = this.cbToRatio(-voiceParams.initialAttenuation) *
1052
- (1 + pressure);
1074
+ (1 + this.getAmplitudeControl(channel));
1053
1075
  const sustainVolume = attackVolume * (1 - voiceParams.volSustain);
1054
1076
  const volDelay = startTime + voiceParams.volDelay;
1055
1077
  const volAttack = volDelay + voiceParams.volAttack;
@@ -1063,20 +1085,20 @@ export class MidyGM2 {
1063
1085
  .setValueAtTime(attackVolume, volHold)
1064
1086
  .linearRampToValueAtTime(sustainVolume, volDecay);
1065
1087
  }
1066
- setPitchEnvelope(note) {
1067
- const now = this.audioContext.currentTime;
1088
+ setPitchEnvelope(note, scheduleTime) {
1089
+ scheduleTime ??= this.audioContext.currentTime;
1068
1090
  const { voiceParams } = note;
1069
1091
  const baseRate = voiceParams.playbackRate;
1070
1092
  note.bufferSource.playbackRate
1071
- .cancelScheduledValues(now)
1072
- .setValueAtTime(baseRate, now);
1093
+ .cancelScheduledValues(scheduleTime)
1094
+ .setValueAtTime(baseRate, scheduleTime);
1073
1095
  const modEnvToPitch = voiceParams.modEnvToPitch;
1074
1096
  if (modEnvToPitch === 0)
1075
1097
  return;
1076
1098
  const basePitch = this.rateToCent(baseRate);
1077
1099
  const peekPitch = basePitch + modEnvToPitch;
1078
1100
  const peekRate = this.centToRate(peekPitch);
1079
- const modDelay = startTime + voiceParams.modDelay;
1101
+ const modDelay = note.startTime + voiceParams.modDelay;
1080
1102
  const modAttack = modDelay + voiceParams.modAttack;
1081
1103
  const modHold = modAttack + voiceParams.modHold;
1082
1104
  const modDecay = modHold + voiceParams.modDecay;
@@ -1112,13 +1134,14 @@ export class MidyGM2 {
1112
1134
  .setValueAtTime(adjustedBaseFreq, modDelay)
1113
1135
  .linearRampToValueAtTime(adjustedSustainFreq, portamentoTime);
1114
1136
  }
1115
- setFilterEnvelope(channel, note, pressure) {
1137
+ setFilterEnvelope(channel, note) {
1116
1138
  const now = this.audioContext.currentTime;
1117
1139
  const state = channel.state;
1118
1140
  const { voiceParams, noteNumber, startTime } = note;
1119
1141
  const softPedalFactor = 1 -
1120
1142
  (0.1 + (noteNumber / 127) * 0.2) * state.softPedal;
1121
- const baseCent = voiceParams.initialFilterFc + pressure;
1143
+ const baseCent = voiceParams.initialFilterFc +
1144
+ this.getFilterCutoffControl(channel);
1122
1145
  const baseFreq = this.centToHz(baseCent) * softPedalFactor;
1123
1146
  const peekFreq = this.centToHz(baseCent + voiceParams.modEnvToFilterFc) *
1124
1147
  softPedalFactor;
@@ -1148,9 +1171,9 @@ export class MidyGM2 {
1148
1171
  gain: voiceParams.modLfoToFilterFc,
1149
1172
  });
1150
1173
  note.modulationDepth = new GainNode(this.audioContext);
1151
- this.setModLfoToPitch(channel, note, 0);
1174
+ this.setModLfoToPitch(channel, note);
1152
1175
  note.volumeDepth = new GainNode(this.audioContext);
1153
- this.setModLfoToVolume(note, 0);
1176
+ this.setModLfoToVolume(channel, note);
1154
1177
  note.modulationLFO.start(startTime + voiceParams.delayModLFO);
1155
1178
  note.modulationLFO.connect(note.filterDepth);
1156
1179
  note.filterDepth.connect(note.filterNode.frequency);
@@ -1211,8 +1234,8 @@ export class MidyGM2 {
1211
1234
  }
1212
1235
  else {
1213
1236
  note.portamento = false;
1214
- this.setVolumeEnvelope(note, 0);
1215
- this.setFilterEnvelope(channel, note, 0);
1237
+ this.setVolumeEnvelope(channel, note);
1238
+ this.setFilterEnvelope(channel, note);
1216
1239
  }
1217
1240
  if (0 < state.vibratoDepth) {
1218
1241
  this.startVibrato(channel, note, startTime);
@@ -1426,8 +1449,9 @@ export class MidyGM2 {
1426
1449
  channel.bank = channel.bankMSB * 128 + channel.bankLSB;
1427
1450
  channel.program = program;
1428
1451
  }
1429
- handleChannelPressure(channelNumber, value) {
1430
- const now = this.audioContext.currentTime;
1452
+ handleChannelPressure(channelNumber, value, startTime) {
1453
+ if (!startTime)
1454
+ startTime = this.audioContext.currentTime;
1431
1455
  const channel = this.channels[channelNumber];
1432
1456
  const prev = channel.state.channelPressure;
1433
1457
  const next = value / 127;
@@ -1437,8 +1461,8 @@ export class MidyGM2 {
1437
1461
  channel.detune += pressureDepth * (next - prev);
1438
1462
  }
1439
1463
  const table = channel.channelPressureTable;
1440
- this.getActiveNotes(channel, now).forEach((note) => {
1441
- this.applyDestinationSettings(channel, note, table);
1464
+ this.getActiveNotes(channel, startTime).forEach((note) => {
1465
+ this.setControllerParameters(channel, note, table);
1442
1466
  });
1443
1467
  // this.applyVoiceParams(channel, 13);
1444
1468
  }
@@ -1456,9 +1480,10 @@ export class MidyGM2 {
1456
1480
  this.updateChannelDetune(channel);
1457
1481
  this.applyVoiceParams(channel, 14);
1458
1482
  }
1459
- setModLfoToPitch(channel, note, pressure) {
1483
+ setModLfoToPitch(channel, note) {
1460
1484
  const now = this.audioContext.currentTime;
1461
- const modLfoToPitch = note.voiceParams.modLfoToPitch + pressure;
1485
+ const modLfoToPitch = note.voiceParams.modLfoToPitch +
1486
+ this.getLFOPitchDepth(channel);
1462
1487
  const baseDepth = Math.abs(modLfoToPitch) + channel.state.modulationDepth;
1463
1488
  const modulationDepth = baseDepth * Math.sign(modLfoToPitch);
1464
1489
  note.modulationDepth.gain
@@ -1475,18 +1500,20 @@ export class MidyGM2 {
1475
1500
  .cancelScheduledValues(now)
1476
1501
  .setValueAtTime(vibratoDepth * vibratoDepthSign, now);
1477
1502
  }
1478
- setModLfoToFilterFc(note, pressure) {
1503
+ setModLfoToFilterFc(channel, note) {
1479
1504
  const now = this.audioContext.currentTime;
1480
- const modLfoToFilterFc = note.voiceParams.modLfoToFilterFc + pressure;
1505
+ const modLfoToFilterFc = note.voiceParams.modLfoToFilterFc +
1506
+ this.getLFOFilterDepth(channel);
1481
1507
  note.filterDepth.gain
1482
1508
  .cancelScheduledValues(now)
1483
1509
  .setValueAtTime(modLfoToFilterFc, now);
1484
1510
  }
1485
- setModLfoToVolume(note, pressure) {
1511
+ setModLfoToVolume(channel, note) {
1486
1512
  const now = this.audioContext.currentTime;
1487
1513
  const modLfoToVolume = note.voiceParams.modLfoToVolume;
1488
1514
  const baseDepth = this.cbToRatio(Math.abs(modLfoToVolume)) - 1;
1489
- const volumeDepth = baseDepth * Math.sign(modLfoToVolume) * (1 + pressure);
1515
+ const volumeDepth = baseDepth * Math.sign(modLfoToVolume) *
1516
+ (1 + this.getLFOAmplitudeDepth(channel));
1490
1517
  note.volumeDepth.gain
1491
1518
  .cancelScheduledValues(now)
1492
1519
  .setValueAtTime(volumeDepth, now);
@@ -1570,7 +1597,7 @@ export class MidyGM2 {
1570
1597
  return {
1571
1598
  modLfoToPitch: (channel, note, _prevValue) => {
1572
1599
  if (0 < channel.state.modulationDepth) {
1573
- this.setModLfoToPitch(channel, note, 0);
1600
+ this.setModLfoToPitch(channel, note);
1574
1601
  }
1575
1602
  },
1576
1603
  vibLfoToPitch: (channel, note, _prevValue) => {
@@ -1580,12 +1607,12 @@ export class MidyGM2 {
1580
1607
  },
1581
1608
  modLfoToFilterFc: (channel, note, _prevValue) => {
1582
1609
  if (0 < channel.state.modulationDepth) {
1583
- this.setModLfoToFilterFc(note, 0);
1610
+ this.setModLfoToFilterFc(channel, note);
1584
1611
  }
1585
1612
  },
1586
1613
  modLfoToVolume: (channel, note, _prevValue) => {
1587
1614
  if (0 < channel.state.modulationDepth) {
1588
- this.setModLfoToVolume(note, 0);
1615
+ this.setModLfoToVolume(channel, note);
1589
1616
  }
1590
1617
  },
1591
1618
  chorusEffectsSend: (channel, note, prevValue) => {
@@ -1655,7 +1682,7 @@ export class MidyGM2 {
1655
1682
  this.setPortamentoStartFilterEnvelope(channel, note);
1656
1683
  }
1657
1684
  else {
1658
- this.setFilterEnvelope(channel, note, 0);
1685
+ this.setFilterEnvelope(channel, note);
1659
1686
  }
1660
1687
  this.setPitchEnvelope(note);
1661
1688
  }
@@ -1669,7 +1696,7 @@ export class MidyGM2 {
1669
1696
  if (key in voiceParams)
1670
1697
  noteVoiceParams[key] = voiceParams[key];
1671
1698
  }
1672
- this.setVolumeEnvelope(note, 0);
1699
+ this.setVolumeEnvelope(channel, note);
1673
1700
  }
1674
1701
  }
1675
1702
  }
@@ -1703,10 +1730,10 @@ export class MidyGM2 {
1703
1730
  127: this.polyOn,
1704
1731
  };
1705
1732
  }
1706
- handleControlChange(channelNumber, controllerType, value) {
1733
+ handleControlChange(channelNumber, controllerType, value, startTime) {
1707
1734
  const handler = this.controlChangeHandlers[controllerType];
1708
1735
  if (handler) {
1709
- handler.call(this, channelNumber, value);
1736
+ handler.call(this, channelNumber, value, startTime);
1710
1737
  const channel = this.channels[channelNumber];
1711
1738
  this.applyVoiceParams(channel, controllerType + 128);
1712
1739
  this.applyControlTable(channel, controllerType);
@@ -1718,55 +1745,45 @@ export class MidyGM2 {
1718
1745
  setBankMSB(channelNumber, msb) {
1719
1746
  this.channels[channelNumber].bankMSB = msb;
1720
1747
  }
1721
- updateModulation(channel) {
1722
- const now = this.audioContext.currentTime;
1748
+ updateModulation(channel, scheduleTime) {
1749
+ scheduleTime ??= this.audioContext.currentTime;
1723
1750
  const depth = channel.state.modulationDepth * channel.modulationDepthRange;
1724
- channel.scheduledNotes.forEach((noteList) => {
1725
- for (let i = 0; i < noteList.length; i++) {
1726
- const note = noteList[i];
1727
- if (!note)
1728
- continue;
1729
- if (note.modulationDepth) {
1730
- note.modulationDepth.gain.setValueAtTime(depth, now);
1731
- }
1732
- else {
1733
- this.setPitchEnvelope(note);
1734
- this.startModulation(channel, note, now);
1735
- }
1751
+ this.processScheduledNotes(channel, scheduleTime, (note) => {
1752
+ if (note.modulationDepth) {
1753
+ note.modulationDepth.gain.setValueAtTime(depth, scheduleTime);
1754
+ }
1755
+ else {
1756
+ this.setPitchEnvelope(note, scheduleTime);
1757
+ this.startModulation(channel, note, scheduleTime);
1736
1758
  }
1737
1759
  });
1738
1760
  }
1739
- setModulationDepth(channelNumber, modulation) {
1761
+ setModulationDepth(channelNumber, modulation, scheduleTime) {
1740
1762
  const channel = this.channels[channelNumber];
1741
1763
  channel.state.modulationDepth = modulation / 127;
1742
- this.updateModulation(channel);
1764
+ this.updateModulation(channel, scheduleTime);
1743
1765
  }
1744
1766
  setPortamentoTime(channelNumber, portamentoTime) {
1745
1767
  const channel = this.channels[channelNumber];
1746
1768
  const factor = 5 * Math.log(10) / 127;
1747
1769
  channel.state.portamentoTime = Math.exp(factor * portamentoTime);
1748
1770
  }
1749
- setKeyBasedVolume(channel) {
1750
- const now = this.audioContext.currentTime;
1751
- channel.scheduledNotes.forEach((noteList) => {
1752
- for (let i = 0; i < noteList.length; i++) {
1753
- const note = noteList[i];
1754
- if (!note)
1755
- continue;
1756
- const keyBasedValue = this.getKeyBasedInstrumentControlValue(channel, note.noteNumber, 7);
1757
- if (keyBasedValue === 0)
1758
- continue;
1771
+ setKeyBasedVolume(channel, scheduleTime) {
1772
+ scheduleTime ??= this.audioContext.currentTime;
1773
+ this.processScheduledNotes(channel, scheduleTime, (note) => {
1774
+ const keyBasedValue = this.getKeyBasedInstrumentControlValue(channel, note.noteNumber, 7);
1775
+ if (keyBasedValue !== 0) {
1759
1776
  note.volumeNode.gain
1760
- .cancelScheduledValues(now)
1761
- .setValueAtTime(1 + keyBasedValue, now);
1777
+ .cancelScheduledValues(scheduleTime)
1778
+ .setValueAtTime(1 + keyBasedValue, scheduleTime);
1762
1779
  }
1763
1780
  });
1764
1781
  }
1765
- setVolume(channelNumber, volume) {
1782
+ setVolume(channelNumber, volume, scheduleTime) {
1766
1783
  const channel = this.channels[channelNumber];
1767
1784
  channel.state.volume = volume / 127;
1768
- this.updateChannelVolume(channel);
1769
- this.setKeyBasedVolume(channel);
1785
+ this.updateChannelVolume(channel, scheduleTime);
1786
+ this.setKeyBasedVolume(channel, scheduleTime);
1770
1787
  }
1771
1788
  panToGain(pan) {
1772
1789
  const theta = Math.PI / 2 * Math.max(0, pan * 127 - 1) / 126;
@@ -1775,36 +1792,31 @@ export class MidyGM2 {
1775
1792
  gainRight: Math.sin(theta),
1776
1793
  };
1777
1794
  }
1778
- setKeyBasedPan(channel) {
1779
- const now = this.audioContext.currentTime;
1780
- channel.scheduledNotes.forEach((noteList) => {
1781
- for (let i = 0; i < noteList.length; i++) {
1782
- const note = noteList[i];
1783
- if (!note)
1784
- continue;
1785
- const keyBasedValue = this.getKeyBasedInstrumentControlValue(channel, note.noteNumber, 10);
1786
- if (keyBasedValue === 0)
1787
- continue;
1795
+ setKeyBasedPan(channel, scheduleTime) {
1796
+ scheduleTime ??= this.audioContext.currentTime;
1797
+ this.processScheduledNotes(channel, scheduleTime, (note) => {
1798
+ const keyBasedValue = this.getKeyBasedInstrumentControlValue(channel, note.noteNumber, 10);
1799
+ if (keyBasedValue !== 0) {
1788
1800
  const { gainLeft, gainRight } = this.panToGain((keyBasedValue + 1) / 2);
1789
1801
  note.gainL.gain
1790
- .cancelScheduledValues(now)
1791
- .setValueAtTime(gainLeft, now);
1802
+ .cancelScheduledValues(scheduleTime)
1803
+ .setValueAtTime(gainLeft, scheduleTime);
1792
1804
  note.gainR.gain
1793
- .cancelScheduledValues(now)
1794
- .setValueAtTime(gainRight, now);
1805
+ .cancelScheduledValues(scheduleTime)
1806
+ .setValueAtTime(gainRight, scheduleTime);
1795
1807
  }
1796
1808
  });
1797
1809
  }
1798
- setPan(channelNumber, pan) {
1810
+ setPan(channelNumber, pan, scheduleTime) {
1799
1811
  const channel = this.channels[channelNumber];
1800
1812
  channel.state.pan = pan / 127;
1801
- this.updateChannelVolume(channel);
1802
- this.setKeyBasedPan(channel);
1813
+ this.updateChannelVolume(channel, scheduleTime);
1814
+ this.setKeyBasedPan(channel, scheduleTime);
1803
1815
  }
1804
- setExpression(channelNumber, expression) {
1816
+ setExpression(channelNumber, expression, scheduleTime) {
1805
1817
  const channel = this.channels[channelNumber];
1806
1818
  channel.state.expression = expression / 127;
1807
- this.updateChannelVolume(channel);
1819
+ this.updateChannelVolume(channel, scheduleTime);
1808
1820
  }
1809
1821
  setBankLSB(channelNumber, lsb) {
1810
1822
  this.channels[channelNumber].bankLSB = lsb;
@@ -2432,42 +2444,46 @@ export class MidyGM2 {
2432
2444
  this.updateChannelDetune(channel);
2433
2445
  }
2434
2446
  }
2435
- applyDestinationSettings(channel, note, table) {
2436
- if (table[0] !== 64) {
2437
- this.updateDetune(channel, note, 0);
2438
- }
2447
+ getFilterCutoffControl(channel) {
2448
+ const channelPressure = (channel.channelPressureTable[1] - 64) *
2449
+ channel.state.channelPressure;
2450
+ return channelPressure * 15;
2451
+ }
2452
+ getAmplitudeControl(channel) {
2453
+ const channelPressure = channel.channelPressureTable[2] *
2454
+ channel.state.channelPressure;
2455
+ return channelPressure / 64;
2456
+ }
2457
+ getLFOPitchDepth(channel) {
2458
+ const channelPressure = channel.channelPressureTable[3] *
2459
+ channel.state.channelPressure;
2460
+ return channelPressure / 127 * 600;
2461
+ }
2462
+ getLFOFilterDepth(channel) {
2463
+ const channelPressure = channel.channelPressureTable[4] *
2464
+ channel.state.channelPressure;
2465
+ return channelPressure / 127 * 2400;
2466
+ }
2467
+ getLFOAmplitudeDepth(channel) {
2468
+ const channelPressure = channel.channelPressureTable[5] *
2469
+ channel.state.channelPressure;
2470
+ return channelPressure / 127;
2471
+ }
2472
+ setControllerParameters(channel, note, table) {
2473
+ if (table[0] !== 64)
2474
+ this.updateDetune(channel, note);
2439
2475
  if (!note.portamento) {
2440
- if (table[1] !== 64) {
2441
- const channelPressure = channel.channelPressureTable[1] *
2442
- channel.state.channelPressure;
2443
- const pressure = (channelPressure - 64) * 15;
2444
- this.setFilterEnvelope(channel, note, pressure);
2445
- }
2446
- if (table[2] !== 64) {
2447
- const channelPressure = channel.channelPressureTable[2] *
2448
- channel.state.channelPressure;
2449
- const pressure = channelPressure / 64;
2450
- this.setVolumeEnvelope(note, pressure);
2451
- }
2452
- }
2453
- if (table[3] !== 0) {
2454
- const channelPressure = channel.channelPressureTable[3] *
2455
- channel.state.channelPressure;
2456
- const pressure = channelPressure / 127 * 600;
2457
- this.setModLfoToPitch(channel, note, pressure);
2458
- }
2459
- if (table[4] !== 0) {
2460
- const channelPressure = channel.channelPressureTable[4] *
2461
- channel.state.channelPressure;
2462
- const pressure = channelPressure / 127 * 2400;
2463
- this.setModLfoToFilterFc(note, pressure);
2464
- }
2465
- if (table[5] !== 0) {
2466
- const channelPressure = channel.channelPressureTable[5] *
2467
- channel.state.channelPressure;
2468
- const pressure = channelPressure / 127;
2469
- this.setModLfoToVolume(note, pressure);
2470
- }
2476
+ if (table[1] !== 64)
2477
+ this.setFilterEnvelope(channel, note);
2478
+ if (table[2] !== 64)
2479
+ this.setVolumeEnvelope(channel, note);
2480
+ }
2481
+ if (table[3] !== 0)
2482
+ this.setModLfoToPitch(channel, note);
2483
+ if (table[4] !== 0)
2484
+ this.setModLfoToFilterFc(channel, note);
2485
+ if (table[5] !== 0)
2486
+ this.setModLfoToVolume(channel, note);
2471
2487
  }
2472
2488
  handleChannelPressureSysEx(data, tableName) {
2473
2489
  const channelNumber = data[4];
@@ -2498,7 +2514,7 @@ export class MidyGM2 {
2498
2514
  const note = noteList[i];
2499
2515
  if (!note)
2500
2516
  continue;
2501
- this.applyDestinationSettings(channel, note, table);
2517
+ this.setControllerParameters(channel, note, table);
2502
2518
  }
2503
2519
  });
2504
2520
  }
@@ -2561,9 +2577,6 @@ Object.defineProperty(MidyGM2, "channelSettings", {
2561
2577
  value: {
2562
2578
  currentBufferSource: null,
2563
2579
  detune: 0,
2564
- scaleOctaveTuningTable: new Int8Array(12), // [-64, 63] cent
2565
- channelPressureTable: new Uint8Array([64, 64, 64, 0, 0, 0]),
2566
- keyBasedInstrumentControlTable: new Int8Array(128 * 128), // [-64, 63]
2567
2580
  program: 0,
2568
2581
  bank: 121 * 128,
2569
2582
  bankMSB: 121,
@@ -45,11 +45,11 @@ export class MidyGMLite {
45
45
  freqVibLFO: (_channel: any, _note: any, _prevValue: any) => void;
46
46
  };
47
47
  controlChangeHandlers: {
48
- 1: (channelNumber: any, modulation: any) => void;
48
+ 1: (channelNumber: any, modulation: any, scheduleTime: any) => void;
49
49
  6: (channelNumber: any, value: any) => void;
50
- 7: (channelNumber: any, volume: any) => void;
51
- 10: (channelNumber: any, pan: any) => void;
52
- 11: (channelNumber: any, expression: any) => void;
50
+ 7: (channelNumber: any, volume: any, scheduleTime: any) => void;
51
+ 10: (channelNumber: any, pan: any, scheduleTime: any) => void;
52
+ 11: (channelNumber: any, expression: any, scheduleTime: any) => void;
53
53
  38: (channelNumber: any, value: any) => void;
54
54
  64: (channelNumber: any, value: any) => void;
55
55
  100: (channelNumber: any, value: any) => void;
@@ -90,6 +90,7 @@ export class MidyGMLite {
90
90
  seekTo(second: any): void;
91
91
  calcTotalTime(): number;
92
92
  currentTime(): number;
93
+ processScheduledNotes(channel: any, scheduleTime: any, callback: any): void;
93
94
  getActiveNotes(channel: any, time: any): SparseMap;
94
95
  getActiveNote(noteList: any, time: any): any;
95
96
  cbToRatio(cb: any): number;
@@ -100,7 +101,7 @@ export class MidyGMLite {
100
101
  updateChannelDetune(channel: any): void;
101
102
  updateDetune(channel: any, note: any): void;
102
103
  setVolumeEnvelope(note: any): void;
103
- setPitchEnvelope(note: any): void;
104
+ setPitchEnvelope(note: any, scheduleTime: any): void;
104
105
  clampCutoffFrequency(frequency: any): number;
105
106
  setFilterEnvelope(note: any): void;
106
107
  startModulation(channel: any, note: any, startTime: any): void;
@@ -136,11 +137,11 @@ export class MidyGMLite {
136
137
  getControllerState(channel: any, noteNumber: any, velocity: any): Float32Array<any>;
137
138
  applyVoiceParams(channel: any, controllerType: any): void;
138
139
  createControlChangeHandlers(): {
139
- 1: (channelNumber: any, modulation: any) => void;
140
+ 1: (channelNumber: any, modulation: any, scheduleTime: any) => void;
140
141
  6: (channelNumber: any, value: any) => void;
141
- 7: (channelNumber: any, volume: any) => void;
142
- 10: (channelNumber: any, pan: any) => void;
143
- 11: (channelNumber: any, expression: any) => void;
142
+ 7: (channelNumber: any, volume: any, scheduleTime: any) => void;
143
+ 10: (channelNumber: any, pan: any, scheduleTime: any) => void;
144
+ 11: (channelNumber: any, expression: any, scheduleTime: any) => void;
144
145
  38: (channelNumber: any, value: any) => void;
145
146
  64: (channelNumber: any, value: any) => void;
146
147
  100: (channelNumber: any, value: any) => void;
@@ -149,18 +150,18 @@ export class MidyGMLite {
149
150
  121: (channelNumber: any) => void;
150
151
  123: (channelNumber: any) => Promise<void>;
151
152
  };
152
- handleControlChange(channelNumber: any, controllerType: any, value: any): void;
153
- updateModulation(channel: any): void;
154
- setModulationDepth(channelNumber: any, modulation: any): void;
155
- setVolume(channelNumber: any, volume: any): void;
153
+ handleControlChange(channelNumber: any, controllerType: any, value: any, startTime: any): void;
154
+ updateModulation(channel: any, scheduleTime: any): void;
155
+ setModulationDepth(channelNumber: any, modulation: any, scheduleTime: any): void;
156
+ setVolume(channelNumber: any, volume: any, scheduleTime: any): void;
156
157
  panToGain(pan: any): {
157
158
  gainLeft: number;
158
159
  gainRight: number;
159
160
  };
160
- setPan(channelNumber: any, pan: any): void;
161
- setExpression(channelNumber: any, expression: any): void;
161
+ setPan(channelNumber: any, pan: any, scheduleTime: any): void;
162
+ setExpression(channelNumber: any, expression: any, scheduleTime: any): void;
162
163
  dataEntryLSB(channelNumber: any, value: any): void;
163
- updateChannelVolume(channel: any): void;
164
+ updateChannelVolume(channel: any, scheduleTime: any): void;
164
165
  setSustainPedal(channelNumber: any, value: any): void;
165
166
  limitData(channel: any, minMSB: any, maxMSB: any, minLSB: any, maxLSB: any): void;
166
167
  handleRPN(channelNumber: any): void;
@@ -198,6 +199,7 @@ declare class Note {
198
199
  constructor(noteNumber: any, velocity: any, startTime: any, voice: any, voiceParams: any);
199
200
  bufferSource: any;
200
201
  filterNode: any;
202
+ filterDepth: any;
201
203
  volumeEnvelopeNode: any;
202
204
  volumeDepth: any;
203
205
  modulationLFO: any;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAgJA;IAsBE;;;;;;;;;MASE;IAEF,+BAQC;IAxCD,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,kCAA+B;IAC/B,gCAA6B;IAC7B,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAClB,6BAAuC;IAcrC,kBAAgC;IAChC,kBAA8C;IAC9C;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAKnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAUC;IAED,6DA2BC;IAED,8DASC;IAED,2EA+CC;IAED,mCAOC;IAED,0BAoDC;IAED,uDAEC;IAED,wDAEC;IAED,6EAEC;IAED;;;MA4EC;IAED,+EAmBC;IAED,qDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,mDASC;IAED,6CAQC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,wCAIC;IAED,wCAQC;IAED,4CAKC;IAED,mCAgBC;IAED,kCAqBC;IAED,6CAIC;IAED,mCAuBC;IAED,+DAoBC;IAED,yGAgBC;IAED,gHAuCC;IAED,kGAgDC;IAED,0EAGC;IAED,qFAwBC;IAED,6HAuBC;IAED,0FAGC;IAED,kEAeC;IAED,gFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,mDASC;IAED,gDASC;IAED,qCAMC;IAED,mCAQC;IAED,gCAOC;IAED,+BAMC;IAED;;;;;;;;;;;MAqBC;IAED,oFAMC;IAED,0DA6CC;IAED;;;;;;;;;;;;;MAeC;IAED,+EAWC;IAED,qCAeC;IAED,8DAIC;IACD,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,mDAGC;IAED,wCAWC;IAED,sDAKC;IAED,kFAeC;IAED,oCAYC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,kDAKC;IAED,wDASC;IAED,+CAEC;IAED,8CAqBC;IAED,+CAEC;IAED,4DAgBC;IAED,oBAMC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAv0CD;IACE,uBAGC;IAFC,YAA2B;IAC3B,qBAAuB;IAGzB,gCAKC;IAED,mBAEC;IAED,0BAUC;IAED,uBAEC;IAED,mBAEC;IAED,cAMC;IASD,6BAKC;IAZD,qDAKC;CAQF;AAED;IAQE,0FAMC;IAbD,kBAAa;IACb,gBAAW;IACX,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
1
+ {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAiJA;IAsBE;;;;;;;;;MASE;IAEF,+BAQC;IAxCD,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,kCAA+B;IAC/B,gCAA6B;IAC7B,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAClB,6BAAuC;IAcrC,kBAAgC;IAChC,kBAA8C;IAC9C;;;;;;;;;;;MAA2D;IAC3D;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAKnD,4BAMC;IAED,mCAWC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAUC;IAED,6DA2BC;IAED,8DASC;IAED,2EAqDC;IAED,mCAOC;IAED,0BAoDC;IAED,uDAEC;IAED,wDAEC;IAED,6EAEC;IAED;;;MA4EC;IAED,+EAmBC;IAED,qDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,4EASC;IAED,mDASC;IAED,6CAQC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,wCAIC;IAED,wCAQC;IAED,4CAKC;IAED,mCAgBC;IAED,qDAqBC;IAED,6CAIC;IAED,mCAuBC;IAED,+DAoBC;IAED,yGAgBC;IAED,gHAuCC;IAED,kGAgDC;IAED,0EAGC;IAED,qFAwBC;IAED,6HAuBC;IAED,0FAGC;IAED,kEAeC;IAED,gFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,mDASC;IAED,gDASC;IAED,qCAMC;IAED,mCAQC;IAED,gCAOC;IAED,+BAMC;IAED;;;;;;;;;;;MAqBC;IAED,oFAMC;IAED,0DA6CC;IAED;;;;;;;;;;;;;MAeC;IAED,+FAWC;IAED,wDAWC;IAED,iFAIC;IAED,oEAIC;IAED;;;MAMC;IAED,8DAIC;IAED,4EAIC;IAED,mDAGC;IAED,2DAWC;IAED,sDAKC;IAED,kFAeC;IAED,oCAYC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,kDAKC;IAED,wDASC;IAED,+CAEC;IAED,8CAqBC;IAED,+CAEC;IAED,4DAgBC;IAED,oBAMC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAt1CD;IACE,uBAGC;IAFC,YAA2B;IAC3B,qBAAuB;IAGzB,gCAKC;IAED,mBAEC;IAED,0BAUC;IAED,uBAEC;IAED,mBAEC;IAED,cAMC;IASD,6BAKC;IAZD,qDAKC;CAQF;AAED;IASE,0FAMC;IAdD,kBAAa;IACb,gBAAW;IACX,iBAAY;IACZ,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}