@marmooo/midy 0.3.1 → 0.3.2

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.
@@ -3,60 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MidyGM1 = void 0;
4
4
  const midi_file_1 = require("midi-file");
5
5
  const soundfont_parser_1 = require("@marmooo/soundfont-parser");
6
- // 2-3 times faster than Map
7
- class SparseMap {
8
- constructor(size) {
9
- this.data = new Array(size);
10
- this.activeIndices = [];
11
- }
12
- set(key, value) {
13
- if (this.data[key] === undefined) {
14
- this.activeIndices.push(key);
15
- }
16
- this.data[key] = value;
17
- }
18
- get(key) {
19
- return this.data[key];
20
- }
21
- delete(key) {
22
- if (this.data[key] !== undefined) {
23
- this.data[key] = undefined;
24
- const index = this.activeIndices.indexOf(key);
25
- if (index !== -1) {
26
- this.activeIndices.splice(index, 1);
27
- }
28
- return true;
29
- }
30
- return false;
31
- }
32
- has(key) {
33
- return this.data[key] !== undefined;
34
- }
35
- get size() {
36
- return this.activeIndices.length;
37
- }
38
- clear() {
39
- for (let i = 0; i < this.activeIndices.length; i++) {
40
- const key = this.activeIndices[i];
41
- this.data[key] = undefined;
42
- }
43
- this.activeIndices = [];
44
- }
45
- *[Symbol.iterator]() {
46
- for (let i = 0; i < this.activeIndices.length; i++) {
47
- const key = this.activeIndices[i];
48
- yield [key, this.data[key]];
49
- }
50
- }
51
- forEach(callback) {
52
- for (let i = 0; i < this.activeIndices.length; i++) {
53
- const key = this.activeIndices[i];
54
- callback(this.data[key], key, this);
55
- }
56
- }
57
- }
58
6
  class Note {
59
7
  constructor(noteNumber, velocity, startTime, voice, voiceParams) {
8
+ Object.defineProperty(this, "index", {
9
+ enumerable: true,
10
+ configurable: true,
11
+ writable: true,
12
+ value: -1
13
+ });
60
14
  Object.defineProperty(this, "bufferSource", {
61
15
  enumerable: true,
62
16
  configurable: true,
@@ -117,7 +71,7 @@ const defaultControllerState = {
117
71
  modulationDepth: { type: 128 + 1, defaultValue: 0 },
118
72
  // dataMSB: { type: 128 + 6, defaultValue: 0, },
119
73
  volume: { type: 128 + 7, defaultValue: 100 / 127 },
120
- pan: { type: 128 + 10, defaultValue: 0.5 },
74
+ pan: { type: 128 + 10, defaultValue: 64 / 127 },
121
75
  expression: { type: 128 + 11, defaultValue: 1 },
122
76
  // bankLSB: { type: 128 + 32, defaultValue: 0, },
123
77
  // dataLSB: { type: 128 + 38, defaultValue: 0, },
@@ -322,7 +276,7 @@ class MidyGM1 {
322
276
  initSoundFontTable() {
323
277
  const table = new Array(128);
324
278
  for (let i = 0; i < 128; i++) {
325
- table[i] = new SparseMap(128);
279
+ table[i] = new Map();
326
280
  }
327
281
  return table;
328
282
  }
@@ -374,10 +328,10 @@ class MidyGM1 {
374
328
  return {
375
329
  currentBufferSource: null,
376
330
  isDrum: false,
377
- ...this.constructor.channelSettings,
378
331
  state: new ControllerState(),
332
+ ...this.constructor.channelSettings,
379
333
  ...this.setChannelAudioNodes(audioContext),
380
- scheduledNotes: new SparseMap(128),
334
+ scheduledNotes: [],
381
335
  sustainNotes: [],
382
336
  };
383
337
  });
@@ -412,7 +366,7 @@ class MidyGM1 {
412
366
  return audioBuffer;
413
367
  }
414
368
  }
415
- createBufferSource(audioBuffer, voiceParams) {
369
+ createBufferSource(voiceParams, audioBuffer) {
416
370
  const bufferSource = new AudioBufferSourceNode(this.audioContext);
417
371
  bufferSource.buffer = audioBuffer;
418
372
  bufferSource.loop = voiceParams.sampleModes % 2 !== 0;
@@ -422,24 +376,20 @@ class MidyGM1 {
422
376
  }
423
377
  return bufferSource;
424
378
  }
425
- async scheduleTimelineEvents(t, offset, queueIndex) {
379
+ async scheduleTimelineEvents(t, resumeTime, queueIndex) {
426
380
  while (queueIndex < this.timeline.length) {
427
381
  const event = this.timeline[queueIndex];
428
382
  if (event.startTime > t + this.lookAhead)
429
383
  break;
430
- const startTime = event.startTime + this.startDelay - offset;
384
+ const delay = this.startDelay - resumeTime;
385
+ const startTime = event.startTime + delay;
431
386
  switch (event.type) {
432
- case "noteOn":
433
- if (0 < event.velocity) {
434
- await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime);
435
- break;
436
- }
437
- /* falls through */
438
- case "noteOff": {
439
- const notePromise = this.scheduleNoteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
440
- if (notePromise) {
441
- this.notePromises.push(notePromise);
442
- }
387
+ case "noteOn": {
388
+ const noteOffEvent = {
389
+ ...event.noteOffEvent,
390
+ startTime: event.noteOffEvent.startTime + delay,
391
+ };
392
+ await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime, noteOffEvent);
443
393
  break;
444
394
  }
445
395
  case "controller":
@@ -472,7 +422,7 @@ class MidyGM1 {
472
422
  this.isPaused = false;
473
423
  this.startTime = this.audioContext.currentTime;
474
424
  let queueIndex = this.getQueueIndex(this.resumeTime);
475
- let offset = this.resumeTime - this.startTime;
425
+ let resumeTime = this.resumeTime - this.startTime;
476
426
  this.notePromises = [];
477
427
  const schedulePlayback = async () => {
478
428
  if (queueIndex >= this.timeline.length) {
@@ -480,18 +430,21 @@ class MidyGM1 {
480
430
  this.notePromises = [];
481
431
  this.exclusiveClassNotes.fill(undefined);
482
432
  this.audioBufferCache.clear();
433
+ for (let i = 0; i < this.channels.length; i++) {
434
+ this.resetAllStates(i);
435
+ }
483
436
  resolve();
484
437
  return;
485
438
  }
486
439
  const now = this.audioContext.currentTime;
487
- const t = now + offset;
488
- queueIndex = await this.scheduleTimelineEvents(t, offset, queueIndex);
440
+ const t = now + resumeTime;
441
+ queueIndex = await this.scheduleTimelineEvents(t, resumeTime, queueIndex);
489
442
  if (this.isPausing) {
490
443
  await this.stopNotes(0, true, now);
491
444
  this.notePromises = [];
492
- resolve();
493
445
  this.isPausing = false;
494
446
  this.isPaused = true;
447
+ resolve();
495
448
  return;
496
449
  }
497
450
  else if (this.isStopping) {
@@ -499,9 +452,12 @@ class MidyGM1 {
499
452
  this.notePromises = [];
500
453
  this.exclusiveClassNotes.fill(undefined);
501
454
  this.audioBufferCache.clear();
502
- resolve();
455
+ for (let i = 0; i < this.channels.length; i++) {
456
+ this.resetAllStates(i);
457
+ }
503
458
  this.isStopping = false;
504
459
  this.isPaused = false;
460
+ resolve();
505
461
  return;
506
462
  }
507
463
  else if (this.isSeeking) {
@@ -509,7 +465,7 @@ class MidyGM1 {
509
465
  this.exclusiveClassNotes.fill(undefined);
510
466
  this.startTime = this.audioContext.currentTime;
511
467
  queueIndex = this.getQueueIndex(this.resumeTime);
512
- offset = this.resumeTime - this.startTime;
468
+ resumeTime = this.resumeTime - this.startTime;
513
469
  this.isSeeking = false;
514
470
  await schedulePlayback();
515
471
  }
@@ -595,13 +551,37 @@ class MidyGM1 {
595
551
  prevTempoTicks = event.ticks;
596
552
  }
597
553
  }
554
+ const activeNotes = new Array(this.channels.length * 128);
555
+ for (let i = 0; i < activeNotes.length; i++) {
556
+ activeNotes[i] = [];
557
+ }
558
+ for (let i = 0; i < timeline.length; i++) {
559
+ const event = timeline[i];
560
+ switch (event.type) {
561
+ case "noteOn": {
562
+ const index = event.channel * 128 + event.noteNumber;
563
+ activeNotes[index].push(event);
564
+ break;
565
+ }
566
+ case "noteOff": {
567
+ const index = event.channel * 128 + event.noteNumber;
568
+ const noteOn = activeNotes[index].pop();
569
+ if (noteOn) {
570
+ noteOn.noteOffEvent = event;
571
+ }
572
+ else {
573
+ const eventString = JSON.stringify(event, null, 2);
574
+ console.warn(`noteOff without matching noteOn: ${eventString}`);
575
+ }
576
+ }
577
+ }
578
+ }
598
579
  return { instruments, timeline };
599
580
  }
600
581
  stopActiveNotes(channelNumber, velocity, force, scheduleTime) {
601
582
  const channel = this.channels[channelNumber];
602
583
  const promises = [];
603
- const activeNotes = this.getActiveNotes(channel, scheduleTime);
604
- activeNotes.forEach((note) => {
584
+ this.processActiveNotes(channel, scheduleTime, (note) => {
605
585
  const promise = this.scheduleNoteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force, undefined);
606
586
  this.notePromises.push(promise);
607
587
  promises.push(promise);
@@ -612,11 +592,11 @@ class MidyGM1 {
612
592
  const channel = this.channels[channelNumber];
613
593
  const promises = [];
614
594
  this.processScheduledNotes(channel, (note) => {
615
- const promise = this.scheduleNoteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
595
+ const promise = this.scheduleNoteOff(channelNumber, note, velocity, scheduleTime, force);
616
596
  this.notePromises.push(promise);
617
597
  promises.push(promise);
618
598
  });
619
- channel.scheduledNotes.clear();
599
+ channel.scheduledNotes = [];
620
600
  return Promise.all(promises);
621
601
  }
622
602
  stopNotes(velocity, force, scheduleTime) {
@@ -637,9 +617,6 @@ class MidyGM1 {
637
617
  if (!this.isPlaying)
638
618
  return;
639
619
  this.isStopping = true;
640
- for (let i = 0; i < this.channels.length; i++) {
641
- this.resetAllStates(i);
642
- }
643
620
  }
644
621
  pause() {
645
622
  if (!this.isPlaying || this.isPaused)
@@ -674,37 +651,31 @@ class MidyGM1 {
674
651
  return this.resumeTime + now - this.startTime - this.startDelay;
675
652
  }
676
653
  processScheduledNotes(channel, callback) {
677
- channel.scheduledNotes.forEach((noteList) => {
678
- for (let i = 0; i < noteList.length; i++) {
679
- const note = noteList[i];
680
- if (!note)
681
- continue;
682
- if (note.ending)
683
- continue;
684
- callback(note);
685
- }
686
- });
687
- }
688
- getActiveNotes(channel, scheduleTime) {
689
- const activeNotes = new SparseMap(128);
690
- channel.scheduledNotes.forEach((noteList) => {
691
- const activeNote = this.getActiveNote(noteList, scheduleTime);
692
- if (activeNote) {
693
- activeNotes.set(activeNote.noteNumber, activeNote);
694
- }
695
- });
696
- return activeNotes;
654
+ const scheduledNotes = channel.scheduledNotes;
655
+ for (let i = 0; i < scheduledNotes.length; i++) {
656
+ const note = scheduledNotes[i];
657
+ if (!note)
658
+ continue;
659
+ if (note.ending)
660
+ continue;
661
+ callback(note);
662
+ }
697
663
  }
698
- getActiveNote(noteList, scheduleTime) {
699
- for (let i = noteList.length - 1; i >= 0; i--) {
700
- const note = noteList[i];
664
+ processActiveNotes(channel, scheduleTime, callback) {
665
+ const scheduledNotes = channel.scheduledNotes;
666
+ for (let i = 0; i < scheduledNotes.length; i++) {
667
+ const note = scheduledNotes[i];
701
668
  if (!note)
702
- return;
669
+ continue;
670
+ if (note.ending)
671
+ continue;
672
+ const noteOffEvent = note.noteOffEvent;
673
+ if (noteOffEvent && noteOffEvent.startTime < scheduleTime)
674
+ continue;
703
675
  if (scheduleTime < note.startTime)
704
676
  continue;
705
- return (note.ending) ? null : note;
677
+ callback(note);
706
678
  }
707
- return noteList[0];
708
679
  }
709
680
  cbToRatio(cb) {
710
681
  return Math.pow(10, cb / 200);
@@ -844,7 +815,7 @@ class MidyGM1 {
844
815
  const voiceParams = voice.getAllParams(controllerState);
845
816
  const note = new Note(noteNumber, velocity, startTime, voice, voiceParams);
846
817
  const audioBuffer = await this.getAudioBuffer(channel.programNumber, noteNumber, velocity, voiceParams, isSF3);
847
- note.bufferSource = this.createBufferSource(audioBuffer, voiceParams);
818
+ note.bufferSource = this.createBufferSource(voiceParams, audioBuffer);
848
819
  note.volumeEnvelopeNode = new GainNode(this.audioContext);
849
820
  note.filterNode = new BiquadFilterNode(this.audioContext, {
850
821
  type: "lowpass",
@@ -853,6 +824,7 @@ class MidyGM1 {
853
824
  this.setVolumeEnvelope(note, now);
854
825
  this.setFilterEnvelope(note, now);
855
826
  this.setPitchEnvelope(note, now);
827
+ this.updateDetune(channel, note, now);
856
828
  if (0 < state.modulationDepth) {
857
829
  this.startModulation(channel, note, now);
858
830
  }
@@ -869,13 +841,13 @@ class MidyGM1 {
869
841
  if (prev) {
870
842
  const [prevNote, prevChannelNumber] = prev;
871
843
  if (prevNote && !prevNote.ending) {
872
- this.scheduleNoteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
844
+ this.scheduleNoteOff(prevChannelNumber, prevNote, 0, // velocity,
873
845
  startTime, true);
874
846
  }
875
847
  }
876
848
  this.exclusiveClassNotes[exclusiveClass] = [note, channelNumber];
877
849
  }
878
- async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
850
+ async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime, noteOffEvent) {
879
851
  const channel = this.channels[channelNumber];
880
852
  const bankNumber = channel.bank;
881
853
  const soundFontIndex = this.soundFontTable[channel.programNumber].get(bankNumber);
@@ -887,6 +859,7 @@ class MidyGM1 {
887
859
  return;
888
860
  const isSF3 = soundFont.parsed.info.version.major === 3;
889
861
  const note = await this.createNote(channel, voice, noteNumber, velocity, startTime, isSF3);
862
+ note.noteOffEvent = noteOffEvent;
890
863
  note.volumeEnvelopeNode.connect(channel.gainL);
891
864
  note.volumeEnvelopeNode.connect(channel.gainR);
892
865
  if (0.5 <= channel.state.sustainPedal) {
@@ -894,18 +867,18 @@ class MidyGM1 {
894
867
  }
895
868
  this.handleExclusiveClass(note, channelNumber, startTime);
896
869
  const scheduledNotes = channel.scheduledNotes;
897
- let noteList = scheduledNotes.get(noteNumber);
898
- if (noteList) {
899
- noteList.push(note);
900
- }
901
- else {
902
- noteList = [note];
903
- scheduledNotes.set(noteNumber, noteList);
870
+ note.index = scheduledNotes.length;
871
+ scheduledNotes.push(note);
872
+ if (noteOffEvent) {
873
+ const notePromise = this.scheduleNoteOff(channelNumber, note, noteOffEvent.velocity, noteOffEvent.startTime, false);
874
+ if (notePromise) {
875
+ this.notePromises.push(notePromise);
876
+ }
904
877
  }
905
878
  }
906
879
  noteOn(channelNumber, noteNumber, velocity, scheduleTime) {
907
880
  scheduleTime ??= this.audioContext.currentTime;
908
- return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime);
881
+ return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime, undefined);
909
882
  }
910
883
  disconnectNote(note) {
911
884
  note.bufferSource.disconnect();
@@ -917,8 +890,7 @@ class MidyGM1 {
917
890
  note.modulationLFO.stop();
918
891
  }
919
892
  }
920
- stopNote(endTime, stopTime, noteList, index) {
921
- const note = noteList[index];
893
+ stopNote(channel, note, endTime, stopTime) {
922
894
  note.volumeEnvelopeNode.gain
923
895
  .cancelScheduledValues(endTime)
924
896
  .linearRampToValueAtTime(0, stopTime);
@@ -928,54 +900,50 @@ class MidyGM1 {
928
900
  }, stopTime);
929
901
  return new Promise((resolve) => {
930
902
  note.bufferSource.onended = () => {
931
- noteList[index] = undefined;
903
+ channel.scheduledNotes[note.index] = undefined;
932
904
  this.disconnectNote(note);
933
905
  resolve();
934
906
  };
935
907
  note.bufferSource.stop(stopTime);
936
908
  });
937
909
  }
938
- findNoteOffTarget(noteList) {
939
- for (let i = 0; i < noteList.length; i++) {
940
- const note = noteList[i];
941
- if (!note)
942
- continue;
943
- if (note.ending)
944
- continue;
945
- return [note, i];
946
- }
947
- }
948
- scheduleNoteOff(channelNumber, noteNumber, _velocity, endTime, force) {
910
+ scheduleNoteOff(channelNumber, note, _velocity, endTime, force) {
949
911
  const channel = this.channels[channelNumber];
950
912
  if (!force && 0.5 <= channel.state.sustainPedal)
951
913
  return;
952
- if (!channel.scheduledNotes.has(noteNumber))
953
- return;
954
- const noteList = channel.scheduledNotes.get(noteNumber);
955
- if (!noteList)
956
- return; // be careful with drum channel
957
- const noteOffTarget = this.findNoteOffTarget(noteList, endTime);
958
- if (!noteOffTarget)
959
- return;
960
- const [note, i] = noteOffTarget;
961
914
  const volRelease = endTime + note.voiceParams.volRelease;
962
915
  const modRelease = endTime + note.voiceParams.modRelease;
963
916
  note.filterNode.frequency
964
917
  .cancelScheduledValues(endTime)
965
918
  .linearRampToValueAtTime(0, modRelease);
966
919
  const stopTime = Math.min(volRelease, modRelease);
967
- return this.stopNote(endTime, stopTime, noteList, i);
920
+ return this.stopNote(channel, note, endTime, stopTime);
921
+ }
922
+ findNoteOffTarget(channel, noteNumber) {
923
+ const scheduledNotes = channel.scheduledNotes;
924
+ for (let i = 0; i < scheduledNotes.length; i++) {
925
+ const note = scheduledNotes[i];
926
+ if (!note)
927
+ continue;
928
+ if (note.ending)
929
+ continue;
930
+ if (note.noteNumber !== noteNumber)
931
+ continue;
932
+ return note;
933
+ }
968
934
  }
969
935
  noteOff(channelNumber, noteNumber, velocity, scheduleTime) {
970
936
  scheduleTime ??= this.audioContext.currentTime;
971
- return this.scheduleNoteOff(channelNumber, noteNumber, velocity, scheduleTime, false);
937
+ const channel = this.channels[channelNumber];
938
+ const note = this.findNoteOffTarget(channel, noteNumber);
939
+ return this.scheduleNoteOff(channelNumber, note, velocity, scheduleTime, false);
972
940
  }
973
941
  releaseSustainPedal(channelNumber, halfVelocity, scheduleTime) {
974
942
  const velocity = halfVelocity * 2;
975
943
  const channel = this.channels[channelNumber];
976
944
  const promises = [];
977
945
  for (let i = 0; i < channel.sustainNotes.length; i++) {
978
- const promise = this.noteOff(channelNumber, channel.sustainNotes[i].noteNumber, velocity, scheduleTime);
946
+ const promise = this.scheduleNoteOff(channelNumber, channel.sustainNotes[i], velocity, scheduleTime);
979
947
  promises.push(promise);
980
948
  }
981
949
  channel.sustainNotes = [];
@@ -1131,20 +1099,19 @@ class MidyGM1 {
1131
1099
  });
1132
1100
  }
1133
1101
  createControlChangeHandlers() {
1134
- return {
1135
- 1: this.setModulationDepth,
1136
- 6: this.dataEntryMSB,
1137
- 7: this.setVolume,
1138
- 10: this.setPan,
1139
- 11: this.setExpression,
1140
- 38: this.dataEntryLSB,
1141
- 64: this.setSustainPedal,
1142
- 100: this.setRPNLSB,
1143
- 101: this.setRPNMSB,
1144
- 120: this.allSoundOff,
1145
- 121: this.resetAllControllers,
1146
- 123: this.allNotesOff,
1147
- };
1102
+ const handlers = new Array(128);
1103
+ handlers[1] = this.setModulationDepth;
1104
+ handlers[6] = this.dataEntryMSB;
1105
+ handlers[7] = this.setVolume;
1106
+ handlers[10] = this.setPan;
1107
+ handlers[11] = this.setExpression;
1108
+ handlers[38] = this.dataEntryLSB;
1109
+ handlers[64] = this.setSustainPedal;
1110
+ handlers[100] = this.setRPNLSB;
1111
+ handlers[101] = this.setRPNMSB;
1112
+ handlers[120] = this.allSoundOff;
1113
+ handlers[121] = this.resetAllControllers;
1114
+ return handlers;
1148
1115
  }
1149
1116
  handleControlChange(channelNumber, controllerType, value, scheduleTime) {
1150
1117
  const handler = this.controlChangeHandlers[controllerType];
@@ -1333,19 +1300,26 @@ class MidyGM1 {
1333
1300
  return this.stopActiveNotes(channelNumber, 0, true, scheduleTime);
1334
1301
  }
1335
1302
  resetAllStates(channelNumber) {
1303
+ const scheduleTime = this.audioContext.currentTime;
1336
1304
  const channel = this.channels[channelNumber];
1337
1305
  const state = channel.state;
1338
- for (const type of Object.keys(defaultControllerState)) {
1339
- state[type] = defaultControllerState[type].defaultValue;
1306
+ const entries = Object.entries(defaultControllerState);
1307
+ for (const [key, { type, defaultValue }] of entries) {
1308
+ if (128 <= type) {
1309
+ this.handleControlChange(channelNumber, type - 128, Math.ceil(defaultValue * 127), scheduleTime);
1310
+ }
1311
+ else {
1312
+ state[key] = defaultValue;
1313
+ }
1340
1314
  }
1341
- for (const type of Object.keys(this.constructor.channelSettings)) {
1342
- channel[type] = this.constructor.channelSettings[type];
1315
+ for (const key of Object.keys(this.constructor.channelSettings)) {
1316
+ channel[key] = this.constructor.channelSettings[key];
1343
1317
  }
1344
1318
  this.mode = "GM1";
1345
1319
  }
1346
1320
  // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/rp15.pdf
1347
- resetAllControllers(channelNumber) {
1348
- const stateTypes = [
1321
+ resetAllControllers(channelNumber, _value, scheduleTime) {
1322
+ const keys = [
1349
1323
  "pitchWheel",
1350
1324
  "expression",
1351
1325
  "modulationDepth",
@@ -1353,10 +1327,17 @@ class MidyGM1 {
1353
1327
  ];
1354
1328
  const channel = this.channels[channelNumber];
1355
1329
  const state = channel.state;
1356
- for (let i = 0; i < stateTypes.length; i++) {
1357
- const type = stateTypes[i];
1358
- state[type] = defaultControllerState[type].defaultValue;
1330
+ for (let i = 0; i < keys.length; i++) {
1331
+ const key = keys[i];
1332
+ const { type, defaultValue } = defaultControllerState[key];
1333
+ if (128 <= type) {
1334
+ this.handleControlChange(channelNumber, type - 128, Math.ceil(defaultValue * 127), scheduleTime);
1335
+ }
1336
+ else {
1337
+ state[key] = defaultValue;
1338
+ }
1359
1339
  }
1340
+ this.setPitchBend(channelNumber, 8192, scheduleTime);
1360
1341
  const settingTypes = [
1361
1342
  "rpnMSB",
1362
1343
  "rpnLSB",