@marmooo/midy 0.1.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/esm/midy-GM1.d.ts +53 -27
  2. package/esm/midy-GM1.d.ts.map +1 -1
  3. package/esm/midy-GM1.js +398 -146
  4. package/esm/midy-GM2.d.ts +55 -35
  5. package/esm/midy-GM2.d.ts.map +1 -1
  6. package/esm/midy-GM2.js +646 -244
  7. package/esm/midy-GMLite.d.ts +51 -26
  8. package/esm/midy-GMLite.d.ts.map +1 -1
  9. package/esm/midy-GMLite.js +379 -148
  10. package/esm/midy.d.ts +55 -40
  11. package/esm/midy.d.ts.map +1 -1
  12. package/esm/midy.js +662 -263
  13. package/package.json +5 -1
  14. package/script/midy-GM1.d.ts +53 -27
  15. package/script/midy-GM1.d.ts.map +1 -1
  16. package/script/midy-GM1.js +401 -149
  17. package/script/midy-GM2.d.ts +55 -35
  18. package/script/midy-GM2.d.ts.map +1 -1
  19. package/script/midy-GM2.js +649 -247
  20. package/script/midy-GMLite.d.ts +51 -26
  21. package/script/midy-GMLite.d.ts.map +1 -1
  22. package/script/midy-GMLite.js +382 -151
  23. package/script/midy.d.ts +55 -40
  24. package/script/midy.d.ts.map +1 -1
  25. package/script/midy.js +665 -266
  26. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.d.ts +0 -149
  27. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.d.ts.map +0 -1
  28. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.js +0 -180
  29. package/esm/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.d.ts +0 -84
  30. package/esm/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.d.ts.map +0 -1
  31. package/esm/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js +0 -216
  32. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.d.ts +0 -149
  33. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.d.ts.map +0 -1
  34. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.6/+esm.js +0 -190
  35. package/script/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.d.ts +0 -84
  36. package/script/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.d.ts.map +0 -1
  37. package/script/deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js +0 -221
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MidyGM2 = void 0;
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.6/+esm.js");
4
+ const midi_file_1 = require("midi-file");
5
+ const soundfont_parser_1 = require("@marmooo/soundfont-parser");
6
6
  class Note {
7
- constructor(noteNumber, velocity, startTime, instrumentKey) {
7
+ constructor(noteNumber, velocity, startTime, voice, voiceParams) {
8
8
  Object.defineProperty(this, "bufferSource", {
9
9
  enumerable: true,
10
10
  configurable: true,
@@ -53,12 +53,118 @@ class Note {
53
53
  writable: true,
54
54
  value: void 0
55
55
  });
56
+ Object.defineProperty(this, "reverbEffectsSend", {
57
+ enumerable: true,
58
+ configurable: true,
59
+ writable: true,
60
+ value: void 0
61
+ });
62
+ Object.defineProperty(this, "chorusEffectsSend", {
63
+ enumerable: true,
64
+ configurable: true,
65
+ writable: true,
66
+ value: void 0
67
+ });
68
+ Object.defineProperty(this, "portamento", {
69
+ enumerable: true,
70
+ configurable: true,
71
+ writable: true,
72
+ value: void 0
73
+ });
56
74
  this.noteNumber = noteNumber;
57
75
  this.velocity = velocity;
58
76
  this.startTime = startTime;
59
- this.instrumentKey = instrumentKey;
77
+ this.voice = voice;
78
+ this.voiceParams = voiceParams;
79
+ }
80
+ }
81
+ // normalized to 0-1 for use with the SF2 modulator model
82
+ const defaultControllerState = {
83
+ noteOnVelocity: { type: 2, defaultValue: 0 },
84
+ noteOnKeyNumber: { type: 3, defaultValue: 0 },
85
+ polyPressure: { type: 10, defaultValue: 0 },
86
+ channelPressure: { type: 13, defaultValue: 0 },
87
+ pitchWheel: { type: 14, defaultValue: 8192 / 16383 },
88
+ pitchWheelSensitivity: { type: 16, defaultValue: 2 / 128 },
89
+ link: { type: 127, defaultValue: 0 },
90
+ // bankMSB: { type: 128 + 0, defaultValue: 121, },
91
+ modulationDepth: { type: 128 + 1, defaultValue: 0 },
92
+ portamentoTime: { type: 128 + 5, defaultValue: 0 },
93
+ // dataMSB: { type: 128 + 6, defaultValue: 0, },
94
+ volume: { type: 128 + 7, defaultValue: 100 / 127 },
95
+ pan: { type: 128 + 10, defaultValue: 0.5 },
96
+ expression: { type: 128 + 11, defaultValue: 1 },
97
+ // bankLSB: { type: 128 + 32, defaultValue: 0, },
98
+ // dataLSB: { type: 128 + 38, defaultValue: 0, },
99
+ sustainPedal: { type: 128 + 64, defaultValue: 0 },
100
+ portamento: { type: 128 + 65, defaultValue: 0 },
101
+ sostenutoPedal: { type: 128 + 66, defaultValue: 0 },
102
+ softPedal: { type: 128 + 67, defaultValue: 0 },
103
+ filterResonance: { type: 128 + 71, defaultValue: 0.5 },
104
+ releaseTime: { type: 128 + 72, defaultValue: 0.5 },
105
+ attackTime: { type: 128 + 73, defaultValue: 0.5 },
106
+ brightness: { type: 128 + 74, defaultValue: 0.5 },
107
+ decayTime: { type: 128 + 75, defaultValue: 0.5 },
108
+ vibratoRate: { type: 128 + 76, defaultValue: 0.5 },
109
+ vibratoDepth: { type: 128 + 77, defaultValue: 0.5 },
110
+ vibratoDelay: { type: 128 + 78, defaultValue: 0.5 },
111
+ reverbSendLevel: { type: 128 + 91, defaultValue: 0 },
112
+ chorusSendLevel: { type: 128 + 93, defaultValue: 0 },
113
+ // dataIncrement: { type: 128 + 96, defaultValue: 0 },
114
+ // dataDecrement: { type: 128 + 97, defaultValue: 0 },
115
+ // rpnLSB: { type: 128 + 100, defaultValue: 127 },
116
+ // rpnMSB: { type: 128 + 101, defaultValue: 127 },
117
+ // allSoundOff: { type: 128 + 120, defaultValue: 0 },
118
+ // resetAllControllers: { type: 128 + 121, defaultValue: 0 },
119
+ // allNotesOff: { type: 128 + 123, defaultValue: 0 },
120
+ // omniOff: { type: 128 + 124, defaultValue: 0 },
121
+ // omniOn: { type: 128 + 125, defaultValue: 0 },
122
+ // monoOn: { type: 128 + 126, defaultValue: 0 },
123
+ // polyOn: { type: 128 + 127, defaultValue: 0 },
124
+ };
125
+ class ControllerState {
126
+ constructor() {
127
+ Object.defineProperty(this, "array", {
128
+ enumerable: true,
129
+ configurable: true,
130
+ writable: true,
131
+ value: new Float32Array(256)
132
+ });
133
+ const entries = Object.entries(defaultControllerState);
134
+ for (const [name, { type, defaultValue }] of entries) {
135
+ this.array[type] = defaultValue;
136
+ Object.defineProperty(this, name, {
137
+ get: () => this.array[type],
138
+ set: (value) => this.array[type] = value,
139
+ enumerable: true,
140
+ configurable: true,
141
+ });
142
+ }
60
143
  }
61
144
  }
145
+ const filterEnvelopeKeys = [
146
+ "modEnvToPitch",
147
+ "initialFilterFc",
148
+ "modEnvToFilterFc",
149
+ "modDelay",
150
+ "modAttack",
151
+ "modHold",
152
+ "modDecay",
153
+ "modSustain",
154
+ "modRelease",
155
+ "playbackRate",
156
+ ];
157
+ const filterEnvelopeKeySet = new Set(filterEnvelopeKeys);
158
+ const volumeEnvelopeKeys = [
159
+ "volDelay",
160
+ "volAttack",
161
+ "volHold",
162
+ "volDecay",
163
+ "volSustain",
164
+ "volRelease",
165
+ "initialAttenuation",
166
+ ];
167
+ const volumeEnvelopeKeySet = new Set(volumeEnvelopeKeys);
62
168
  class MidyGM2 {
63
169
  constructor(audioContext, options = this.defaultOptions) {
64
170
  Object.defineProperty(this, "ticksPerBeat", {
@@ -208,6 +314,12 @@ class MidyGM2 {
208
314
  writable: true,
209
315
  value: []
210
316
  });
317
+ Object.defineProperty(this, "exclusiveClassMap", {
318
+ enumerable: true,
319
+ configurable: true,
320
+ writable: true,
321
+ value: new Map()
322
+ });
211
323
  Object.defineProperty(this, "defaultOptions", {
212
324
  enumerable: true,
213
325
  configurable: true,
@@ -233,6 +345,7 @@ class MidyGM2 {
233
345
  this.audioContext = audioContext;
234
346
  this.options = { ...this.defaultOptions, ...options };
235
347
  this.masterGain = new GainNode(audioContext);
348
+ this.voiceParamsHandlers = this.createVoiceParamsHandlers();
236
349
  this.controlChangeHandlers = this.createControlChangeHandlers();
237
350
  this.channels = this.createChannels(audioContext);
238
351
  this.reverbEffect = this.options.reverbAlgorithm(audioContext);
@@ -264,14 +377,14 @@ class MidyGM2 {
264
377
  async loadSoundFont(soundFontUrl) {
265
378
  const response = await fetch(soundFontUrl);
266
379
  const arrayBuffer = await response.arrayBuffer();
267
- const parsed = (0, _esm_js_2.parse)(new Uint8Array(arrayBuffer));
268
- const soundFont = new _esm_js_2.SoundFont(parsed);
380
+ const parsed = (0, soundfont_parser_1.parse)(new Uint8Array(arrayBuffer));
381
+ const soundFont = new soundfont_parser_1.SoundFont(parsed);
269
382
  this.addSoundFont(soundFont);
270
383
  }
271
384
  async loadMIDI(midiUrl) {
272
385
  const response = await fetch(midiUrl);
273
386
  const arrayBuffer = await response.arrayBuffer();
274
- const midi = (0, _esm_js_1.parseMidi)(new Uint8Array(arrayBuffer));
387
+ const midi = (0, midi_file_1.parseMidi)(new Uint8Array(arrayBuffer));
275
388
  this.ticksPerBeat = midi.header.ticksPerBeat;
276
389
  const midiData = this.extractMidiData(midi);
277
390
  this.instruments = midiData.instruments;
@@ -279,7 +392,7 @@ class MidyGM2 {
279
392
  this.totalTime = this.calcTotalTime();
280
393
  }
281
394
  setChannelAudioNodes(audioContext) {
282
- const { gainLeft, gainRight } = this.panToGain(this.constructor.channelSettings.pan);
395
+ const { gainLeft, gainRight } = this.panToGain(defaultControllerState.pan.defaultValue);
283
396
  const gainL = new GainNode(audioContext, { gain: gainLeft });
284
397
  const gainR = new GainNode(audioContext, { gain: gainRight });
285
398
  const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
@@ -296,7 +409,7 @@ class MidyGM2 {
296
409
  const channels = Array.from({ length: 16 }, () => {
297
410
  return {
298
411
  ...this.constructor.channelSettings,
299
- ...this.constructor.effectSettings,
412
+ state: new ControllerState(),
300
413
  ...this.setChannelAudioNodes(audioContext),
301
414
  scheduledNotes: new Map(),
302
415
  sostenutoNotes: new Map(),
@@ -307,38 +420,43 @@ class MidyGM2 {
307
420
  });
308
421
  return channels;
309
422
  }
310
- async createNoteBuffer(instrumentKey, isSF3) {
311
- const sampleStart = instrumentKey.start;
312
- const sampleEnd = instrumentKey.sample.length + instrumentKey.end;
423
+ async createNoteBuffer(voiceParams, isSF3) {
424
+ const sampleStart = voiceParams.start;
425
+ const sampleEnd = voiceParams.sample.length + voiceParams.end;
313
426
  if (isSF3) {
314
- const sample = instrumentKey.sample.slice(sampleStart, sampleEnd);
315
- const audioBuffer = await this.audioContext.decodeAudioData(sample.buffer);
427
+ const sample = voiceParams.sample;
428
+ const start = sample.byteOffset + sampleStart;
429
+ const end = sample.byteOffset + sampleEnd;
430
+ const buffer = sample.buffer.slice(start, end);
431
+ const audioBuffer = await this.audioContext.decodeAudioData(buffer);
316
432
  return audioBuffer;
317
433
  }
318
434
  else {
319
- const sample = instrumentKey.sample.subarray(sampleStart, sampleEnd);
435
+ const sample = voiceParams.sample;
436
+ const start = sample.byteOffset + sampleStart;
437
+ const end = sample.byteOffset + sampleEnd;
438
+ const buffer = sample.buffer.slice(start, end);
320
439
  const audioBuffer = new AudioBuffer({
321
440
  numberOfChannels: 1,
322
441
  length: sample.length,
323
- sampleRate: instrumentKey.sampleRate,
442
+ sampleRate: voiceParams.sampleRate,
324
443
  });
325
444
  const channelData = audioBuffer.getChannelData(0);
326
- const int16Array = new Int16Array(sample.buffer);
445
+ const int16Array = new Int16Array(buffer);
327
446
  for (let i = 0; i < int16Array.length; i++) {
328
447
  channelData[i] = int16Array[i] / 32768;
329
448
  }
330
449
  return audioBuffer;
331
450
  }
332
451
  }
333
- async createNoteBufferNode(instrumentKey, isSF3) {
452
+ async createNoteBufferNode(voiceParams, isSF3) {
334
453
  const bufferSource = new AudioBufferSourceNode(this.audioContext);
335
- const audioBuffer = await this.createNoteBuffer(instrumentKey, isSF3);
454
+ const audioBuffer = await this.createNoteBuffer(voiceParams, isSF3);
336
455
  bufferSource.buffer = audioBuffer;
337
- bufferSource.loop = instrumentKey.sampleModes % 2 !== 0;
456
+ bufferSource.loop = voiceParams.sampleModes % 2 !== 0;
338
457
  if (bufferSource.loop) {
339
- bufferSource.loopStart = instrumentKey.loopStart /
340
- instrumentKey.sampleRate;
341
- bufferSource.loopEnd = instrumentKey.loopEnd / instrumentKey.sampleRate;
458
+ bufferSource.loopStart = voiceParams.loopStart / voiceParams.sampleRate;
459
+ bufferSource.loopEnd = voiceParams.loopEnd / voiceParams.sampleRate;
342
460
  }
343
461
  return bufferSource;
344
462
  }
@@ -392,7 +510,7 @@ class MidyGM2 {
392
510
  this.handleChannelPressure(event.channel, event.amount);
393
511
  break;
394
512
  case "pitchBend":
395
- this.setPitchBend(event.channel, event.value);
513
+ this.setPitchBend(event.channel, event.value + 8192);
396
514
  break;
397
515
  case "sysEx":
398
516
  this.handleSysEx(event.data);
@@ -421,6 +539,7 @@ class MidyGM2 {
421
539
  if (queueIndex >= this.timeline.length) {
422
540
  await Promise.all(this.notePromises);
423
541
  this.notePromises = [];
542
+ this.exclusiveClassMap.clear();
424
543
  resolve();
425
544
  return;
426
545
  }
@@ -436,6 +555,7 @@ class MidyGM2 {
436
555
  }
437
556
  else if (this.isStopping) {
438
557
  await this.stopNotes(0, true);
558
+ this.exclusiveClassMap.clear();
439
559
  this.notePromises = [];
440
560
  resolve();
441
561
  this.isStopping = false;
@@ -444,6 +564,7 @@ class MidyGM2 {
444
564
  }
445
565
  else if (this.isSeeking) {
446
566
  this.stopNotes(0, true);
567
+ this.exclusiveClassMap.clear();
447
568
  this.startTime = this.audioContext.currentTime;
448
569
  queueIndex = this.getQueueIndex(this.resumeTime);
449
570
  offset = this.resumeTime - this.startTime;
@@ -672,14 +793,14 @@ class MidyGM2 {
672
793
  return impulse;
673
794
  }
674
795
  createConvolutionReverb(audioContext, impulse) {
675
- const output = new GainNode(audioContext);
796
+ const input = new GainNode(audioContext);
676
797
  const convolverNode = new ConvolverNode(audioContext, {
677
798
  buffer: impulse,
678
799
  });
679
- convolverNode.connect(output);
800
+ input.connect(convolverNode);
680
801
  return {
681
- input: convolverNode,
682
- output,
802
+ input,
803
+ output: convolverNode,
683
804
  convolverNode,
684
805
  };
685
806
  }
@@ -721,7 +842,6 @@ class MidyGM2 {
721
842
  // M.R.Schroeder, "Natural Sounding Artificial Reverberation", J.Audio Eng. Soc., vol.10, p.219, 1962
722
843
  createSchroederReverb(audioContext, combFeedbacks, combDelays, allpassFeedbacks, allpassDelays) {
723
844
  const input = new GainNode(audioContext);
724
- const output = new GainNode(audioContext);
725
845
  const mergerGain = new GainNode(audioContext);
726
846
  for (let i = 0; i < combDelays.length; i++) {
727
847
  const comb = this.createCombFilter(audioContext, input, combDelays[i], combFeedbacks[i]);
@@ -732,7 +852,7 @@ class MidyGM2 {
732
852
  const allpass = this.createAllpassFilter(audioContext, (i === 0) ? mergerGain : allpasses.at(-1), allpassDelays[i], allpassFeedbacks[i]);
733
853
  allpasses.push(allpass);
734
854
  }
735
- allpasses.at(-1).connect(output);
855
+ const output = allpasses.at(-1);
736
856
  return { input, output };
737
857
  }
738
858
  createChorusEffect(audioContext) {
@@ -787,53 +907,62 @@ class MidyGM2 {
787
907
  calcSemitoneOffset(channel) {
788
908
  const masterTuning = this.masterCoarseTuning + this.masterFineTuning;
789
909
  const channelTuning = channel.coarseTuning + channel.fineTuning;
790
- const tuning = masterTuning + channelTuning;
791
- return channel.pitchBend * channel.pitchBendRange + tuning;
792
- }
793
- calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset) {
794
- return instrumentKey.playbackRate(noteNumber) *
795
- Math.pow(2, semitoneOffset / 12);
910
+ const pitchWheel = channel.state.pitchWheel * 2 - 1;
911
+ const pitchWheelSensitivity = channel.state.pitchWheelSensitivity * 128;
912
+ const pitch = pitchWheel * pitchWheelSensitivity;
913
+ return masterTuning + channelTuning + pitch;
796
914
  }
797
915
  setPortamentoStartVolumeEnvelope(channel, note) {
798
- const { instrumentKey, startTime } = note;
799
- const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
800
- const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
801
- const volDelay = startTime + instrumentKey.volDelay;
802
- const portamentoTime = volDelay + channel.portamentoTime;
916
+ const now = this.audioContext.currentTime;
917
+ const { voiceParams, startTime } = note;
918
+ const attackVolume = this.cbToRatio(-voiceParams.initialAttenuation);
919
+ const sustainVolume = attackVolume * (1 - voiceParams.volSustain);
920
+ const volDelay = startTime + voiceParams.volDelay;
921
+ const portamentoTime = volDelay + channel.state.portamentoTime;
803
922
  note.volumeNode.gain
804
- .cancelScheduledValues(startTime)
923
+ .cancelScheduledValues(now)
805
924
  .setValueAtTime(0, volDelay)
806
925
  .linearRampToValueAtTime(sustainVolume, portamentoTime);
807
926
  }
808
927
  setVolumeEnvelope(note) {
809
- const { instrumentKey, startTime } = note;
810
- const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
811
- const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
812
- const volDelay = startTime + instrumentKey.volDelay;
813
- const volAttack = volDelay + instrumentKey.volAttack;
814
- const volHold = volAttack + instrumentKey.volHold;
815
- const volDecay = volHold + instrumentKey.volDecay;
928
+ const now = this.audioContext.currentTime;
929
+ const { voiceParams, startTime } = note;
930
+ const attackVolume = this.cbToRatio(-voiceParams.initialAttenuation);
931
+ const sustainVolume = attackVolume * (1 - voiceParams.volSustain);
932
+ const volDelay = startTime + voiceParams.volDelay;
933
+ const volAttack = volDelay + voiceParams.volAttack;
934
+ const volHold = volAttack + voiceParams.volHold;
935
+ const volDecay = volHold + voiceParams.volDecay;
816
936
  note.volumeNode.gain
817
- .cancelScheduledValues(startTime)
937
+ .cancelScheduledValues(now)
818
938
  .setValueAtTime(0, startTime)
819
939
  .setValueAtTime(1e-6, volDelay) // exponentialRampToValueAtTime() requires a non-zero value
820
940
  .exponentialRampToValueAtTime(attackVolume, volAttack)
821
941
  .setValueAtTime(attackVolume, volHold)
822
942
  .linearRampToValueAtTime(sustainVolume, volDecay);
823
943
  }
824
- setPitch(note, semitoneOffset) {
825
- const { instrumentKey, noteNumber, startTime } = note;
826
- const modEnvToPitch = instrumentKey.modEnvToPitch / 100;
827
- note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
944
+ setPlaybackRate(note) {
945
+ const now = this.audioContext.currentTime;
946
+ note.bufferSource.playbackRate
947
+ .cancelScheduledValues(now)
948
+ .setValueAtTime(note.voiceParams.playbackRate, now);
949
+ }
950
+ setPitch(channel, note) {
951
+ const now = this.audioContext.currentTime;
952
+ const { startTime } = note;
953
+ const basePitch = this.calcSemitoneOffset(channel) * 100;
954
+ note.bufferSource.detune
955
+ .cancelScheduledValues(now)
956
+ .setValueAtTime(basePitch, startTime);
957
+ const modEnvToPitch = note.voiceParams.modEnvToPitch;
828
958
  if (modEnvToPitch === 0)
829
959
  return;
830
- const basePitch = note.bufferSource.playbackRate.value;
831
- const peekPitch = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset + modEnvToPitch);
832
- const modDelay = startTime + instrumentKey.modDelay;
833
- const modAttack = modDelay + instrumentKey.modAttack;
834
- const modHold = modAttack + instrumentKey.modHold;
835
- const modDecay = modHold + instrumentKey.modDecay;
836
- note.bufferSource.playbackRate.value
960
+ const peekPitch = basePitch + modEnvToPitch;
961
+ const modDelay = startTime + voiceParams.modDelay;
962
+ const modAttack = modDelay + voiceParams.modAttack;
963
+ const modHold = modAttack + voiceParams.modHold;
964
+ const modDecay = modHold + voiceParams.modDecay;
965
+ note.bufferSource.detune
837
966
  .setValueAtTime(basePitch, modDelay)
838
967
  .exponentialRampToValueAtTime(peekPitch, modAttack)
839
968
  .setValueAtTime(peekPitch, modHold)
@@ -845,42 +974,46 @@ class MidyGM2 {
845
974
  return Math.max(minFrequency, Math.min(frequency, maxFrequency));
846
975
  }
847
976
  setPortamentoStartFilterEnvelope(channel, note) {
848
- const { instrumentKey, noteNumber, startTime } = note;
977
+ const now = this.audioContext.currentTime;
978
+ const state = channel.state;
979
+ const { voiceParams, noteNumber, startTime } = note;
849
980
  const softPedalFactor = 1 -
850
- (0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
851
- const baseFreq = this.centToHz(instrumentKey.initialFilterFc) *
981
+ (0.1 + (noteNumber / 127) * 0.2) * state.softPedal;
982
+ const baseFreq = this.centToHz(voiceParams.initialFilterFc) *
852
983
  softPedalFactor;
853
- const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc) * softPedalFactor;
984
+ const peekFreq = this.centToHz(voiceParams.initialFilterFc + voiceParams.modEnvToFilterFc) * softPedalFactor;
854
985
  const sustainFreq = baseFreq +
855
- (peekFreq - baseFreq) * (1 - instrumentKey.modSustain);
986
+ (peekFreq - baseFreq) * (1 - voiceParams.modSustain);
856
987
  const adjustedBaseFreq = this.clampCutoffFrequency(baseFreq);
857
988
  const adjustedSustainFreq = this.clampCutoffFrequency(sustainFreq);
858
- const portamentoTime = startTime + channel.portamentoTime;
859
- const modDelay = startTime + instrumentKey.modDelay;
989
+ const portamentoTime = startTime + channel.state.portamentoTime;
990
+ const modDelay = startTime + voiceParams.modDelay;
860
991
  note.filterNode.frequency
861
- .cancelScheduledValues(startTime)
992
+ .cancelScheduledValues(now)
862
993
  .setValueAtTime(adjustedBaseFreq, startTime)
863
994
  .setValueAtTime(adjustedBaseFreq, modDelay)
864
995
  .linearRampToValueAtTime(adjustedSustainFreq, portamentoTime);
865
996
  }
866
997
  setFilterEnvelope(channel, note) {
867
- const { instrumentKey, noteNumber, startTime } = note;
998
+ const now = this.audioContext.currentTime;
999
+ const state = channel.state;
1000
+ const { voiceParams, noteNumber, startTime } = note;
868
1001
  const softPedalFactor = 1 -
869
- (0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
870
- const baseFreq = this.centToHz(instrumentKey.initialFilterFc) *
1002
+ (0.1 + (noteNumber / 127) * 0.2) * state.softPedal;
1003
+ const baseFreq = this.centToHz(voiceParams.initialFilterFc) *
871
1004
  softPedalFactor;
872
- const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc) * softPedalFactor;
1005
+ const peekFreq = this.centToHz(voiceParams.initialFilterFc + voiceParams.modEnvToFilterFc) * softPedalFactor;
873
1006
  const sustainFreq = baseFreq +
874
- (peekFreq - baseFreq) * (1 - instrumentKey.modSustain);
1007
+ (peekFreq - baseFreq) * (1 - voiceParams.modSustain);
875
1008
  const adjustedBaseFreq = this.clampCutoffFrequency(baseFreq);
876
1009
  const adjustedPeekFreq = this.clampCutoffFrequency(peekFreq);
877
1010
  const adjustedSustainFreq = this.clampCutoffFrequency(sustainFreq);
878
- const modDelay = startTime + instrumentKey.modDelay;
879
- const modAttack = modDelay + instrumentKey.modAttack;
880
- const modHold = modAttack + instrumentKey.modHold;
881
- const modDecay = modHold + instrumentKey.modDecay;
1011
+ const modDelay = startTime + voiceParams.modDelay;
1012
+ const modAttack = modDelay + voiceParams.modAttack;
1013
+ const modHold = modAttack + voiceParams.modHold;
1014
+ const modDecay = modHold + voiceParams.modDecay;
882
1015
  note.filterNode.frequency
883
- .cancelScheduledValues(startTime)
1016
+ .cancelScheduledValues(now)
884
1017
  .setValueAtTime(adjustedBaseFreq, startTime)
885
1018
  .setValueAtTime(adjustedBaseFreq, modDelay)
886
1019
  .exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
@@ -888,25 +1021,18 @@ class MidyGM2 {
888
1021
  .linearRampToValueAtTime(adjustedSustainFreq, modDecay);
889
1022
  }
890
1023
  startModulation(channel, note, startTime) {
891
- const { instrumentKey } = note;
892
- const { modLfoToPitch, modLfoToVolume } = instrumentKey;
1024
+ const { voiceParams } = note;
893
1025
  note.modulationLFO = new OscillatorNode(this.audioContext, {
894
- frequency: this.centToHz(instrumentKey.freqModLFO),
1026
+ frequency: this.centToHz(voiceParams.freqModLFO),
895
1027
  });
896
1028
  note.filterDepth = new GainNode(this.audioContext, {
897
- gain: instrumentKey.modLfoToFilterFc,
1029
+ gain: voiceParams.modLfoToFilterFc,
898
1030
  });
899
- const modulationDepth = Math.abs(modLfoToPitch) + channel.modulationDepth;
900
- const modulationDepthSign = (0 < modLfoToPitch) ? 1 : -1;
901
- note.modulationDepth = new GainNode(this.audioContext, {
902
- gain: modulationDepth * modulationDepthSign,
903
- });
904
- const volumeDepth = this.cbToRatio(Math.abs(modLfoToVolume)) - 1;
905
- const volumeDepthSign = (0 < modLfoToVolume) ? 1 : -1;
906
- note.volumeDepth = new GainNode(this.audioContext, {
907
- gain: volumeDepth * volumeDepthSign,
908
- });
909
- note.modulationLFO.start(startTime + instrumentKey.delayModLFO);
1031
+ note.modulationDepth = new GainNode(this.audioContext);
1032
+ this.setModLfoToPitch(channel, note);
1033
+ note.volumeDepth = new GainNode(this.audioContext);
1034
+ this.setModLfoToVolume(note);
1035
+ note.modulationLFO.start(startTime + voiceParams.delayModLFO);
910
1036
  note.modulationLFO.connect(note.filterDepth);
911
1037
  note.filterDepth.connect(note.filterNode.frequency);
912
1038
  note.modulationLFO.connect(note.modulationDepth);
@@ -915,54 +1041,59 @@ class MidyGM2 {
915
1041
  note.volumeDepth.connect(note.volumeNode.gain);
916
1042
  }
917
1043
  startVibrato(channel, note, startTime) {
918
- const { instrumentKey } = note;
919
- const { vibLfoToPitch } = instrumentKey;
1044
+ const { voiceParams } = note;
1045
+ const state = channel.state;
920
1046
  note.vibratoLFO = new OscillatorNode(this.audioContext, {
921
- frequency: this.centToHz(instrumentKey.freqVibLFO) *
922
- channel.vibratoRate,
923
- });
924
- const vibratoDepth = Math.abs(vibLfoToPitch) * channel.vibratoDepth;
925
- const vibratoDepthSign = 0 < vibLfoToPitch;
926
- note.vibratoDepth = new GainNode(this.audioContext, {
927
- gain: vibratoDepth * vibratoDepthSign,
1047
+ frequency: this.centToHz(voiceParams.freqVibLFO) *
1048
+ state.vibratoRate,
928
1049
  });
929
- note.vibratoLFO.start(startTime + instrumentKey.delayVibLFO * channel.vibratoDelay);
1050
+ note.vibratoLFO.start(startTime + voiceParams.delayVibLFO * state.vibratoDelay * 2);
1051
+ note.vibratoDepth = new GainNode(this.audioContext);
1052
+ this.setVibLfoToPitch(channel, note);
930
1053
  note.vibratoLFO.connect(note.vibratoDepth);
931
1054
  note.vibratoDepth.connect(note.bufferSource.detune);
932
1055
  }
933
- async createNote(channel, instrumentKey, noteNumber, velocity, startTime, portamento, isSF3) {
934
- const semitoneOffset = this.calcSemitoneOffset(channel);
935
- const note = new Note(noteNumber, velocity, startTime, instrumentKey);
936
- note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
1056
+ async createNote(channel, voice, noteNumber, velocity, startTime, portamento, isSF3) {
1057
+ const state = channel.state;
1058
+ const controllerState = this.getControllerState(channel, noteNumber, velocity);
1059
+ const voiceParams = voice.getAllParams(controllerState);
1060
+ const note = new Note(noteNumber, velocity, startTime, voice, voiceParams);
1061
+ note.bufferSource = await this.createNoteBufferNode(voiceParams, isSF3);
937
1062
  note.volumeNode = new GainNode(this.audioContext);
938
1063
  note.filterNode = new BiquadFilterNode(this.audioContext, {
939
1064
  type: "lowpass",
940
- Q: instrumentKey.initialFilterQ / 10, // dB
1065
+ Q: voiceParams.initialFilterQ / 10, // dB
941
1066
  });
942
1067
  if (portamento) {
1068
+ note.portamento = true;
943
1069
  this.setPortamentoStartVolumeEnvelope(channel, note);
944
1070
  this.setPortamentoStartFilterEnvelope(channel, note);
945
1071
  }
946
1072
  else {
947
- this.setVolumeEnvelope(note);
1073
+ note.portamento = false;
1074
+ this.setVolumeEnvelope(channel, note);
948
1075
  this.setFilterEnvelope(channel, note);
949
1076
  }
950
- if (0 < channel.vibratoDepth) {
1077
+ if (0 < state.vibratoDepth) {
951
1078
  this.startVibrato(channel, note, startTime);
952
1079
  }
953
- if (0 < channel.modulationDepth) {
954
- this.setPitch(note, semitoneOffset);
1080
+ this.setPlaybackRate(note);
1081
+ if (0 < state.modulationDepth) {
1082
+ this.setPitch(channel, note);
955
1083
  this.startModulation(channel, note, startTime);
956
1084
  }
957
- else {
958
- note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
959
- }
960
1085
  if (this.mono && channel.currentBufferSource) {
961
1086
  channel.currentBufferSource.stop(startTime);
962
1087
  channel.currentBufferSource = note.bufferSource;
963
1088
  }
964
1089
  note.bufferSource.connect(note.filterNode);
965
1090
  note.filterNode.connect(note.volumeNode);
1091
+ if (0 < channel.chorusSendLevel) {
1092
+ this.setChorusEffectsSend(channel, note, 0);
1093
+ }
1094
+ if (0 < channel.reverbSendLevel) {
1095
+ this.setReverbEffectsSend(channel, note, 0);
1096
+ }
966
1097
  note.bufferSource.start(startTime);
967
1098
  return note;
968
1099
  }
@@ -983,15 +1114,28 @@ class MidyGM2 {
983
1114
  return;
984
1115
  const soundFont = this.soundFonts[soundFontIndex];
985
1116
  const isSF3 = soundFont.parsed.info.version.major === 3;
986
- const instrumentKey = soundFont.getInstrumentKey(bankNumber, channel.program, noteNumber, velocity);
987
- if (!instrumentKey)
1117
+ const voice = soundFont.getVoice(bankNumber, channel.program, noteNumber, velocity);
1118
+ if (!voice)
988
1119
  return;
989
- const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, portamento, isSF3);
1120
+ const note = await this.createNote(channel, voice, noteNumber, velocity, startTime, portamento, isSF3);
990
1121
  note.volumeNode.connect(channel.gainL);
991
1122
  note.volumeNode.connect(channel.gainR);
992
- if (channel.sostenutoPedal) {
1123
+ if (channel.state.sostenutoPedal) {
993
1124
  channel.sostenutoNotes.set(noteNumber, note);
994
1125
  }
1126
+ const exclusiveClass = note.voiceParams.exclusiveClass;
1127
+ if (exclusiveClass !== 0) {
1128
+ if (this.exclusiveClassMap.has(exclusiveClass)) {
1129
+ const prevEntry = this.exclusiveClassMap.get(exclusiveClass);
1130
+ const [prevNote, prevChannelNumber] = prevEntry;
1131
+ if (!prevNote.ending) {
1132
+ this.scheduleNoteRelease(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
1133
+ startTime, undefined, // portamentoNoteNumber
1134
+ true);
1135
+ }
1136
+ }
1137
+ this.exclusiveClassMap.set(exclusiveClass, [note, channelNumber]);
1138
+ }
995
1139
  const scheduledNotes = channel.scheduledNotes;
996
1140
  if (scheduledNotes.has(noteNumber)) {
997
1141
  scheduledNotes.get(noteNumber).push(note);
@@ -1004,15 +1148,15 @@ class MidyGM2 {
1004
1148
  const now = this.audioContext.currentTime;
1005
1149
  return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now, portamento);
1006
1150
  }
1007
- stopNote(stopTime, endTime, scheduledNotes, index) {
1151
+ stopNote(endTime, stopTime, scheduledNotes, index) {
1008
1152
  const note = scheduledNotes[index];
1009
1153
  note.volumeNode.gain
1010
- .cancelScheduledValues(stopTime)
1011
- .linearRampToValueAtTime(0, endTime);
1154
+ .cancelScheduledValues(endTime)
1155
+ .linearRampToValueAtTime(0, stopTime);
1012
1156
  note.ending = true;
1013
1157
  this.scheduleTask(() => {
1014
1158
  note.bufferSource.loop = false;
1015
- }, endTime);
1159
+ }, stopTime);
1016
1160
  return new Promise((resolve) => {
1017
1161
  note.bufferSource.onended = () => {
1018
1162
  scheduledNotes[index] = null;
@@ -1028,15 +1172,22 @@ class MidyGM2 {
1028
1172
  note.vibratoDepth.disconnect();
1029
1173
  note.vibratoLFO.stop();
1030
1174
  }
1175
+ if (note.reverbEffectsSend) {
1176
+ note.reverbEffectsSend.disconnect();
1177
+ }
1178
+ if (note.chorusEffectsSend) {
1179
+ note.chorusEffectsSend.disconnect();
1180
+ }
1031
1181
  resolve();
1032
1182
  };
1033
- note.bufferSource.stop(endTime);
1183
+ note.bufferSource.stop(stopTime);
1034
1184
  });
1035
1185
  }
1036
- scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, portamentoNoteNumber, force) {
1186
+ scheduleNoteRelease(channelNumber, noteNumber, _velocity, endTime, portamentoNoteNumber, force) {
1037
1187
  const channel = this.channels[channelNumber];
1188
+ const state = channel.state;
1038
1189
  if (!force) {
1039
- if (channel.sustainPedal)
1190
+ if (0.5 < state.sustainPedal)
1040
1191
  return;
1041
1192
  if (channel.sostenutoNotes.has(noteNumber))
1042
1193
  return;
@@ -1051,21 +1202,22 @@ class MidyGM2 {
1051
1202
  if (note.ending)
1052
1203
  continue;
1053
1204
  if (portamentoNoteNumber === undefined) {
1054
- const volEndTime = stopTime + note.instrumentKey.volRelease;
1055
- const modRelease = stopTime + note.instrumentKey.modRelease;
1205
+ const volRelease = endTime + note.voiceParams.volRelease;
1206
+ const modRelease = endTime + note.voiceParams.modRelease;
1056
1207
  note.filterNode.frequency
1057
- .cancelScheduledValues(stopTime)
1208
+ .cancelScheduledValues(endTime)
1058
1209
  .linearRampToValueAtTime(0, modRelease);
1059
- return this.stopNote(stopTime, volEndTime, scheduledNotes, i);
1210
+ const stopTime = Math.min(volRelease, modRelease);
1211
+ return this.stopNote(endTime, stopTime, scheduledNotes, i);
1060
1212
  }
1061
1213
  else {
1062
- const portamentoTime = stopTime + channel.portamentoTime;
1214
+ const portamentoTime = endTime + state.portamentoTime;
1063
1215
  const detuneChange = (portamentoNoteNumber - noteNumber) * 100;
1064
1216
  const detune = note.bufferSource.detune.value + detuneChange;
1065
1217
  note.bufferSource.detune
1066
- .cancelScheduledValues(stopTime)
1218
+ .cancelScheduledValues(endTime)
1067
1219
  .linearRampToValueAtTime(detune, portamentoTime);
1068
- return this.stopNote(stopTime, portamentoTime, scheduledNotes, i);
1220
+ return this.stopNote(endTime, portamentoTime, scheduledNotes, i);
1069
1221
  }
1070
1222
  }
1071
1223
  }
@@ -1077,7 +1229,7 @@ class MidyGM2 {
1077
1229
  const velocity = halfVelocity * 2;
1078
1230
  const channel = this.channels[channelNumber];
1079
1231
  const promises = [];
1080
- channel.sustainPedal = false;
1232
+ channel.state.sustainPedal = halfVelocity;
1081
1233
  channel.scheduledNotes.forEach((noteList) => {
1082
1234
  for (let i = 0; i < noteList.length; i++) {
1083
1235
  const note = noteList[i];
@@ -1094,7 +1246,7 @@ class MidyGM2 {
1094
1246
  const velocity = halfVelocity * 2;
1095
1247
  const channel = this.channels[channelNumber];
1096
1248
  const promises = [];
1097
- channel.sostenutoPedal = false;
1249
+ channel.state.sostenutoPedal = 0;
1098
1250
  channel.sostenutoNotes.forEach((activeNote) => {
1099
1251
  const { noteNumber } = activeNote;
1100
1252
  const promise = this.releaseNote(channelNumber, noteNumber, velocity);
@@ -1142,18 +1294,232 @@ class MidyGM2 {
1142
1294
  .setValueAtTime(gain * pressure, now);
1143
1295
  });
1144
1296
  }
1297
+ // this.applyVoiceParams(channel, 13);
1145
1298
  }
1146
1299
  handlePitchBendMessage(channelNumber, lsb, msb) {
1147
- const pitchBend = msb * 128 + lsb - 8192;
1300
+ const pitchBend = msb * 128 + lsb;
1148
1301
  this.setPitchBend(channelNumber, pitchBend);
1149
1302
  }
1150
- setPitchBend(channelNumber, pitchBend) {
1303
+ setPitchBend(channelNumber, value) {
1151
1304
  const channel = this.channels[channelNumber];
1152
- const prevPitchBend = channel.pitchBend;
1153
- channel.pitchBend = pitchBend / 8192;
1154
- const detuneChange = (channel.pitchBend - prevPitchBend) *
1155
- channel.pitchBendRange * 100;
1305
+ const state = channel.state;
1306
+ state.pitchWheel = value / 16383;
1307
+ const pitchWheel = (value - 8192) / 8192;
1308
+ const detuneChange = pitchWheel * state.pitchWheelSensitivity * 12800;
1156
1309
  this.updateDetune(channel, detuneChange);
1310
+ this.applyVoiceParams(channel, 14);
1311
+ }
1312
+ setModLfoToPitch(channel, note) {
1313
+ const now = this.audioContext.currentTime;
1314
+ const modLfoToPitch = note.voiceParams.modLfoToPitch;
1315
+ const modulationDepth = Math.abs(modLfoToPitch) +
1316
+ channel.state.modulationDepth;
1317
+ const modulationDepthSign = (0 < modLfoToPitch) ? 1 : -1;
1318
+ note.modulationDepth.gain
1319
+ .cancelScheduledValues(now)
1320
+ .setValueAtTime(modulationDepth * modulationDepthSign, now);
1321
+ }
1322
+ setModLfoToVolume(note) {
1323
+ const now = this.audioContext.currentTime;
1324
+ const modLfoToVolume = note.voiceParams.modLfoToVolume;
1325
+ const volumeDepth = this.cbToRatio(Math.abs(modLfoToVolume)) - 1;
1326
+ const volumeDepthSign = (0 < modLfoToVolume) ? 1 : -1;
1327
+ note.volumeDepth.gain
1328
+ .cancelScheduledValues(now)
1329
+ .setValueAtTime(volumeDepth * volumeDepthSign, now);
1330
+ }
1331
+ setChorusEffectsSend(note, prevValue) {
1332
+ if (0 < prevValue) {
1333
+ if (0 < note.voiceParams.chorusEffectsSend) {
1334
+ const now = this.audioContext.currentTime;
1335
+ const value = note.voiceParams.chorusEffectsSend;
1336
+ note.chorusEffectsSend.gain
1337
+ .cancelScheduledValues(now)
1338
+ .setValueAtTime(value, now);
1339
+ }
1340
+ else {
1341
+ note.chorusEffectsSend.disconnect();
1342
+ }
1343
+ }
1344
+ else {
1345
+ if (0 < note.voiceParams.chorusEffectsSend) {
1346
+ if (!note.chorusEffectsSend) {
1347
+ note.chorusEffectsSend = new GainNode(this.audioContext, {
1348
+ gain: note.voiceParams.chorusEffectsSend,
1349
+ });
1350
+ note.volumeNode.connect(note.chorusEffectsSend);
1351
+ }
1352
+ note.chorusEffectsSend.connect(this.chorusEffect.input);
1353
+ }
1354
+ }
1355
+ }
1356
+ setReverbEffectsSend(note, prevValue) {
1357
+ if (0 < prevValue) {
1358
+ if (0 < note.voiceParams.reverbEffectsSend) {
1359
+ const now = this.audioContext.currentTime;
1360
+ const value = note.voiceParams.reverbEffectsSend;
1361
+ note.reverbEffectsSend.gain
1362
+ .cancelScheduledValues(now)
1363
+ .setValueAtTime(value, now);
1364
+ }
1365
+ else {
1366
+ note.reverbEffectsSend.disconnect();
1367
+ }
1368
+ }
1369
+ else {
1370
+ if (0 < note.voiceParams.reverbEffectsSend) {
1371
+ if (!note.reverbEffectsSend) {
1372
+ note.reverbEffectsSend = new GainNode(this.audioContext, {
1373
+ gain: note.voiceParams.reverbEffectsSend,
1374
+ });
1375
+ note.volumeNode.connect(note.reverbEffectsSend);
1376
+ }
1377
+ note.reverbEffectsSend.connect(this.reverbEffect.input);
1378
+ }
1379
+ }
1380
+ }
1381
+ setVibLfoToPitch(channel, note) {
1382
+ const now = this.audioContext.currentTime;
1383
+ const vibLfoToPitch = note.voiceParams.vibLfoToPitch;
1384
+ const vibratoDepth = Math.abs(vibLfoToPitch) * channel.state.vibratoDepth *
1385
+ 2;
1386
+ const vibratoDepthSign = 0 < vibLfoToPitch;
1387
+ note.vibratoDepth.gain
1388
+ .cancelScheduledValues(now)
1389
+ .setValueAtTime(vibratoDepth * vibratoDepthSign, now);
1390
+ }
1391
+ setModLfoToFilterFc(note) {
1392
+ const now = this.audioContext.currentTime;
1393
+ const modLfoToFilterFc = note.voiceParams.modLfoToFilterFc;
1394
+ note.filterDepth.gain
1395
+ .cancelScheduledValues(now)
1396
+ .setValueAtTime(modLfoToFilterFc, now);
1397
+ }
1398
+ setDelayModLFO(note) {
1399
+ const now = this.audioContext.currentTime;
1400
+ const startTime = note.startTime;
1401
+ if (startTime < now)
1402
+ return;
1403
+ note.modulationLFO.stop(now);
1404
+ note.modulationLFO.start(startTime + note.voiceParams.delayModLFO);
1405
+ note.modulationLFO.connect(note.filterDepth);
1406
+ }
1407
+ setFreqModLFO(note) {
1408
+ const now = this.audioContext.currentTime;
1409
+ const freqModLFO = note.voiceParams.freqModLFO;
1410
+ note.modulationLFO.frequency
1411
+ .cancelScheduledValues(now)
1412
+ .setValueAtTime(freqModLFO, now);
1413
+ }
1414
+ createVoiceParamsHandlers() {
1415
+ return {
1416
+ modLfoToPitch: (channel, note, _prevValue) => {
1417
+ if (0 < channel.state.modulationDepth) {
1418
+ this.setModLfoToPitch(channel, note);
1419
+ }
1420
+ },
1421
+ vibLfoToPitch: (channel, note, _prevValue) => {
1422
+ if (0 < channel.state.vibratoDepth) {
1423
+ this.setVibLfoToPitch(channel, note);
1424
+ }
1425
+ },
1426
+ modLfoToFilterFc: (channel, note, _prevValue) => {
1427
+ if (0 < channel.state.modulationDepth)
1428
+ this.setModLfoToFilterFc(note);
1429
+ },
1430
+ modLfoToVolume: (channel, note) => {
1431
+ if (0 < channel.state.modulationDepth)
1432
+ this.setModLfoToVolume(note);
1433
+ },
1434
+ chorusEffectsSend: (_channel, note, prevValue) => {
1435
+ this.setChorusEffectsSend(note, prevValue);
1436
+ },
1437
+ reverbEffectsSend: (_channel, note, prevValue) => {
1438
+ this.setReverbEffectsSend(note, prevValue);
1439
+ },
1440
+ delayModLFO: (_channel, note, _prevValue) => this.setDelayModLFO(note),
1441
+ freqModLFO: (_channel, note, _prevValue) => this.setFreqModLFO(note),
1442
+ delayVibLFO: (channel, note, prevValue) => {
1443
+ if (0 < channel.state.vibratoDepth) {
1444
+ const now = this.audioContext.currentTime;
1445
+ const prevStartTime = note.startTime +
1446
+ prevValue * channel.state.vibratoDelay * 2;
1447
+ if (now < prevStartTime)
1448
+ return;
1449
+ const startTime = note.startTime +
1450
+ value * channel.state.vibratoDelay * 2;
1451
+ note.vibratoLFO.stop(now);
1452
+ note.vibratoLFO.start(startTime);
1453
+ }
1454
+ },
1455
+ freqVibLFO: (channel, note, _prevValue) => {
1456
+ if (0 < channel.state.vibratoDepth) {
1457
+ const now = this.audioContext.currentTime;
1458
+ note.vibratoLFO.frequency
1459
+ .cancelScheduledValues(now)
1460
+ .setValueAtTime(value * sate.vibratoRate, now);
1461
+ }
1462
+ },
1463
+ };
1464
+ }
1465
+ getControllerState(channel, noteNumber, velocity) {
1466
+ const state = new Float32Array(channel.state.array.length);
1467
+ state.set(channel.state.array);
1468
+ state[2] = velocity / 127;
1469
+ state[3] = noteNumber / 127;
1470
+ return state;
1471
+ }
1472
+ applyVoiceParams(channel, controllerType) {
1473
+ channel.scheduledNotes.forEach((noteList) => {
1474
+ for (let i = 0; i < noteList.length; i++) {
1475
+ const note = noteList[i];
1476
+ if (!note)
1477
+ continue;
1478
+ const controllerState = this.getControllerState(channel, note.noteNumber, note.velocity);
1479
+ const voiceParams = note.voice.getParams(controllerType, controllerState);
1480
+ let appliedFilterEnvelope = false;
1481
+ let appliedVolumeEnvelope = false;
1482
+ for (const [key, value] of Object.entries(voiceParams)) {
1483
+ const prevValue = note.voiceParams[key];
1484
+ if (value === prevValue)
1485
+ continue;
1486
+ note.voiceParams[key] = value;
1487
+ if (key in this.voiceParamsHandlers) {
1488
+ this.voiceParamsHandlers[key](channel, note, prevValue);
1489
+ }
1490
+ else if (filterEnvelopeKeySet.has(key)) {
1491
+ if (appliedFilterEnvelope)
1492
+ continue;
1493
+ appliedFilterEnvelope = true;
1494
+ const noteVoiceParams = note.voiceParams;
1495
+ for (let i = 0; i < filterEnvelopeKeys.length; i++) {
1496
+ const key = filterEnvelopeKeys[i];
1497
+ if (key in voiceParams)
1498
+ noteVoiceParams[key] = voiceParams[key];
1499
+ }
1500
+ if (note.portamento) {
1501
+ this.setPortamentoStartFilterEnvelope(channel, note);
1502
+ }
1503
+ else {
1504
+ this.setFilterEnvelope(channel, note);
1505
+ }
1506
+ this.setPitch(channel, note);
1507
+ }
1508
+ else if (volumeEnvelopeKeySet.has(key)) {
1509
+ if (appliedVolumeEnvelope)
1510
+ continue;
1511
+ appliedVolumeEnvelope = true;
1512
+ const noteVoiceParams = note.voiceParams;
1513
+ for (let i = 0; i < volumeEnvelopeKeys.length; i++) {
1514
+ const key = volumeEnvelopeKeys[i];
1515
+ if (key in voiceParams)
1516
+ noteVoiceParams[key] = voiceParams[key];
1517
+ }
1518
+ this.setVolumeEnvelope(channel, note);
1519
+ }
1520
+ }
1521
+ }
1522
+ });
1157
1523
  }
1158
1524
  createControlChangeHandlers() {
1159
1525
  return {
@@ -1183,13 +1549,16 @@ class MidyGM2 {
1183
1549
  127: this.polyOn,
1184
1550
  };
1185
1551
  }
1186
- handleControlChange(channelNumber, controller, value) {
1187
- const handler = this.controlChangeHandlers[controller];
1552
+ handleControlChange(channelNumber, controllerType, value) {
1553
+ const handler = this.controlChangeHandlers[controllerType];
1188
1554
  if (handler) {
1189
1555
  handler.call(this, channelNumber, value);
1556
+ const channel = this.channels[channelNumber];
1557
+ const controller = 128 + controllerType;
1558
+ this.applyVoiceParams(channel, controller);
1190
1559
  }
1191
1560
  else {
1192
- console.warn(`Unsupported Control change: controller=${controller} value=${value}`);
1561
+ console.warn(`Unsupported Control change: controllerType=${controllerType} value=${value}`);
1193
1562
  }
1194
1563
  }
1195
1564
  setBankMSB(channelNumber, msb) {
@@ -1203,11 +1572,10 @@ class MidyGM2 {
1203
1572
  if (!note)
1204
1573
  continue;
1205
1574
  if (note.modulationDepth) {
1206
- note.modulationDepth.gain.setValueAtTime(channel.modulationDepth, now);
1575
+ note.modulationDepth.gain.setValueAtTime(channel.state.modulationDepth, now);
1207
1576
  }
1208
1577
  else {
1209
- const semitoneOffset = this.calcSemitoneOffset(channel);
1210
- this.setPitch(note, semitoneOffset);
1578
+ this.setPitch(channel, note);
1211
1579
  this.startModulation(channel, note, now);
1212
1580
  }
1213
1581
  }
@@ -1215,21 +1583,22 @@ class MidyGM2 {
1215
1583
  }
1216
1584
  setModulationDepth(channelNumber, modulation) {
1217
1585
  const channel = this.channels[channelNumber];
1218
- channel.modulationDepth = (modulation / 127) * channel.modulationDepthRange;
1586
+ channel.state.modulationDepth = (modulation / 127) *
1587
+ channel.modulationDepthRange;
1219
1588
  this.updateModulation(channel);
1220
1589
  }
1221
1590
  setPortamentoTime(channelNumber, portamentoTime) {
1222
1591
  const channel = this.channels[channelNumber];
1223
1592
  const factor = 5 * Math.log(10) / 127;
1224
- channel.portamentoTime = Math.exp(factor * portamentoTime);
1593
+ channel.state.portamentoTime = Math.exp(factor * portamentoTime);
1225
1594
  }
1226
1595
  setVolume(channelNumber, volume) {
1227
1596
  const channel = this.channels[channelNumber];
1228
- channel.volume = volume / 127;
1597
+ channel.state.volume = volume / 127;
1229
1598
  this.updateChannelVolume(channel);
1230
1599
  }
1231
1600
  panToGain(pan) {
1232
- const theta = Math.PI / 2 * Math.max(0, pan - 1) / 126;
1601
+ const theta = Math.PI / 2 * Math.max(0, pan * 127 - 1) / 126;
1233
1602
  return {
1234
1603
  gainLeft: Math.cos(theta),
1235
1604
  gainRight: Math.sin(theta),
@@ -1237,12 +1606,12 @@ class MidyGM2 {
1237
1606
  }
1238
1607
  setPan(channelNumber, pan) {
1239
1608
  const channel = this.channels[channelNumber];
1240
- channel.pan = pan;
1609
+ channel.state.pan = pan / 127;
1241
1610
  this.updateChannelVolume(channel);
1242
1611
  }
1243
1612
  setExpression(channelNumber, expression) {
1244
1613
  const channel = this.channels[channelNumber];
1245
- channel.expression = expression / 127;
1614
+ channel.state.expression = expression / 127;
1246
1615
  this.updateChannelVolume(channel);
1247
1616
  }
1248
1617
  setBankLSB(channelNumber, lsb) {
@@ -1254,8 +1623,9 @@ class MidyGM2 {
1254
1623
  }
1255
1624
  updateChannelVolume(channel) {
1256
1625
  const now = this.audioContext.currentTime;
1257
- const volume = channel.volume * channel.expression;
1258
- const { gainLeft, gainRight } = this.panToGain(channel.pan);
1626
+ const state = channel.state;
1627
+ const volume = state.volume * state.expression;
1628
+ const { gainLeft, gainRight } = this.panToGain(state.pan);
1259
1629
  channel.gainL.gain
1260
1630
  .cancelScheduledValues(now)
1261
1631
  .setValueAtTime(volume * gainLeft, now);
@@ -1264,68 +1634,100 @@ class MidyGM2 {
1264
1634
  .setValueAtTime(volume * gainRight, now);
1265
1635
  }
1266
1636
  setSustainPedal(channelNumber, value) {
1267
- const isOn = value >= 64;
1268
- this.channels[channelNumber].sustainPedal = isOn;
1269
- if (!isOn) {
1637
+ this.channels[channelNumber].state.sustainPedal = value / 127;
1638
+ if (value < 64) {
1270
1639
  this.releaseSustainPedal(channelNumber, value);
1271
1640
  }
1272
1641
  }
1273
1642
  setPortamento(channelNumber, value) {
1274
- this.channels[channelNumber].portamento = value >= 64;
1643
+ this.channels[channelNumber].state.portamento = value / 127;
1275
1644
  }
1276
1645
  setReverbSendLevel(channelNumber, reverbSendLevel) {
1277
1646
  const channel = this.channels[channelNumber];
1647
+ const state = channel.state;
1278
1648
  const reverbEffect = this.reverbEffect;
1279
- if (0 < channel.reverbSendLevel) {
1649
+ if (0 < state.reverbSendLevel) {
1280
1650
  if (0 < reverbSendLevel) {
1281
1651
  const now = this.audioContext.currentTime;
1282
- channel.reverbSendLevel = reverbSendLevel / 127;
1283
- reverbEffect.output.gain.cancelScheduledValues(now);
1284
- reverbEffect.output.gain.setValueAtTime(channel.reverbSendLevel, now);
1652
+ state.reverbSendLevel = reverbSendLevel / 127;
1653
+ reverbEffect.input.gain.cancelScheduledValues(now);
1654
+ reverbEffect.input.gain.setValueAtTime(state.reverbSendLevel, now);
1285
1655
  }
1286
1656
  else {
1287
- channel.merger.disconnect(reverbEffect.input);
1657
+ channel.scheduledNotes.forEach((noteList) => {
1658
+ for (let i = 0; i < noteList.length; i++) {
1659
+ const note = noteList[i];
1660
+ if (!note)
1661
+ continue;
1662
+ if (note.voiceParams.reverbEffectsSend <= 0)
1663
+ continue;
1664
+ note.reverbEffectsSend.disconnect();
1665
+ }
1666
+ });
1288
1667
  }
1289
1668
  }
1290
1669
  else {
1291
1670
  if (0 < reverbSendLevel) {
1292
- channel.merger.connect(reverbEffect.input);
1293
1671
  const now = this.audioContext.currentTime;
1294
- channel.reverbSendLevel = reverbSendLevel / 127;
1295
- reverbEffect.output.gain.cancelScheduledValues(now);
1296
- reverbEffect.output.gain.setValueAtTime(channel.reverbSendLevel, now);
1672
+ channel.scheduledNotes.forEach((noteList) => {
1673
+ for (let i = 0; i < noteList.length; i++) {
1674
+ const note = noteList[i];
1675
+ if (!note)
1676
+ continue;
1677
+ this.setReverbEffectsSend(note, 0);
1678
+ }
1679
+ });
1680
+ state.reverbSendLevel = reverbSendLevel / 127;
1681
+ reverbEffect.input.gain.cancelScheduledValues(now);
1682
+ reverbEffect.input.gain.setValueAtTime(state.reverbSendLevel, now);
1297
1683
  }
1298
1684
  }
1299
1685
  }
1300
1686
  setChorusSendLevel(channelNumber, chorusSendLevel) {
1301
1687
  const channel = this.channels[channelNumber];
1688
+ const state = channel.state;
1302
1689
  const chorusEffect = this.chorusEffect;
1303
- if (0 < channel.chorusSendLevel) {
1690
+ if (0 < state.chorusSendLevel) {
1304
1691
  if (0 < chorusSendLevel) {
1305
1692
  const now = this.audioContext.currentTime;
1306
- channel.chorusSendLevel = chorusSendLevel / 127;
1307
- chorusEffect.output.gain.cancelScheduledValues(now);
1308
- chorusEffect.output.gain.setValueAtTime(channel.chorusSendLevel, now);
1693
+ state.chorusSendLevel = chorusSendLevel / 127;
1694
+ chorusEffect.input.gain.cancelScheduledValues(now);
1695
+ chorusEffect.input.gain.setValueAtTime(state.chorusSendLevel, now);
1309
1696
  }
1310
1697
  else {
1311
- channel.merger.disconnect(chorusEffect.input);
1698
+ channel.scheduledNotes.forEach((noteList) => {
1699
+ for (let i = 0; i < noteList.length; i++) {
1700
+ const note = noteList[i];
1701
+ if (!note)
1702
+ continue;
1703
+ if (note.voiceParams.chorusEffectsSend <= 0)
1704
+ continue;
1705
+ note.chorusEffectsSend.disconnect();
1706
+ }
1707
+ });
1312
1708
  }
1313
1709
  }
1314
1710
  else {
1315
1711
  if (0 < chorusSendLevel) {
1316
- channel.merger.connect(chorusEffect.input);
1317
1712
  const now = this.audioContext.currentTime;
1318
- channel.chorusSendLevel = chorusSendLevel / 127;
1319
- chorusEffect.output.gain.cancelScheduledValues(now);
1320
- chorusEffect.output.gain.setValueAtTime(channel.chorusSendLevel, now);
1713
+ channel.scheduledNotes.forEach((noteList) => {
1714
+ for (let i = 0; i < noteList.length; i++) {
1715
+ const note = noteList[i];
1716
+ if (!note)
1717
+ continue;
1718
+ this.setChorusEffectsSend(note, 0);
1719
+ }
1720
+ });
1721
+ state.chorusSendLevel = chorusSendLevel / 127;
1722
+ chorusEffect.input.gain.cancelScheduledValues(now);
1723
+ chorusEffect.input.gain.setValueAtTime(state.chorusSendLevel, now);
1321
1724
  }
1322
1725
  }
1323
1726
  }
1324
1727
  setSostenutoPedal(channelNumber, value) {
1325
- const isOn = value >= 64;
1326
1728
  const channel = this.channels[channelNumber];
1327
- channel.sostenutoPedal = isOn;
1328
- if (isOn) {
1729
+ channel.state.sostenutoPedal = value / 127;
1730
+ if (64 <= value) {
1329
1731
  const now = this.audioContext.currentTime;
1330
1732
  const activeNotes = this.getActiveNotes(channel, now);
1331
1733
  channel.sostenutoNotes = new Map(activeNotes);
@@ -1336,7 +1738,7 @@ class MidyGM2 {
1336
1738
  }
1337
1739
  setSoftPedal(channelNumber, softPedal) {
1338
1740
  const channel = this.channels[channelNumber];
1339
- channel.softPedal = softPedal / 127;
1741
+ channel.state.softPedal = softPedal / 127;
1340
1742
  }
1341
1743
  limitData(channel, minMSB, maxMSB, minLSB, maxLSB) {
1342
1744
  if (maxLSB < channel.dataLSB) {
@@ -1394,7 +1796,7 @@ class MidyGM2 {
1394
1796
  this.channels[channelNumber].dataMSB = value;
1395
1797
  this.handleRPN(channelNumber);
1396
1798
  }
1397
- updateDetune(channel, detuneChange) {
1799
+ updateDetune(channel, detune) {
1398
1800
  const now = this.audioContext.currentTime;
1399
1801
  channel.scheduledNotes.forEach((noteList) => {
1400
1802
  for (let i = 0; i < noteList.length; i++) {
@@ -1402,7 +1804,6 @@ class MidyGM2 {
1402
1804
  if (!note)
1403
1805
  continue;
1404
1806
  const { bufferSource } = note;
1405
- const detune = bufferSource.detune.value + detuneChange;
1406
1807
  bufferSource.detune
1407
1808
  .cancelScheduledValues(now)
1408
1809
  .setValueAtTime(detune, now);
@@ -1415,13 +1816,13 @@ class MidyGM2 {
1415
1816
  const pitchBendRange = channel.dataMSB + channel.dataLSB / 100;
1416
1817
  this.setPitchBendRange(channelNumber, pitchBendRange);
1417
1818
  }
1418
- setPitchBendRange(channelNumber, pitchBendRange) {
1819
+ setPitchBendRange(channelNumber, pitchWheelSensitivity) {
1419
1820
  const channel = this.channels[channelNumber];
1420
- const prevPitchBendRange = channel.pitchBendRange;
1421
- channel.pitchBendRange = pitchBendRange;
1422
- const detuneChange = (channel.pitchBendRange - prevPitchBendRange) *
1423
- channel.pitchBend * 100;
1424
- this.updateDetune(channel, detuneChange);
1821
+ const state = channel.state;
1822
+ state.pitchWheelSensitivity = pitchWheelSensitivity / 128;
1823
+ const detune = (state.pitchWheel * 2 - 1) * pitchWheelSensitivity * 100;
1824
+ this.updateDetune(channel, detune);
1825
+ this.applyVoiceParams(channel, 16);
1425
1826
  }
1426
1827
  handleFineTuningRPN(channelNumber) {
1427
1828
  const channel = this.channels[channelNumber];
@@ -1465,7 +1866,30 @@ class MidyGM2 {
1465
1866
  return this.stopChannelNotes(channelNumber, 0, true);
1466
1867
  }
1467
1868
  resetAllControllers(channelNumber) {
1468
- Object.assign(this.channels[channelNumber], this.effectSettings);
1869
+ const stateTypes = [
1870
+ "expression",
1871
+ "modulationDepth",
1872
+ "sustainPedal",
1873
+ "portamento",
1874
+ "sostenutoPedal",
1875
+ "softPedal",
1876
+ "channelPressure",
1877
+ "pitchWheelSensitivity",
1878
+ ];
1879
+ const channel = this.channels[channelNumber];
1880
+ const state = channel.state;
1881
+ for (let i = 0; i < stateTypes.length; i++) {
1882
+ const type = stateTypes[i];
1883
+ state[type] = defaultControllerState[type];
1884
+ }
1885
+ const settingTypes = [
1886
+ "rpnMSB",
1887
+ "rpnLSB",
1888
+ ];
1889
+ for (let i = 0; i < settingTypes.length; i++) {
1890
+ const type = settingTypes[i];
1891
+ channel[type] = this.constructor.channelSettings[type];
1892
+ }
1469
1893
  }
1470
1894
  allNotesOff(channelNumber) {
1471
1895
  return this.stopChannelNotes(channelNumber, 0, false);
@@ -1659,10 +2083,8 @@ class MidyGM2 {
1659
2083
  }
1660
2084
  setReverbTime(value) {
1661
2085
  this.reverb.time = this.getReverbTime(value);
1662
- const { audioContext, channels, options } = this;
1663
- for (let i = 0; i < channels.length; i++) {
1664
- channels[i].reverbEffect = options.reverbAlgorithm(audioContext);
1665
- }
2086
+ const { audioContext, options } = this;
2087
+ this.reverbEffect = options.reverbAlgorithm(audioContext);
1666
2088
  }
1667
2089
  getReverbTime(value) {
1668
2090
  return Math.pow(Math.E, (value - 40) * 0.025);
@@ -1739,10 +2161,7 @@ class MidyGM2 {
1739
2161
  const now = this.audioContext.currentTime;
1740
2162
  const modRate = this.getChorusModRate(value);
1741
2163
  this.chorus.modRate = modRate;
1742
- for (let i = 0; i < this.channels.length; i++) {
1743
- const lfo = this.channels[i].chorusEffect.lfo;
1744
- lfo.frequency.setValueAtTime(modRate, now);
1745
- }
2164
+ this.chorusEffect.lfo.frequency.setValueAtTime(modRate, now);
1746
2165
  }
1747
2166
  getChorusModRate(value) {
1748
2167
  return value * 0.122; // Hz
@@ -1751,12 +2170,9 @@ class MidyGM2 {
1751
2170
  const now = this.audioContext.currentTime;
1752
2171
  const modDepth = this.getChorusModDepth(value);
1753
2172
  this.chorus.modDepth = modDepth;
1754
- for (let i = 0; i < this.channels.length; i++) {
1755
- const chorusEffect = this.channels[i].chorusEffect;
1756
- chorusEffect.lfoGain.gain
1757
- .cancelScheduledValues(now)
1758
- .setValueAtTime(modDepth / 2, now);
1759
- }
2173
+ this.chorusEffect.lfoGain.gain
2174
+ .cancelScheduledValues(now)
2175
+ .setValueAtTime(modDepth / 2, now);
1760
2176
  }
1761
2177
  getChorusModDepth(value) {
1762
2178
  return (value + 1) / 3200; // second
@@ -1765,14 +2181,11 @@ class MidyGM2 {
1765
2181
  const now = this.audioContext.currentTime;
1766
2182
  const feedback = this.getChorusFeedback(value);
1767
2183
  this.chorus.feedback = feedback;
1768
- for (let i = 0; i < this.channels.length; i++) {
1769
- const chorusEffect = this.channels[i].chorusEffect;
1770
- for (let j = 0; j < chorusEffect.feedbackGains.length; j++) {
1771
- const feedbackGain = chorusEffect.feedbackGains[j];
1772
- feedbackGain.gain
1773
- .cancelScheduledValues(now)
1774
- .setValueAtTime(feedback, now);
1775
- }
2184
+ const chorusEffect = this.chorusEffect;
2185
+ for (let i = 0; i < chorusEffect.feedbackGains.length; i++) {
2186
+ chorusEffect.feedbackGains[i].gain
2187
+ .cancelScheduledValues(now)
2188
+ .setValueAtTime(feedback, now);
1776
2189
  }
1777
2190
  }
1778
2191
  getChorusFeedback(value) {
@@ -1780,15 +2193,28 @@ class MidyGM2 {
1780
2193
  }
1781
2194
  setChorusSendToReverb(value) {
1782
2195
  const sendToReverb = this.getChorusSendToReverb(value);
1783
- if (0 < sendToReverb) {
1784
- const now = this.audioContext.currentTime;
2196
+ const sendGain = this.chorusEffect.sendGain;
2197
+ if (0 < this.chorus.sendToReverb) {
1785
2198
  this.chorus.sendToReverb = sendToReverb;
1786
- this.chorusEffect.sendGain.gain
1787
- .cancelScheduledValues(now)
1788
- .setValueAtTime(sendToReverb, now);
2199
+ if (0 < sendToReverb) {
2200
+ const now = this.audioContext.currentTime;
2201
+ sendGain.gain
2202
+ .cancelScheduledValues(now)
2203
+ .setValueAtTime(sendToReverb, now);
2204
+ }
2205
+ else {
2206
+ sendGain.disconnect();
2207
+ }
1789
2208
  }
1790
- else if (this.chorus.sendToReverb !== 0) {
1791
- this.chorusEffect.sendGain.disconnect(this.reverbEffect.input);
2209
+ else {
2210
+ this.chorus.sendToReverb = sendToReverb;
2211
+ if (0 < sendToReverb) {
2212
+ const now = this.audioContext.currentTime;
2213
+ sendGain.connect(this.reverbEffect.input);
2214
+ sendGain.gain
2215
+ .cancelScheduledValues(now)
2216
+ .setValueAtTime(sendToReverb, now);
2217
+ }
1792
2218
  }
1793
2219
  }
1794
2220
  getChorusSendToReverb(value) {
@@ -1826,43 +2252,19 @@ Object.defineProperty(MidyGM2, "channelSettings", {
1826
2252
  writable: true,
1827
2253
  value: {
1828
2254
  currentBufferSource: null,
1829
- volume: 100 / 127,
1830
- pan: 64,
1831
- portamentoTime: 1, // sec
1832
- reverbSendLevel: 0,
1833
- chorusSendLevel: 0,
1834
- vibratoRate: 1,
1835
- vibratoDepth: 1,
1836
- vibratoDelay: 1,
2255
+ program: 0,
1837
2256
  bank: 121 * 128,
1838
2257
  bankMSB: 121,
1839
2258
  bankLSB: 0,
1840
2259
  dataMSB: 0,
1841
2260
  dataLSB: 0,
1842
- program: 0,
1843
- pitchBend: 0,
2261
+ rpnMSB: 127,
2262
+ rpnLSB: 127,
1844
2263
  fineTuning: 0, // cb
1845
2264
  coarseTuning: 0, // cb
1846
2265
  modulationDepthRange: 50, // cent
1847
2266
  }
1848
2267
  });
1849
- Object.defineProperty(MidyGM2, "effectSettings", {
1850
- enumerable: true,
1851
- configurable: true,
1852
- writable: true,
1853
- value: {
1854
- expression: 1,
1855
- modulationDepth: 0,
1856
- sustainPedal: false,
1857
- portamento: false,
1858
- sostenutoPedal: false,
1859
- softPedal: 0,
1860
- rpnMSB: 127,
1861
- rpnLSB: 127,
1862
- channelPressure: 0,
1863
- pitchBendRange: 2,
1864
- }
1865
- });
1866
2268
  Object.defineProperty(MidyGM2, "controllerDestinationSettings", {
1867
2269
  enumerable: true,
1868
2270
  configurable: true,