@marmooo/midy 0.1.3 → 0.1.5

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.
Files changed (35) hide show
  1. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.4 → soundfont-parser@0.0.6}/+esm.d.ts +16 -20
  2. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.d.ts.map +1 -0
  3. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.js +180 -0
  4. package/esm/midy-GM1.d.ts +32 -3
  5. package/esm/midy-GM1.d.ts.map +1 -1
  6. package/esm/midy-GM1.js +93 -87
  7. package/esm/midy-GM2.d.ts +56 -3
  8. package/esm/midy-GM2.d.ts.map +1 -1
  9. package/esm/midy-GM2.js +142 -126
  10. package/esm/midy-GMLite.d.ts +32 -3
  11. package/esm/midy-GMLite.d.ts.map +1 -1
  12. package/esm/midy-GMLite.js +91 -85
  13. package/esm/midy.d.ts +87 -4
  14. package/esm/midy.d.ts.map +1 -1
  15. package/esm/midy.js +234 -140
  16. package/package.json +1 -1
  17. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.4 → soundfont-parser@0.0.6}/+esm.d.ts +16 -20
  18. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.d.ts.map +1 -0
  19. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.js +190 -0
  20. package/script/midy-GM1.d.ts +32 -3
  21. package/script/midy-GM1.d.ts.map +1 -1
  22. package/script/midy-GM1.js +93 -87
  23. package/script/midy-GM2.d.ts +56 -3
  24. package/script/midy-GM2.d.ts.map +1 -1
  25. package/script/midy-GM2.js +142 -126
  26. package/script/midy-GMLite.d.ts +32 -3
  27. package/script/midy-GMLite.d.ts.map +1 -1
  28. package/script/midy-GMLite.js +91 -85
  29. package/script/midy.d.ts +87 -4
  30. package/script/midy.d.ts.map +1 -1
  31. package/script/midy.js +234 -140
  32. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.d.ts.map +0 -1
  33. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.js +0 -162
  34. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.d.ts.map +0 -1
  35. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.js +0 -169
@@ -92,6 +92,32 @@ export class MidyGM2 {
92
92
  };
93
93
  };
94
94
  masterGain: any;
95
+ controlChangeHandlers: {
96
+ 0: (channelNumber: any, msb: any) => void;
97
+ 1: (channelNumber: any, modulation: any) => void;
98
+ 5: (channelNumber: any, portamentoTime: any) => void;
99
+ 6: (channelNumber: any, value: any) => void;
100
+ 7: (channelNumber: any, volume: any) => void;
101
+ 10: (channelNumber: any, pan: any) => void;
102
+ 11: (channelNumber: any, expression: any) => void;
103
+ 32: (channelNumber: any, lsb: any) => void;
104
+ 38: (channelNumber: any, value: any) => void;
105
+ 64: (channelNumber: any, value: any) => void;
106
+ 65: (channelNumber: any, value: any) => void;
107
+ 66: (channelNumber: any, value: any) => void;
108
+ 67: (channelNumber: any, softPedal: any) => void;
109
+ 91: (channelNumber: any, reverbSendLevel: any) => void;
110
+ 93: (channelNumber: any, chorusSendLevel: any) => void;
111
+ 100: (channelNumber: any, value: any) => void;
112
+ 101: (channelNumber: any, value: any) => void;
113
+ 120: (channelNumber: any) => Promise<void>;
114
+ 121: (channelNumber: any) => void;
115
+ 123: (channelNumber: any) => Promise<void>;
116
+ 124: () => void;
117
+ 125: () => void;
118
+ 126: () => void;
119
+ 127: () => void;
120
+ };
95
121
  channels: any[];
