@marmooo/midy 0.0.6 → 0.0.8

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
@@ -75,13 +75,13 @@ export class MidyGM2 {
75
75
  configurable: true,
76
76
  writable: true,
77
77
  value: 0
78
- });
78
+ }); // cb
79
79
  Object.defineProperty(this, "masterCoarseTuning", {
80
80
  enumerable: true,
81
81
  configurable: true,
82
82
  writable: true,
83
83
  value: 0
84
- });
84
+ }); // cb
85
85
  Object.defineProperty(this, "mono", {
86
86
  enumerable: true,
87
87
  configurable: true,
@@ -225,22 +225,23 @@ export class MidyGM2 {
225
225
  this.totalTime = this.calcTotalTime();
226
226
  }
227
227
  setChannelAudioNodes(audioContext) {
228
- const gainNode = new GainNode(audioContext, {
229
- gain: MidyGM2.channelSettings.volume,
230
- });
231
- const pannerNode = new StereoPannerNode(audioContext, {
232
- pan: MidyGM2.channelSettings.pan,
233
- });
228
+ const { gainLeft, gainRight } = this.panToGain(MidyGM2.channelSettings.pan);
229
+ const gainL = new GainNode(audioContext, { gain: gainLeft });
230
+ const gainR = new GainNode(audioContext, { gain: gainRight });
231
+ const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
232
+ gainL.connect(merger, 0, 0);
233
+ gainR.connect(merger, 0, 1);
234
+ merger.connect(this.masterGain);
234
235
  const reverbEffect = this.createReverbEffect(audioContext);
235
236
  const chorusEffect = this.createChorusEffect(audioContext);
236
237
  chorusEffect.lfo.start();
237
- reverbEffect.dryGain.connect(pannerNode);
238
- reverbEffect.wetGain.connect(pannerNode);
239
- pannerNode.connect(gainNode);
240
- gainNode.connect(this.masterGain);
238
+ reverbEffect.dryGain.connect(gainL);
239
+ reverbEffect.dryGain.connect(gainR);
240
+ reverbEffect.wetGain.connect(gainL);
241
+ reverbEffect.wetGain.connect(gainR);
241
242
  return {
242
- gainNode,
243
- pannerNode,
243
+ gainL,
244
+ gainR,
244
245
  reverbEffect,
245
246
  chorusEffect,
246
247
  };
@@ -644,14 +645,16 @@ export class MidyGM2 {
644
645
  connectNoteEffects(channel, gainNode) {
645
646
  if (channel.reverb === 0) {
646
647
  if (channel.chorus === 0) { // no effect
647
- gainNode.connect(channel.pannerNode);
648
+ gainNode.connect(channel.gainL);
649
+ gainNode.connect(channel.gainR);
648
650
  }
649
651
  else { // chorus
650
652
  channel.chorusEffect.delayNodes.forEach((delayNode) => {
651
653
  gainNode.connect(delayNode);
652
654
  });
653
655
  channel.chorusEffect.chorusGains.forEach((chorusGain) => {
654
- chorusGain.connect(channel.pannerNode);
656
+ chorusGain.connect(channel.gainL);
657
+ chorusGain.connect(channel.gainR);
655
658
  });
656
659
  }
657
660
  }
@@ -932,20 +935,12 @@ export class MidyGM2 {
932
935
  this.setPitchBend(channelNumber, pitchBend);
933
936
  }
934
937
  setPitchBend(channelNumber, pitchBend) {
935
- const now = this.audioContext.currentTime;
936
938
  const channel = this.channels[channelNumber];
937
939
  const prevPitchBend = channel.pitchBend;
938
940
  channel.pitchBend = (pitchBend - 8192) / 8192;
939
941
  const detuneChange = (channel.pitchBend - prevPitchBend) *
940
942
  channel.pitchBendRange * 100;
941
- const activeNotes = this.getActiveNotes(channel, now);
942
- activeNotes.forEach((activeNote) => {
943
- const { bufferSource } = activeNote;
944
- const detune = bufferSource.detune.value + detuneChange;
945
- bufferSource.detune
946
- .cancelScheduledValues(now)
947
- .setValueAtTime(detune, now);
948
- });
943
+ this.updateDetune(channel, detuneChange);
949
944
  }
950
945
  handleControlChange(channelNumber, controller, value) {
951
946
  switch (controller) {
@@ -956,7 +951,7 @@ export class MidyGM2 {
956
951
  case 5:
957
952
  return this.setPortamentoTime(channelNumber, value);
958
953
  case 6:
959
- return this.setDataEntry(channelNumber, value, true);
954
+ return this.dataEntryMSB(channelNumber, value);
960
955
  case 7:
961
956
  return this.setVolume(channelNumber, value);
962
957
  case 10:
@@ -966,7 +961,7 @@ export class MidyGM2 {
966
961
  case 32:
967
962
  return this.setBankLSB(channelNumber, value);
968
963
  case 38:
969
- return this.setDataEntry(channelNumber, value, false);
964
+ return this.dataEntryLSB(channelNumber, value);
970
965
  case 64:
971
966
  return this.setSustainPedal(channelNumber, value);
972
967
  case 65:
@@ -976,13 +971,13 @@ export class MidyGM2 {
976
971
  case 67:
977
972
  return this.setSoftPedal(channelNumber, value);
978
973
  case 91:
979
- return this.setReverb(channelNumber, value);
974
+ return this.setReverbSendLevel(channelNumber, value);
980
975
  case 93:
981
- return this.setChorus(channelNumber, value);
976
+ return this.setChorusSendLevel(channelNumber, value);
982
977
  case 100:
983
- return this.setRPNMSB(channelNumber, value);
984
- case 101:
985
978
  return this.setRPNLSB(channelNumber, value);
979
+ case 101:
980
+ return this.setRPNMSB(channelNumber, value);
986
981
  case 120:
987
982
  return this.allSoundOff(channelNumber);
988
983
  case 121:
@@ -1004,22 +999,24 @@ export class MidyGM2 {
1004
999
  setBankMSB(channelNumber, msb) {
1005
1000
  this.channels[channelNumber].bankMSB = msb;
1006
1001
  }
1007
- setModulation(channelNumber, modulation) {
1002
+ updateModulation(channel) {
1008
1003
  const now = this.audioContext.currentTime;
1009
- const channel = this.channels[channelNumber];
1010
- channel.modulation = (modulation / 127) *
1011
- (channel.modulationDepthRange * 100);
1012
1004
  const activeNotes = this.getActiveNotes(channel, now);
1013
1005
  activeNotes.forEach((activeNote) => {
1014
1006
  if (activeNote.modLFO) {
1015
- activeNote.gainNode.gain.setValueAtTime(this.cbToRatio(activeNote.instrumentKey.modLfoToVolume) *
1016
- channel.modulation, now);
1007
+ const { gainNode, instrumentKey } = activeNote;
1008
+ gainNode.gain.setValueAtTime(this.cbToRatio(instrumentKey.modLfoToVolume + channel.modulation), now);
1017
1009
  }
1018
1010
  else {
1019
1011
  this.startModulation(channel, activeNote, now);
1020
1012
  }
1021
1013
  });
1022
1014
  }
1015
+ setModulation(channelNumber, modulation) {
1016
+ const channel = this.channels[channelNumber];
1017
+ channel.modulation = (modulation / 127) * channel.modulationDepthRange;
1018
+ this.updateModulation(channel);
1019
+ }
1023
1020
  setPortamentoTime(channelNumber, portamentoTime) {
1024
1021
  this.channels[channelNumber].portamentoTime = portamentoTime / 127;
1025
1022
  }
@@ -1048,6 +1045,10 @@ export class MidyGM2 {
1048
1045
  setBankLSB(channelNumber, lsb) {
1049
1046
  this.channels[channelNumber].bankLSB = lsb;
1050
1047
  }
1048
+ dataEntryLSB(channelNumber, value) {
1049
+ this.channels[channelNumber].dataLSB = value;
1050
+ this.handleRPN(channelNumber);
1051
+ }
1051
1052
  updateChannelGain(channel) {
1052
1053
  const now = this.audioContext.currentTime;
1053
1054
  const volume = channel.volume * channel.expression;
@@ -1069,7 +1070,7 @@ export class MidyGM2 {
1069
1070
  setPortamento(channelNumber, value) {
1070
1071
  this.channels[channelNumber].portamento = value >= 64;
1071
1072
  }
1072
- setReverb(channelNumber, reverb) {
1073
+ setReverbSendLevel(channelNumber, reverb) {
1073
1074
  const now = this.audioContext.currentTime;
1074
1075
  const channel = this.channels[channelNumber];
1075
1076
  const reverbEffect = channel.reverbEffect;
@@ -1079,7 +1080,7 @@ export class MidyGM2 {
1079
1080
  reverbEffect.wetGain.gain.cancelScheduledValues(now);
1080
1081
  reverbEffect.wetGain.gain.setValueAtTime(channel.reverb, now);
1081
1082
  }
1082
- setChorus(channelNumber, chorus) {
1083
+ setChorusSendLevel(channelNumber, chorus) {
1083
1084
  const channel = this.channels[channelNumber];
1084
1085
  channel.chorus = chorus / 127;
1085
1086
  channel.chorusEffect.lfoGain = channel.chorus;
@@ -1101,44 +1102,64 @@ export class MidyGM2 {
1101
1102
  const channel = this.channels[channelNumber];
1102
1103
  channel.softPedal = softPedal / 127;
1103
1104
  }
1104
- setRPNMSB(channelNumber, value) {
1105
- this.channels[channelNumber].rpnMSB = value;
1105
+ limitData(channel, minMSB, maxMSB, minLSB, maxLSB) {
1106
+ if (maxLSB < channel.dataLSB) {
1107
+ channel.dataMSB++;
1108
+ channel.dataLSB = minLSB;
1109
+ }
1110
+ else if (channel.dataLSB < 0) {
1111
+ channel.dataMSB--;
1112
+ channel.dataLSB = maxLSB;
1113
+ }
1114
+ if (maxMSB < channel.dataMSB) {
1115
+ channel.dataMSB = maxMSB;
1116
+ channel.dataLSB = maxLSB;
1117
+ }
1118
+ else if (channel.dataMSB < 0) {
1119
+ channel.dataMSB = minMSB;
1120
+ channel.dataLSB = minLSB;
1121
+ }
1106
1122
  }
1107
- setRPNLSB(channelNumber, value) {
1108
- this.channels[channelNumber].rpnLSB = value;
1123
+ limitDataMSB(channel, minMSB, maxMSB) {
1124
+ if (maxMSB < channel.dataMSB) {
1125
+ channel.dataMSB = maxMSB;
1126
+ }
1127
+ else if (channel.dataMSB < 0) {
1128
+ channel.dataMSB = minMSB;
1129
+ }
1109
1130
  }
1110
- setDataEntry(channelNumber, value, isMSB) {
1131
+ handleRPN(channelNumber) {
1111
1132
  const channel = this.channels[channelNumber];
1112
1133
  const rpn = channel.rpnMSB * 128 + channel.rpnLSB;
1113
- isMSB ? channel.dataMSB = value : channel.dataLSB = value;
1114
- const { dataMSB, dataLSB } = channel;
1115
1134
  switch (rpn) {
1116
1135
  case 0:
1117
- return this.handlePitchBendRangeMessage(channelNumber, dataMSB, dataLSB);
1136
+ this.handlePitchBendRangeRPN(channelNumber);
1137
+ break;
1118
1138
  case 1:
1119
- channel.fineTuning = (dataMSB * 128 + dataLSB - 8192) / 8192;
1139
+ this.handleFineTuningRPN(channelNumber);
1120
1140
  break;
1121
1141
  case 2:
1122
- channel.coarseTuning = dataMSB - 64;
1142
+ this.handleCoarseTuningRPN(channelNumber);
1123
1143
  break;
1124
1144
  case 5:
1125
- channel.modulationDepthRange = dataMSB + dataLSB / 128;
1145
+ this.handleModulationDepthRangeRPN(channelNumber);
1126
1146
  break;
1127
1147
  default:
1128
1148
  console.warn(`Channel ${channelNumber}: Unsupported RPN MSB=${channel.rpnMSB} LSB=${channel.rpnLSB}`);
1129
1149
  }
1130
1150
  }
1131
- handlePitchBendRangeMessage(channelNumber, dataMSB, dataLSB) {
1132
- const pitchBendRange = dataMSB + dataLSB / 100;
1133
- this.setPitchBendRange(channelNumber, pitchBendRange);
1151
+ setRPNMSB(channelNumber, value) {
1152
+ this.channels[channelNumber].rpnMSB = value;
1134
1153
  }
1135
- setPitchBendRange(channelNumber, pitchBendRange) {
1154
+ setRPNLSB(channelNumber, value) {
1155
+ this.channels[channelNumber].rpnLSB = value;
1156
+ }
1157
+ dataEntryMSB(channelNumber, value) {
1158
+ this.channels[channelNumber].dataMSB = value;
1159
+ this.handleRPN(channelNumber);
1160
+ }
1161
+ updateDetune(channel, detuneChange) {
1136
1162
  const now = this.audioContext.currentTime;
1137
- const channel = this.channels[channelNumber];
1138
- const prevPitchBendRange = channel.pitchBendRange;
1139
- channel.pitchBendRange = pitchBendRange;
1140
- const detuneChange = (channel.pitchBendRange - prevPitchBendRange) *
1141
- channel.pitchBend * 100;
1142
1163
  const activeNotes = this.getActiveNotes(channel, now);
1143
1164
  activeNotes.forEach((activeNote) => {
1144
1165
  const { bufferSource } = activeNote;
@@ -1148,6 +1169,58 @@ export class MidyGM2 {
1148
1169
  .setValueAtTime(detune, now);
1149
1170
  });
1150
1171
  }
1172
+ handlePitchBendRangeRPN(channelNumber) {
1173
+ const channel = this.channels[channelNumber];
1174
+ this.limitData(channel, 0, 127, 0, 99);
1175
+ const pitchBendRange = channel.dataMSB + channel.dataLSB / 100;
1176
+ this.setPitchBendRange(channelNumber, pitchBendRange);
1177
+ }
1178
+ setPitchBendRange(channelNumber, pitchBendRange) {
1179
+ const channel = this.channels[channelNumber];
1180
+ const prevPitchBendRange = channel.pitchBendRange;
1181
+ channel.pitchBendRange = pitchBendRange;
1182
+ const detuneChange = (channel.pitchBendRange - prevPitchBendRange) *
1183
+ channel.pitchBend * 100;
1184
+ this.updateDetune(channel, detuneChange);
1185
+ }
1186
+ handleFineTuningRPN(channelNumber) {
1187
+ const channel = this.channels[channelNumber];
1188
+ this.limitData(channel, 0, 127, 0, 127);
1189
+ const fineTuning = (channel.dataMSB * 128 + channel.dataLSB - 8192) / 8192;
1190
+ this.setFineTuning(channelNumber, fineTuning);
1191
+ }
1192
+ setFineTuning(channelNumber, fineTuning) {
1193
+ const channel = this.channels[channelNumber];
1194
+ const prevFineTuning = channel.fineTuning;
1195
+ channel.fineTuning = fineTuning;
1196
+ const detuneChange = channel.fineTuning - prevFineTuning;
1197
+ this.updateDetune(channel, detuneChange);
1198
+ }
1199
+ handleCoarseTuningRPN(channelNumber) {
1200
+ const channel = this.channels[channelNumber];
1201
+ this.limitDataMSB(channel, 0, 127);
1202
+ const coarseTuning = channel.dataMSB - 64;
1203
+ this.setFineTuning(channelNumber, coarseTuning);
1204
+ }
1205
+ setCoarseTuning(channelNumber, coarseTuning) {
1206
+ const channel = this.channels[channelNumber];
1207
+ const prevCoarseTuning = channel.coarseTuning;
1208
+ channel.coarseTuning = coarseTuning;
1209
+ const detuneChange = channel.coarseTuning - prevCoarseTuning;
1210
+ this.updateDetune(channel, detuneChange);
1211
+ }
1212
+ handleModulationDepthRangeRPN(channelNumber) {
1213
+ const channel = this.channels[channelNumber];
1214
+ this.limitData(channel, 0, 127, 0, 127);
1215
+ const modulationDepthRange = dataMSB + dataLSB / 128;
1216
+ this.setModulationDepthRange(channelNumber, modulationDepthRange);
1217
+ }
1218
+ setModulationDepthRange(channelNumber, modulationDepthRange) {
1219
+ const channel = this.channels[channelNumber];
1220
+ channel.modulationDepthRange = modulationDepthRange;
1221
+ channel.modulation = (modulation / 127) * channel.modulationDepthRange;
1222
+ this.updateModulation(channel);
1223
+ }
1151
1224
  allSoundOff(channelNumber) {
1152
1225
  const now = this.audioContext.currentTime;
1153
1226
  const channel = this.channels[channelNumber];
@@ -1237,9 +1310,9 @@ export class MidyGM2 {
1237
1310
  switch (data[3]) {
1238
1311
  case 1:
1239
1312
  return this.handleMasterVolumeSysEx(data);
1240
- case 3:
1313
+ case 3: // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/ca25.pdf
1241
1314
  return this.handleMasterFineTuningSysEx(data);
1242
- case 4:
1315
+ case 4: // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/ca25.pdf
1243
1316
  return this.handleMasterCoarseTuningSysEx(data);
1244
1317
  // case 5: // TODO: Global Parameter Control
1245
1318
  default:
@@ -1350,7 +1423,7 @@ Object.defineProperty(MidyGM2, "channelSettings", {
1350
1423
  value: {
1351
1424
  currentBufferSource: null,
1352
1425
  volume: 100 / 127,
1353
- pan: 0,
1426
+ pan: 64,
1354
1427
  portamentoTime: 0,
1355
1428
  reverb: 0,
1356
1429
  chorus: 0,
@@ -1361,9 +1434,9 @@ Object.defineProperty(MidyGM2, "channelSettings", {
1361
1434
  dataLSB: 0,
1362
1435
  program: 0,
1363
1436
  pitchBend: 0,
1364
- fineTuning: 0,
1365
- coarseTuning: 0,
1366
- modulationDepthRange: 0.5,
1437
+ fineTuning: 0, // cb
1438
+ coarseTuning: 0, // cb
1439
+ modulationDepthRange: 0.5, // cb
1367
1440
  }
1368
1441
  });
1369
1442
  Object.defineProperty(MidyGM2, "effectSettings", {
@@ -124,6 +124,7 @@ export class MidyGMLite {
124
124
  handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
125
125
  setPitchBend(channelNumber: any, pitchBend: any): void;
126
126
  handleControlChange(channelNumber: any, controller: any, value: any): void | any[];
127
+ updateModulation(channel: any): void;
127
128
  setModulation(channelNumber: any, modulation: any): void;
128
129
  setVolume(channelNumber: any, volume: any): void;
129
130
  panToGain(pan: any): {
@@ -132,12 +133,15 @@ export class MidyGMLite {
132
133
  };
133
134
  setPan(channelNumber: any, pan: any): void;
134
135
  setExpression(channelNumber: any, expression: any): void;
136
+ dataEntryLSB(channelNumber: any, value: any): void;
135
137
  updateChannelGain(channel: any): void;
136
138
  setSustainPedal(channelNumber: any, value: any): void;
139
+ handleRPN(channelNumber: any): void;
137
140
  setRPNMSB(channelNumber: any, value: any): void;
138
141
  setRPNLSB(channelNumber: any, value: any): void;
139
- setDataEntry(channelNumber: any, value: any, isMSB: any): void;
140
- handlePitchBendRangeMessage(channelNumber: any, dataMSB: any, dataLSB: any): void;
142
+ dataEntryMSB(channelNumber: any, value: any): void;
143
+ updateDetune(channel: any, detuneChange: any): void;
144
+ handlePitchBendRangeRPN(channelNumber: any): void;
141
145
  setPitchBendRange(channelNumber: any, pitchBendRange: any): void;
142
146
  allSoundOff(channelNumber: any): any[];
143
147
  resetAllControllers(channelNumber: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAqBA;IAmBE;;;;;;;;;MASE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IA5CD,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAuBhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;MAcC;IAED;;;;;;;;;;;;;;;;;;QAUC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EA+CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA8DC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,sDAEC;IAED,2BAEC;IAED,4BAEC;IAED,yCAEC;IAED,mFAGC;IAED,iDAiBC;IAED,iDAiCC;IAED,0DAmBC;IAED,wHA6BC;IAED,kGA6BC;IAED,0EAGC;IAED,sIAmDC;IAED,0FAGC;IAED,kEAeC;IAED,wFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,uDAeC;IAED,mFA+BC;IAED,yDAiBC;IAED,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,sCAUC;IAED,sDAMC;IAED,gDAEC;IAED,gDAEC;IAED,+DAiBC;IAED,kFAGC;IAED,iEAeC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAl/BD;IAOE,gFAKC;IAXD,kBAAa;IACb,cAAS;IACT,gBAAW;IACX,YAAO;IACP,gBAAW;IAGT,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
1
+ {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAqBA;IAmBE;;;;;;;;;MASE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IA5CD,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IAuBhB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;MAcC;IAED;;;;;;;;;;;;;;;;;;QAUC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EA+CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA8DC;IAED,4BAsBC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,sDAGC;IAED,2BAEC;IAED,4BAEC;IAED,yCAEC;IAED,mFAGC;IAED,iDAiBC;IAED,iDAiCC;IAED,0DAmBC;IAED,wHA6BC;IAED,kGA6BC;IAED,0EAGC;IAED,sIAmDC;IAED,0FAGC;IAED,kEAeC;IAED,wFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,uDAOC;IAED,mFA+BC;IAED,qCAcC;IAED,yDAIC;IACD,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,mDAGC;IAED,sCAUC;IAED,sDAMC;IAED,oCAYC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,oDAUC;IAED,kDAKC;IAED,iEAOC;IAED,uCAoBC;IAED,8CAEC;IAED,uCAoBC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAx/BD;IAOE,gFAKC;IAXD,kBAAa;IACb,cAAS;IACT,gBAAW;IACX,YAAO;IACP,gBAAW;IAGT,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
@@ -492,7 +492,8 @@ export class MidyGMLite {
492
492
  return noteList[0];
493
493
  }
494
494
  connectNoteEffects(channel, gainNode) {
495
- gainNode.connect(channel.pannerNode);
495
+ gainNode.connect(channel.gainL);
496
+ gainNode.connect(channel.gainR);
496
497
  }
497
498
  cbToRatio(cb) {
498
499
  return Math.pow(10, cb / 200);
@@ -702,27 +703,19 @@ export class MidyGMLite {
702
703
  this.setPitchBend(channelNumber, pitchBend);
703
704
  }
704
705
  setPitchBend(channelNumber, pitchBend) {
705
- const now = this.audioContext.currentTime;
706
706
  const channel = this.channels[channelNumber];
707
707
  const prevPitchBend = channel.pitchBend;
708
708
  channel.pitchBend = (pitchBend - 8192) / 8192;
709
709
  const detuneChange = (channel.pitchBend - prevPitchBend) *
710
710
  channel.pitchBendRange * 100;
711
- const activeNotes = this.getActiveNotes(channel, now);
712
- activeNotes.forEach((activeNote) => {
713
- const { bufferSource } = activeNote;
714
- const detune = bufferSource.detune.value + detuneChange;
715
- bufferSource.detune
716
- .cancelScheduledValues(now)
717
- .setValueAtTime(detune, now);
718
- });
711
+ this.updateDetune(channel, detuneChange);
719
712
  }
720
713
  handleControlChange(channelNumber, controller, value) {
721
714
  switch (controller) {
722
715
  case 1:
723
716
  return this.setModulation(channelNumber, value);
724
717
  case 6:
725
- return this.setDataEntry(channelNumber, value, true);
718
+ return this.dataEntryMSB(channelNumber, value);
726
719
  case 7:
727
720
  return this.setVolume(channelNumber, value);
728
721
  case 10:
@@ -730,13 +723,13 @@ export class MidyGMLite {
730
723
  case 11:
731
724
  return this.setExpression(channelNumber, value);
732
725
  case 38:
733
- return this.setDataEntry(channelNumber, value, false);
726
+ return this.dataEntryLSB(channelNumber, value);
734
727
  case 64:
735
728
  return this.setSustainPedal(channelNumber, value);
736
729
  case 100:
737
- return this.setRPNMSB(channelNumber, value);
738
- case 101:
739
730
  return this.setRPNLSB(channelNumber, value);
731
+ case 101:
732
+ return this.setRPNMSB(channelNumber, value);
740
733
  case 120:
741
734
  return this.allSoundOff(channelNumber);
742
735
  case 121:
@@ -747,22 +740,24 @@ export class MidyGMLite {
747
740
  console.warn(`Unsupported Control change: controller=${controller} value=${value}`);
748
741
  }
749
742
  }
750
- setModulation(channelNumber, modulation) {
743
+ updateModulation(channel) {
751
744
  const now = this.audioContext.currentTime;
752
- const channel = this.channels[channelNumber];
753
- channel.modulation = (modulation / 127) *
754
- (channel.modulationDepthRange * 100);
755
745
  const activeNotes = this.getActiveNotes(channel, now);
756
746
  activeNotes.forEach((activeNote) => {
757
747
  if (activeNote.modLFO) {
758
- activeNote.gainNode.gain.setValueAtTime(this.cbToRatio(activeNote.instrumentKey.modLfoToVolume) *
759
- channel.modulation, now);
748
+ const { gainNode, instrumentKey } = activeNote;
749
+ gainNode.gain.setValueAtTime(this.cbToRatio(instrumentKey.modLfoToVolume + channel.modulation), now);
760
750
  }
761
751
  else {
762
752
  this.startModulation(channel, activeNote, now);
763
753
  }
764
754
  });
765
755
  }
756
+ setModulation(channelNumber, modulation) {
757
+ const channel = this.channels[channelNumber];
758
+ channel.modulation = (modulation / 127) * channel.modulationDepthRange;
759
+ this.updateModulation(channel);
760
+ }
766
761
  setVolume(channelNumber, volume) {
767
762
  const channel = this.channels[channelNumber];
768
763
  channel.volume = volume / 127;
@@ -785,6 +780,10 @@ export class MidyGMLite {
785
780
  channel.expression = expression / 127;
786
781
  this.updateChannelGain(channel);
787
782
  }
783
+ dataEntryLSB(channelNumber, value) {
784
+ this.channels[channelNumber].dataLSB = value;
785
+ this.handleRPN(channelNumber);
786
+ }
788
787
  updateChannelGain(channel) {
789
788
  const now = this.audioContext.currentTime;
790
789
  const volume = channel.volume * channel.expression;
@@ -803,35 +802,29 @@ export class MidyGMLite {
803
802
  this.releaseSustainPedal(channelNumber, value);
804
803
  }
805
804
  }
806
- setRPNMSB(channelNumber, value) {
807
- this.channels[channelNumber].rpnMSB = value;
808
- }
809
- setRPNLSB(channelNumber, value) {
810
- this.channels[channelNumber].rpnLSB = value;
811
- }
812
- setDataEntry(channelNumber, value, isMSB) {
805
+ handleRPN(channelNumber) {
813
806
  const channel = this.channels[channelNumber];
814
807
  const rpn = channel.rpnMSB * 128 + channel.rpnLSB;
815
- isMSB ? channel.dataMSB = value : channel.dataLSB = value;
816
- const { dataMSB, dataLSB } = channel;
817
808
  switch (rpn) {
818
809
  case 0:
819
- return this.handlePitchBendRangeMessage(channelNumber, dataMSB, dataLSB);
810
+ this.handlePitchBendRangeRPN(channelNumber);
811
+ break;
820
812
  default:
821
813
  console.warn(`Channel ${channelNumber}: Unsupported RPN MSB=${channel.rpnMSB} LSB=${channel.rpnLSB}`);
822
814
  }
823
815
  }
824
- handlePitchBendRangeMessage(channelNumber, dataMSB, dataLSB) {
825
- const pitchBendRange = dataMSB + dataLSB / 100;
826
- this.setPitchBendRange(channelNumber, pitchBendRange);
816
+ setRPNMSB(channelNumber, value) {
817
+ this.channels[channelNumber].rpnMSB = value;
827
818
  }
828
- setPitchBendRange(channelNumber, pitchBendRange) {
819
+ setRPNLSB(channelNumber, value) {
820
+ this.channels[channelNumber].rpnLSB = value;
821
+ }
822
+ dataEntryMSB(channelNumber, value) {
823
+ this.channels[channelNumber].dataMSB = value;
824
+ this.handleRPN(channelNumber);
825
+ }
826
+ updateDetune(channel, detuneChange) {
829
827
  const now = this.audioContext.currentTime;
830
- const channel = this.channels[channelNumber];
831
- const prevPitchBendRange = channel.pitchBendRange;
832
- channel.pitchBendRange = pitchBendRange;
833
- const detuneChange = (channel.pitchBendRange - prevPitchBendRange) *
834
- channel.pitchBend * 100;
835
828
  const activeNotes = this.getActiveNotes(channel, now);
836
829
  activeNotes.forEach((activeNote) => {
837
830
  const { bufferSource } = activeNote;
@@ -841,6 +834,20 @@ export class MidyGMLite {
841
834
  .setValueAtTime(detune, now);
842
835
  });
843
836
  }
837
+ handlePitchBendRangeRPN(channelNumber) {
838
+ const channel = this.channels[channelNumber];
839
+ this.limitData(channel, 0, 127, 0, 99);
840
+ const pitchBendRange = channel.dataMSB + channel.dataLSB / 100;
841
+ this.setPitchBendRange(channelNumber, pitchBendRange);
842
+ }
843
+ setPitchBendRange(channelNumber, pitchBendRange) {
844
+ const channel = this.channels[channelNumber];
845
+ const prevPitchBendRange = channel.pitchBendRange;
846
+ channel.pitchBendRange = pitchBendRange;
847
+ const detuneChange = (channel.pitchBendRange - prevPitchBendRange) *
848
+ channel.pitchBend * 100;
849
+ this.updateDetune(channel, detuneChange);
850
+ }
844
851
  allSoundOff(channelNumber) {
845
852
  const now = this.audioContext.currentTime;
846
853
  const channel = this.channels[channelNumber];
@@ -965,7 +972,7 @@ Object.defineProperty(MidyGMLite, "channelSettings", {
965
972
  dataLSB: 0,
966
973
  program: 0,
967
974
  pitchBend: 0,
968
- modulationDepthRange: 0.5,
975
+ modulationDepthRange: 0.5, // cb
969
976
  }
970
977
  });
971
978
  Object.defineProperty(MidyGMLite, "effectSettings", {
package/esm/midy.d.ts CHANGED
@@ -256,14 +256,15 @@ export class Midy {
256
256
  releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
257
257
  releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
258
258
  releaseSostenutoPedal(channelNumber: any, halfVelocity: any): any[];
259
- handleMIDIMessage(statusByte: any, data1: any, data2: any): any;
259
+ handleMIDIMessage(statusByte: any, data1: any, data2: any): void | any[] | Promise<any>;
260
260
  handlePolyphonicKeyPressure(channelNumber: any, noteNumber: any, pressure: any): void;
261
261
  handleProgramChange(channelNumber: any, program: any): void;
262
262
  handleChannelPressure(channelNumber: any, pressure: any): void;
263
263
  handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
264
264
  setPitchBend(channelNumber: any, pitchBend: any): void;
265
- handleControlChange(channelNumber: any, controller: any, value: any): any;
265
+ handleControlChange(channelNumber: any, controller: any, value: any): void | any[];
266
266
  setBankMSB(channelNumber: any, msb: any): void;
267
+ updateModulation(channel: any): void;
267
268
  setModulation(channelNumber: any, modulation: any): void;
268
269
  setPortamentoTime(channelNumber: any, portamentoTime: any): void;
269
270
  setVolume(channelNumber: any, volume: any): void;
@@ -274,23 +275,34 @@ export class Midy {
274
275
  setPan(channelNumber: any, pan: any): void;
275
276
  setExpression(channelNumber: any, expression: any): void;
276
277
  setBankLSB(channelNumber: any, lsb: any): void;
278
+ dataEntryLSB(channelNumber: any, value: any): void;
277
279
  updateChannelGain(channel: any): void;
278
280
  setSustainPedal(channelNumber: any, value: any): void;
279
281
  setPortamento(channelNumber: any, value: any): void;
280
- setReverb(channelNumber: any, reverb: any): void;
281
- setChorus(channelNumber: any, chorus: any): void;
282
+ setReverbSendLevel(channelNumber: any, reverb: any): void;
283
+ setChorusSendLevel(channelNumber: any, chorus: any): void;
282
284
  setSostenutoPedal(channelNumber: any, value: any): void;
283
285
  setSoftPedal(channelNumber: any, softPedal: any): void;
284
286
  setVibratoRate(channelNumber: any, vibratoRate: any): void;
285
287
  setVibratoDepth(channelNumber: any, vibratoDepth: any): void;
286
288
  setVibratoDelay(channelNumber: any, vibratoDelay: any): void;
287
- incrementRPNValue(channelNumber: any): void;
288
- decrementRPNValue(channelNumber: any): void;
289
+ limitData(channel: any, minMSB: any, maxMSB: any, minLSB: any, maxLSB: any): void;
290
+ limitDataMSB(channel: any, minMSB: any, maxMSB: any): void;
291
+ handleRPN(channelNumber: any, value: any): void;
292
+ dataIncrement(channelNumber: any): void;
293
+ dataDecrement(channelNumber: any): void;
289
294
  setRPNMSB(channelNumber: any, value: any): void;
290
295
  setRPNLSB(channelNumber: any, value: any): void;
291
- setDataEntry(channelNumber: any, value: any, isMSB: any): void;
292
- handlePitchBendRangeMessage(channelNumber: any, dataMSB: any, dataLSB: any): void;
296
+ dataEntryMSB(channelNumber: any, value: any): void;
297
+ updateDetune(channel: any, detuneChange: any): void;
298
+ handlePitchBendRangeRPN(channelNumber: any): void;
293
299
  setPitchBendRange(channelNumber: any, pitchBendRange: any): void;
300
+ handleFineTuningRPN(channelNumber: any): void;
301
+ setFineTuning(channelNumber: any, fineTuning: any): void;
302
+ handleCoarseTuningRPN(channelNumber: any): void;
303
+ setCoarseTuning(channelNumber: any, coarseTuning: any): void;
304
+ handleModulationDepthRangeRPN(channelNumber: any): void;
305
+ setModulationDepthRange(channelNumber: any, modulationDepthRange: any): void;
294
306
  allSoundOff(channelNumber: any): any[];
295
307
  resetAllControllers(channelNumber: any): void;
296
308
  allNotesOff(channelNumber: any): any[];
package/esm/midy.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"AAuBA;IAwBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAzED,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;IA+ChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;MAqBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAiBC;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;;;;MAoCC;IAED;;;;;MAqCC;IAED,sDA2BC;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,sIAwDC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,gEAqBC;IAED,sFAcC;IAED,4DAIC;IAED,+DAcC;IAED,qEAGC;IAED,uDAeC;IAED,0EAkEC;IAED,+CAEC;IAED,yDAiBC;IAED,iEAEC;IAED,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,+CAEC;IAED,sCAUC;IAED,sDAMC;IAED,oDAEC;IAED,iDASC;IAED,iDAIC;IAED,wDAWC;IAED,uDAGC;IAED,2DAGC;IAED,6DAGC;IAED,6DASC;IAED,4CAkBC;IAED,4CAkBC;IAED,gDAEC;IAED,gDAEC;IAGD,+DA0BC;IAED,kFAGC;IAED,iEAeC;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;AAxgDD;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":"AAuBA;IAwBE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAEF,+BAMC;IAzED,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;IA+ChB,kBAAgC;IAChC,gBAA4C;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAAiD;IAInD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;;;;;;;;;;;MAqBC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAiBC;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;;;;MAoCC;IAED;;;;;MAqCC;IAED,sDA6BC;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,sIAwDC;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;AAxjDD;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"}