96
122
  reverbEffect: {
97
123
  input: any;
@@ -167,14 +193,15 @@ export class MidyGM2 {
167
193
  calcPlaybackRate(instrumentKey: any, noteNumber: any, semitoneOffset: any): number;
168
194
  setVolumeEnvelope(note: any): void;
169
195
  setPitch(note: any, semitoneOffset: any): void;
170
- setFilterNode(channel: any, note: any): void;
196
+ clampCutoffFrequency(frequency: any): number;
197
+ setFilterEnvelope(channel: any, note: any): void;
171
198
  startModulation(channel: any, note: any, startTime: any): void;
172
199
  startVibrato(channel: any, note: any, startTime: any): void;
173
200
  createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
174
201
  calcBank(channel: any, channelNumber: any): any;
175
202
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
176
203
  noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
177
- scheduleNoteRelease(channelNumber: any, noteNumber: any, velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
204
+ scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
178
205
  releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
179
206
  releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
180
207
  releaseSostenutoPedal(channelNumber: any, halfVelocity: any): any[];
@@ -183,7 +210,33 @@ export class MidyGM2 {
183
210
  handleChannelPressure(channelNumber: any, pressure: any): void;
184
211
  handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
185
212
  setPitchBend(channelNumber: any, pitchBend: any): void;
186
- handleControlChange(channelNumber: any, controller: any, value: any): void | Promise<void>;
213
+ createControlChangeHandlers(): {
214
+ 0: (channelNumber: any, msb: any) => void;
215
+ 1: (channelNumber: any, modulation: any) => void;
216
+ 5: (channelNumber: any, portamentoTime: any) => void;
217
+ 6: (channelNumber: any, value: any) => void;
218
+ 7: (channelNumber: any, volume: any) => void;
219
+ 10: (channelNumber: any, pan: any) => void;
220
+ 11: (channelNumber: any, expression: any) => void;
221
+ 32: (channelNumber: any, lsb: any) => void;
222
+ 38: (channelNumber: any, value: any) => void;
223
+ 64: (channelNumber: any, value: any) => void;
224
+ 65: (channelNumber: any, value: any) => void;
225
+ 66: (channelNumber: any, value: any) => void;
226
+ 67: (channelNumber: any, softPedal: any) => void;
227
+ 91: (channelNumber: any, reverbSendLevel: any) => void;
228
+ 93: (channelNumber: any, chorusSendLevel: any) => void;
229
+ 100: (channelNumber: any, value: any) => void;
230
+ 101: (channelNumber: any, value: any) => void;
231
+ 120: (channelNumber: any) => Promise<void>;
232
+ 121: (channelNumber: any) => void;
233
+ 123: (channelNumber: any) => Promise<void>;
234
+ 124: () => void;
235
+ 125: () => void;
236
+ 126: () => void;
237
+ 127: () => void;
238
+ };
239
+ handleControlChange(channelNumber: any, controller: any, value: any): void;
187
240
  setBankMSB(channelNumber: any, msb: any): void;
188
241
  updateModulation(channel: any): void;
189
242
  setModulationDepth(channelNumber: any, modulation: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MidyGM2 = void 0;
4
4
  const _esm_js_1 = require("./deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js");
5
- const _esm_js_2 = require("./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.js");
5
+ const _esm_js_2 = require("./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.js");
6
6
  class Note {
7
7
  constructor(noteNumber, velocity, startTime, instrumentKey) {
8
8
  Object.defineProperty(this, "bufferSource", {
@@ -233,6 +233,7 @@ class MidyGM2 {
233
233
  this.audioContext = audioContext;
234
234
  this.options = { ...this.defaultOptions, ...options };
235
235
  this.masterGain = new GainNode(audioContext);
236
+ this.controlChangeHandlers = this.createControlChangeHandlers();
236
237
  this.channels = this.createChannels(audioContext);
237
238
  this.reverbEffect = this.options.reverbAlgorithm(audioContext);
238
239
  this.chorusEffect = this.createChorusEffect(audioContext);
@@ -548,12 +549,13 @@ class MidyGM2 {
548
549
  const now = this.audioContext.currentTime;
549
550
  const channel = this.channels[channelNumber];
550
551
  channel.scheduledNotes.forEach((noteList) => {
551
- noteList.forEach((note) => {
552
- if (note) {
553
- const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, stopPedal);
554
- this.notePromises.push(promise);
555
- }
556
- });
552
+ for (let i = 0; i < noteList.length; i++) {
553
+ const note = noteList[i];
554
+ if (!note)
555
+ continue;
556
+ const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, stopPedal);
557
+ this.notePromises.push(promise);
558
+ }
557
559
  });
558
560
  channel.scheduledNotes.clear();
559
561
  await Promise.all(this.notePromises);
@@ -776,7 +778,6 @@ class MidyGM2 {
776
778
  }
777
779
  setVolumeEnvelope(note) {
778
780
  const { instrumentKey, startTime } = note;
779
- note.volumeNode = new GainNode(this.audioContext, { gain: 0 });
780
781
  const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
781
782
  const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
782
783
  const volDelay = startTime + instrumentKey.volDelay;
@@ -784,6 +785,8 @@ class MidyGM2 {
784
785
  const volHold = volAttack + instrumentKey.volHold;
785
786
  const volDecay = volHold + instrumentKey.volDecay;
786
787
  note.volumeNode.gain
788
+ .cancelScheduledValues(startTime)
789
+ .setValueAtTime(0, startTime)
787
790
  .setValueAtTime(1e-6, volDelay) // exponentialRampToValueAtTime() requires a non-zero value
788
791
  .exponentialRampToValueAtTime(attackVolume, volAttack)
789
792
  .setValueAtTime(attackVolume, volHold)
@@ -807,29 +810,30 @@ class MidyGM2 {
807
810
  .setValueAtTime(peekPitch, modHold)
808
811
  .linearRampToValueAtTime(basePitch, modDecay);
809
812
  }
810
- setFilterNode(channel, note) {
813
+ clampCutoffFrequency(frequency) {
814
+ const minFrequency = 20; // min Hz of initialFilterFc
815
+ const maxFrequency = 20000; // max Hz of initialFilterFc
816
+ return Math.max(minFrequency, Math.min(frequency, maxFrequency));
817
+ }
818
+ setFilterEnvelope(channel, note) {
811
819
  const { instrumentKey, noteNumber, startTime } = note;
812
820
  const softPedalFactor = 1 -
813
821
  (0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
814
- const maxFreq = this.audioContext.sampleRate / 2;
815
822
  const baseFreq = this.centToHz(instrumentKey.initialFilterFc) *
816
823
  softPedalFactor;
817
824
  const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc) * softPedalFactor;
818
825
  const sustainFreq = baseFreq +
819
826
  (peekFreq - baseFreq) * (1 - instrumentKey.modSustain);
820
- const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
821
- const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
822
- const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
827
+ const adjustedBaseFreq = this.clampCutoffFrequency(baseFreq);
828
+ const adjustedPeekFreq = this.clampCutoffFrequency(peekFreq);
829
+ const adjustedSustainFreq = this.clampCutoffFrequency(sustainFreq);
823
830
  const modDelay = startTime + instrumentKey.modDelay;
824
831
  const modAttack = modDelay + instrumentKey.modAttack;
825
832
  const modHold = modAttack + instrumentKey.modHold;
826
833
  const modDecay = modHold + instrumentKey.modDecay;
827
- note.filterNode = new BiquadFilterNode(this.audioContext, {
828
- type: "lowpass",
829
- Q: instrumentKey.initialFilterQ / 10, // dB
830
- frequency: adjustedBaseFreq,
831
- });
832
834
  note.filterNode.frequency
835
+ .cancelScheduledValues(startTime)
836
+ .setValueAtTime(adjustedBaseFreq, startTime)
833
837
  .setValueAtTime(adjustedBaseFreq, modDelay)
834
838
  .exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
835
839
  .setValueAtTime(adjustedPeekFreq, modHold)
@@ -882,8 +886,13 @@ class MidyGM2 {
882
886
  const semitoneOffset = this.calcSemitoneOffset(channel);
883
887
  const note = new Note(noteNumber, velocity, startTime, instrumentKey);
884
888
  note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
885
- this.setFilterNode(channel, note);
889
+ note.volumeNode = new GainNode(this.audioContext);
890
+ note.filterNode = new BiquadFilterNode(this.audioContext, {
891
+ type: "lowpass",
892
+ Q: instrumentKey.initialFilterQ / 10 * channel.filterResonance, // dB
893
+ });
886
894
  this.setVolumeEnvelope(note);
895
+ this.setFilterEnvelope(channel, note);
887
896
  if (0 < channel.vibratoDepth) {
888
897
  this.startVibrato(channel, note, startTime);
889
898
  }
@@ -920,7 +929,7 @@ class MidyGM2 {
920
929
  return;
921
930
  const soundFont = this.soundFonts[soundFontIndex];
922
931
  const isSF3 = soundFont.parsed.info.version.major === 3;
923
- const instrumentKey = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber);
932
+ const instrumentKey = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber, velocity);
924
933
  if (!instrumentKey)
925
934
  return;
926
935
  const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
@@ -941,12 +950,14 @@ class MidyGM2 {
941
950
  const now = this.audioContext.currentTime;
942
951
  return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now);
943
952
  }
944
- scheduleNoteRelease(channelNumber, noteNumber, velocity, stopTime, stopPedal = false) {
953
+ scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, stopPedal = false) {
945
954
  const channel = this.channels[channelNumber];
946
- if (stopPedal && channel.sustainPedal)
947
- return;
948
- if (stopPedal && channel.sostenutoNotes.has(noteNumber))
949
- return;
955
+ if (stopPedal) {
956
+ if (channel.sustainPedal)
957
+ return;
958
+ if (channel.sostenutoNotes.has(noteNumber))
959
+ return;
960
+ }
950
961
  if (!channel.scheduledNotes.has(noteNumber))
951
962
  return;
952
963
  const scheduledNotes = channel.scheduledNotes.get(noteNumber);
@@ -956,14 +967,11 @@ class MidyGM2 {
956
967
  continue;
957
968
  if (note.ending)
958
969
  continue;
959
- const velocityRate = (velocity + 127) / 127;
960
- const volEndTime = stopTime +
961
- note.instrumentKey.volRelease * velocityRate;
970
+ const volEndTime = stopTime + note.instrumentKey.volRelease;
962
971
  note.volumeNode.gain
963
972
  .cancelScheduledValues(stopTime)
964
973
  .linearRampToValueAtTime(0, volEndTime);
965
- const modRelease = stopTime +
966
- note.instrumentKey.modRelease * velocityRate;
974
+ const modRelease = stopTime + note.instrumentKey.modRelease;
967
975
  note.filterNode.frequency
968
976
  .cancelScheduledValues(stopTime)
969
977
  .linearRampToValueAtTime(0, modRelease);
@@ -977,16 +985,11 @@ class MidyGM2 {
977
985
  note.bufferSource.disconnect();
978
986
  note.volumeNode.disconnect();
979
987
  note.filterNode.disconnect();
980
- if (note.volumeDepth)
988
+ if (note.modulationDepth) {
981
989
  note.volumeDepth.disconnect();
982
- if (note.modulationDepth)
983
990
  note.modulationDepth.disconnect();
984
- if (note.modulationLFO)
985
991
  note.modulationLFO.stop();
986
- if (note.vibratoDepth)
987
- note.vibratoDepth.disconnect();
988
- if (note.vibratoLFO)
989
- note.vibratoLFO.stop();
992
+ }
990
993
  resolve();
991
994
  };
992
995
  note.bufferSource.stop(volEndTime);
@@ -1003,13 +1006,14 @@ class MidyGM2 {
1003
1006
  const promises = [];
1004
1007
  channel.sustainPedal = false;
1005
1008
  channel.scheduledNotes.forEach((noteList) => {
1006
- noteList.forEach((note) => {
1007
- if (note) {
1008
- const { noteNumber } = note;
1009
- const promise = this.releaseNote(channelNumber, noteNumber, velocity);
1010
- promises.push(promise);
1011
- }
1012
- });
1009
+ for (let i = 0; i < noteList.length; i++) {
1010
+ const note = noteList[i];
1011
+ if (!note)
1012
+ continue;
1013
+ const { noteNumber } = note;
1014
+ const promise = this.releaseNote(channelNumber, noteNumber, velocity);
1015
+ promises.push(promise);
1016
+ }
1013
1017
  });
1014
1018
  return promises;
1015
1019
  }
@@ -1078,58 +1082,41 @@ class MidyGM2 {
1078
1082
  channel.pitchBendRange * 100;
1079
1083
  this.updateDetune(channel, detuneChange);
1080
1084
  }
1085
+ createControlChangeHandlers() {
1086
+ return {
1087
+ 0: this.setBankMSB,
1088
+ 1: this.setModulationDepth,
1089
+ 5: this.setPortamentoTime,
1090
+ 6: this.dataEntryMSB,
1091
+ 7: this.setVolume,
1092
+ 10: this.setPan,
1093
+ 11: this.setExpression,
1094
+ 32: this.setBankLSB,
1095
+ 38: this.dataEntryLSB,
1096
+ 64: this.setSustainPedal,
1097
+ 65: this.setPortamento,
1098
+ 66: this.setSostenutoPedal,
1099
+ 67: this.setSoftPedal,
1100
+ 91: this.setReverbSendLevel,
1101
+ 93: this.setChorusSendLevel,
1102
+ 100: this.setRPNLSB,
1103
+ 101: this.setRPNMSB,
1104
+ 120: this.allSoundOff,
1105
+ 121: this.resetAllControllers,
1106
+ 123: this.allNotesOff,
1107
+ 124: this.omniOff,
1108
+ 125: this.omniOn,
1109
+ 126: this.monoOn,
1110
+ 127: this.polyOn,
1111
+ };
1112
+ }
1081
1113
  handleControlChange(channelNumber, controller, value) {
1082
- switch (controller) {
1083
- case 0:
1084
- return this.setBankMSB(channelNumber, value);
1085
- case 1:
1086
- return this.setModulationDepth(channelNumber, value);
1087
- case 5:
1088
- return this.setPortamentoTime(channelNumber, value);
1089
- case 6:
1090
- return this.dataEntryMSB(channelNumber, value);
1091
- case 7:
1092
- return this.setVolume(channelNumber, value);
1093
- case 10:
1094
- return this.setPan(channelNumber, value);
1095
- case 11:
1096
- return this.setExpression(channelNumber, value);
1097
- case 32:
1098
- return this.setBankLSB(channelNumber, value);
1099
- case 38:
1100
- return this.dataEntryLSB(channelNumber, value);
1101
- case 64:
1102
- return this.setSustainPedal(channelNumber, value);
1103
- case 65:
1104
- return this.setPortamento(channelNumber, value);
1105
- case 66:
1106
- return this.setSostenutoPedal(channelNumber, value);
1107
- case 67:
1108
- return this.setSoftPedal(channelNumber, value);
1109
- case 91:
1110
- return this.setReverbSendLevel(channelNumber, value);
1111
- case 93:
1112
- return this.setChorusSendLevel(channelNumber, value);
1113
- case 100:
1114
- return this.setRPNLSB(channelNumber, value);
1115
- case 101:
1116
- return this.setRPNMSB(channelNumber, value);
1117
- case 120:
1118
- return this.allSoundOff(channelNumber);
1119
- case 121:
1120
- return this.resetAllControllers(channelNumber);
1121
- case 123:
1122
- return this.allNotesOff(channelNumber);
1123
- case 124:
1124
- return this.omniOff();
1125
- case 125:
1126
- return this.omniOn();
1127
- case 126:
1128
- return this.monoOn();
1129
- case 127:
1130
- return this.polyOn();
1131
- default:
1132
- console.warn(`Unsupported Control change: controller=${controller} value=${value}`);
1114
+ const handler = this.controlChangeHandlers[controller];
1115
+ if (handler) {
1116
+ handler.call(this, channelNumber, value);
1117
+ }
1118
+ else {
1119
+ console.warn(`Unsupported Control change: controller=${controller} value=${value}`);
1133
1120
  }
1134
1121
  }
1135
1122
  setBankMSB(channelNumber, msb) {
@@ -1137,15 +1124,19 @@ class MidyGM2 {
1137
1124
  }
1138
1125
  updateModulation(channel) {
1139
1126
  const now = this.audioContext.currentTime;
1140
- const activeNotes = this.getActiveNotes(channel, now);
1141
- activeNotes.forEach((activeNote) => {
1142
- if (activeNote.modulationDepth) {
1143
- activeNote.modulationDepth.gain.setValueAtTime(channel.modulationDepth, now);
1144
- }
1145
- else {
1146
- const semitoneOffset = this.calcSemitoneOffset(channel);
1147
- this.setPitch(activeNote, semitoneOffset);
1148
- this.startModulation(channel, activeNote, now);
1127
+ channel.scheduledNotes.forEach((noteList) => {
1128
+ for (let i = 0; i < noteList.length; i++) {
1129
+ const note = noteList[i];
1130
+ if (!note)
1131
+ continue;
1132
+ if (note.modulationDepth) {
1133
+ note.modulationDepth.gain.setValueAtTime(channel.modulationDepth, now);
1134
+ }
1135
+ else {
1136
+ const semitoneOffset = this.calcSemitoneOffset(channel);
1137
+ this.setPitch(note, semitoneOffset);
1138
+ this.startModulation(channel, note, now);
1139
+ }
1149
1140
  }
1150
1141
  });
1151
1142
  }
@@ -1210,28 +1201,49 @@ class MidyGM2 {
1210
1201
  }
1211
1202
  setReverbSendLevel(channelNumber, reverbSendLevel) {
1212
1203
  const channel = this.channels[channelNumber];
1213
- const reverbEffect = this.reverbEffect;
1214
- if (0 < reverbSendLevel) {
1215
- const now = this.audioContext.currentTime;
1216
- channel.reverbSendLevel = reverbSendLevel / 127;
1217
- reverbEffect.output.gain.cancelScheduledValues(now);
1218
- reverbEffect.output.gain.setValueAtTime(channel.reverbSendLevel, now);
1204
+ if (0 < channel.reverbSendLevel) {
1205
+ if (0 < reverbSendLevel) {
1206
+ const now = this.audioContext.currentTime;
1207
+ channel.reverbSendLevel = reverbSendLevel / 127;
1208
+ reverbEffect.output.gain.cancelScheduledValues(now);
1209
+ reverbEffect.output.gain.setValueAtTime(channel.reverbSendLevel, now);
1210
+ }
1211
+ else {
1212
+ channel.merger.disconnect(reverbEffect.input);
1213
+ }
1219
1214
  }
1220
- else if (channel.reverbSendLevel !== 0) {
1221
- channel.merger.disconnect(reverbEffect.input);
1215
+ else {
1216
+ if (0 < reverbSendLevel) {
1217
+ channel.merger.connect(reverbEffect.input);
1218
+ const now = this.audioContext.currentTime;
1219
+ channel.reverbSendLevel = reverbSendLevel / 127;
1220
+ reverbEffect.output.gain.cancelScheduledValues(now);
1221
+ reverbEffect.output.gain.setValueAtTime(channel.reverbSendLevel, now);
1222
+ }
1222
1223
  }
1223
1224
  }
1224
1225
  setChorusSendLevel(channelNumber, chorusSendLevel) {
1225
1226
  const channel = this.channels[channelNumber];
1226
1227
  const chorusEffect = this.chorusEffect;
1227
- if (0 < chorusSendLevel) {
1228
- const now = this.audioContext.currentTime;
1229
- channel.chorusSendLevel = chorusSendLevel / 127;
1230
- chorusEffect.output.gain.cancelScheduledValues(now);
1231
- chorusEffect.output.gain.setValueAtTime(channel.chorusSendLevel, now);
1228
+ if (0 < channel.chorusSendLevel) {
1229
+ if (0 < chorusSendLevel) {
1230
+ const now = this.audioContext.currentTime;
1231
+ channel.chorusSendLevel = chorusSendLevel / 127;
1232
+ chorusEffect.output.gain.cancelScheduledValues(now);
1233
+ chorusEffect.output.gain.setValueAtTime(channel.chorusSendLevel, now);
1234
+ }
1235
+ else {
1236
+ channel.merger.disconnect(chorusEffect.input);
1237
+ }
1232
1238
  }
1233
- else if (channel.chorusSendLevel !== 0) {
1234
- channel.merger.disconnect(chorusEffect.input);
1239
+ else {
1240
+ if (0 < chorusSendLevel) {
1241
+ channel.merger.connect(chorusEffect.input);
1242
+ const now = this.audioContext.currentTime;
1243
+ channel.chorusSendLevel = chorusSendLevel / 127;
1244
+ chorusEffect.output.gain.cancelScheduledValues(now);
1245
+ chorusEffect.output.gain.setValueAtTime(channel.chorusSendLevel, now);
1246
+ }
1235
1247
  }
1236
1248
  }
1237
1249
  setSostenutoPedal(channelNumber, value) {
@@ -1309,13 +1321,17 @@ class MidyGM2 {
1309
1321
  }
1310
1322
  updateDetune(channel, detuneChange) {
1311
1323
  const now = this.audioContext.currentTime;
1312
- const activeNotes = this.getActiveNotes(channel, now);
1313
- activeNotes.forEach((activeNote) => {
1314
- const { bufferSource } = activeNote;
1315
- const detune = bufferSource.detune.value + detuneChange;
1316
- bufferSource.detune
1317
- .cancelScheduledValues(now)
1318
- .setValueAtTime(detune, now);
1324
+ channel.scheduledNotes.forEach((noteList) => {
1325
+ for (let i = 0; i < noteList.length; i++) {
1326
+ const note = noteList[i];
1327
+ if (!note)
1328
+ continue;
1329
+ const { bufferSource } = note;
1330
+ const detune = bufferSource.detune.value + detuneChange;
1331
+ bufferSource.detune
1332
+ .cancelScheduledValues(now)
1333
+ .setValueAtTime(detune, now);
1334
+ }
1319
1335
  });
1320
1336
  }
1321
1337
  handlePitchBendRangeRPN(channelNumber) {
@@ -37,6 +37,20 @@ export class MidyGMLite {
37
37
  notePromises: any[];
38
38
  audioContext: any;
39
39
  masterGain: any;
40
+ controlChangeHandlers: {
41
+ 1: (channelNumber: any, modulation: any) => void;
42
+ 6: (channelNumber: any, value: any) => void;
43
+ 7: (channelNumber: any, volume: any) => void;
44
+ 10: (channelNumber: any, pan: any) => void;
45
+ 11: (channelNumber: any, expression: any) => void;
46
+ 38: (channelNumber: any, value: any) => void;
47
+ 64: (channelNumber: any, value: any) => void;
48
+ 100: (channelNumber: any, value: any) => void;
49
+ 101: (channelNumber: any, value: any) => void;
50
+ 120: (channelNumber: any) => Promise<void>;
51
+ 121: (channelNumber: any) => void;
52
+ 123: (channelNumber: any) => Promise<void>;
53
+ };
40
54
  channels: any[];
41
55
  initSoundFontTable(): any[];
42
56
  addSoundFont(soundFont: any): void;
@@ -77,19 +91,34 @@ export class MidyGMLite {
77
91
  calcPlaybackRate(instrumentKey: any, noteNumber: any, semitoneOffset: any): number;
78
92
  setVolumeEnvelope(note: any): void;
79
93
  setPitch(note: any, semitoneOffset: any): void;
80
- setFilterNode(channel: any, note: any): void;
94
+ clampCutoffFrequency(frequency: any): number;
95
+ setFilterEnvelope(note: any): void;
81
96
  startModulation(channel: any, note: any, startTime: any): void;
82
97
  createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
83
98
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
84
99
  noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
85
- scheduleNoteRelease(channelNumber: any, noteNumber: any, velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
100
+ scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
86
101
  releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
87
102
  releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
88
103
  handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<any>;
89
104
  handleProgramChange(channelNumber: any, program: any): void;
90
105
  handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
91
106
  setPitchBend(channelNumber: any, pitchBend: any): void;
92
- handleControlChange(channelNumber: any, controller: any, value: any): void | Promise<void>;
107
+ createControlChangeHandlers(): {
108
+ 1: (channelNumber: any, modulation: any) => void;
109
+ 6: (channelNumber: any, value: any) => void;
110
+ 7: (channelNumber: any, volume: any) => void;
111
+ 10: (channelNumber: any, pan: any) => void;
112
+ 11: (channelNumber: any, expression: any) => void;
113
+ 38: (channelNumber: any, value: any) => void;
114
+ 64: (channelNumber: any, value: any) => void;
115
+ 100: (channelNumber: any, value: any) => void;
116
+ 101: (channelNumber: any, value: any) => void;
117
+ 120: (channelNumber: any) => Promise<void>;
118
+ 121: (channelNumber: any) => void;
119
+ 123: (channelNumber: any) => Promise<void>;
120
+ };
121
+ handleControlChange(channelNumber: any, controller: any, value: any): void;
93
122
  updateModulation(channel: any): void;
94
123
  setModulationDepth(channelNumber: any, modulation: any): void;
95
124
  setVolume(channelNumber: any, volume: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAsBA;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;IAC5C,gBAAiD;IAKnD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAUC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EA+CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA8DC;IAED,mFAmBC;IAED,yDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,2BAEC;IAED,4BAEC;IAED,yCAEC;IAED,mFAGC;IAED,mCAcC;IAED,+CAwBC;IAED,6CA6BC;IAED,+DA0BC;IAED,wHA8BC;IAED,kGA6BC;IAED,0EAGC;IAED,sIA4CC;IAED,0FAGC;IAED,kEAeC;IAED,gFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,uDAOC;IAED,2FA+BC;IAED,qCAeC;IAED,8DAIC;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,+CAEC;IAED,8CAEC;IAED,+CAEC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AA1+BD;IAQE,gFAKC;IAZD,kBAAa;IACb,gBAAW;IACX,gBAAW;IACX,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}
1
+ {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AAsBA;IAmBE;;;;;;;;;MASE;IAEF;;;;;;;MAOE;IAEF,+BAOC;IA7CD,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;IAC5C;;;;;;;;;;;;;MAA+D;IAC/D,gBAAiD;IAKnD,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAUC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EA+CC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MA8DC;IAED,mFAmBC;IAED,yDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,2BAEC;IAED,4BAEC;IAED,yCAEC;IAED,mFAGC;IAED,mCAeC;IAED,+CAwBC;IAED,6CAIC;IAED,mCAsBC;IAED,+DA0BC;IAED,wHAmCC;IAED,kGA8BC;IAED,0EAGC;IAED,uIA2CC;IAED,0FAGC;IAED,kEAeC;IAED,gFAiBC;IAED,4DAGC;IAED,qEAGC;IAED,uDAOC;IAED;;;;;;;;;;;;;MAeC;IAED,2EASC;IAED,qCAkBC;IAED,8DAIC;IACD,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,mDAGC;IAED,sCAUC;IAED,sDAMC;IAED,oCAYC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,oDAaC;IAED,kDAKC;IAED,iEAOC;IAED,+CAEC;IAED,8CAEC;IAED,+CAEC;IAED,4DAgBC;IAED,oBAQC;IAED,yDAaC;IAED,yCAGC;IAED,mCAQC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAj/BD;IAQE,gFAKC;IAZD,kBAAa;IACb,gBAAW;IACX,gBAAW;IACX,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}