@marmooo/midy 0.3.0 → 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.MidyGMLite = 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,
@@ -130,7 +84,7 @@ const defaultControllerState = {
130
84
  modulationDepth: { type: 128 + 1, defaultValue: 0 },
131
85
  // dataMSB: { type: 128 + 6, defaultValue: 0, },
132
86
  volume: { type: 128 + 7, defaultValue: 100 / 127 },
133
- pan: { type: 128 + 10, defaultValue: 0.5 },
87
+ pan: { type: 128 + 10, defaultValue: 64 / 127 },
134
88
  expression: { type: 128 + 11, defaultValue: 1 },
135
89
  // bankLSB: { type: 128 + 32, defaultValue: 0, },
136
90
  // dataLSB: { type: 128 + 38, defaultValue: 0, },
@@ -341,7 +295,7 @@ class MidyGMLite {
341
295
  initSoundFontTable() {
342
296
  const table = new Array(128);
343
297
  for (let i = 0; i < 128; i++) {
344
- table[i] = new SparseMap(128);
298
+ table[i] = new Map();
345
299
  }
346
300
  return table;
347
301
  }
@@ -393,10 +347,10 @@ class MidyGMLite {
393
347
  return {
394
348
  currentBufferSource: null,
395
349
  isDrum: false,
396
- ...this.constructor.channelSettings,
397
350
  state: new ControllerState(),
351
+ ...this.constructor.channelSettings,
398
352
  ...this.setChannelAudioNodes(audioContext),
399
- scheduledNotes: new SparseMap(128),
353
+ scheduledNotes: [],
400
354
  sustainNotes: [],
401
355
  };
402
356
  });
@@ -441,24 +395,20 @@ class MidyGMLite {
441
395
  }
442
396
  return bufferSource;
443
397
  }
444
- async scheduleTimelineEvents(t, offset, queueIndex) {
398
+ async scheduleTimelineEvents(t, resumeTime, queueIndex) {
445
399
  while (queueIndex < this.timeline.length) {
446
400
  const event = this.timeline[queueIndex];
447
401
  if (event.startTime > t + this.lookAhead)
448
402
  break;
449
- const startTime = event.startTime + this.startDelay - offset;
403
+ const delay = this.startDelay - resumeTime;
404
+ const startTime = event.startTime + delay;
450
405
  switch (event.type) {
451
- case "noteOn":
452
- if (event.velocity !== 0) {
453
- await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime);
454
- break;
455
- }
456
- /* falls through */
457
- case "noteOff": {
458
- const notePromise = this.scheduleNoteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
459
- if (notePromise) {
460
- this.notePromises.push(notePromise);
461
- }
406
+ case "noteOn": {
407
+ const noteOffEvent = {
408
+ ...event.noteOffEvent,
409
+ startTime: event.noteOffEvent.startTime + delay,
410
+ };
411
+ await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime, noteOffEvent);
462
412
  break;
463
413
  }
464
414
  case "controller":
@@ -491,44 +441,53 @@ class MidyGMLite {
491
441
  this.isPaused = false;
492
442
  this.startTime = this.audioContext.currentTime;
493
443
  let queueIndex = this.getQueueIndex(this.resumeTime);
494
- let offset = this.resumeTime - this.startTime;
444
+ let resumeTime = this.resumeTime - this.startTime;
495
445
  this.notePromises = [];
496
446
  const schedulePlayback = async () => {
497
447
  if (queueIndex >= this.timeline.length) {
498
448
  await Promise.all(this.notePromises);
499
449
  this.notePromises = [];
500
- this.exclusiveClassNotes.flll(undefined);
450
+ this.exclusiveClassNotes.fill(undefined);
451
+ this.drumExclusiveClassNotes.fill(undefined);
501
452
  this.audioBufferCache.clear();
453
+ for (let i = 0; i < this.channels.length; i++) {
454
+ this.resetAllStates(i);
455
+ }
502
456
  resolve();
503
457
  return;
504
458
  }
505
459
  const now = this.audioContext.currentTime;
506
- const t = now + offset;
507
- queueIndex = await this.scheduleTimelineEvents(t, offset, queueIndex);
460
+ const t = now + resumeTime;
461
+ queueIndex = await this.scheduleTimelineEvents(t, resumeTime, queueIndex);
508
462
  if (this.isPausing) {
509
463
  await this.stopNotes(0, true, now);
510
464
  this.notePromises = [];
511
- resolve();
512
465
  this.isPausing = false;
513
466
  this.isPaused = true;
467
+ resolve();
514
468
  return;
515
469
  }
516
470
  else if (this.isStopping) {
517
471
  await this.stopNotes(0, true, now);
518
472
  this.notePromises = [];
519
473
  this.exclusiveClassNotes.fill(undefined);
474
+ this.drumExclusiveClassNotes.fill(undefined);
520
475
  this.audioBufferCache.clear();
521
- resolve();
476
+ for (let i = 0; i < this.channels.length; i++) {
477
+ this.resetAllStates(i);
478
+ }
522
479
  this.isStopping = false;
523
480
  this.isPaused = false;
481
+ resolve();
524
482
  return;
525
483
  }
526
484
  else if (this.isSeeking) {
527
485
  this.stopNotes(0, true, now);
528
486
  this.exclusiveClassNotes.fill(undefined);
487
+ this.drumExclusiveClassNotes.fill(undefined);
529
488
  this.startTime = this.audioContext.currentTime;
530
489
  queueIndex = this.getQueueIndex(this.resumeTime);
531
- offset = this.resumeTime - this.startTime;
490
+ resumeTime = this.resumeTime - this.startTime;
532
491
  this.isSeeking = false;
533
492
  await schedulePlayback();
534
493
  }
@@ -614,17 +573,52 @@ class MidyGMLite {
614
573
  prevTempoTicks = event.ticks;
615
574
  }
616
575
  }
576
+ const activeNotes = new Array(this.channels.length * 128);
577
+ for (let i = 0; i < activeNotes.length; i++) {
578
+ activeNotes[i] = [];
579
+ }
580
+ for (let i = 0; i < timeline.length; i++) {
581
+ const event = timeline[i];
582
+ switch (event.type) {
583
+ case "noteOn": {
584
+ const index = event.channel * 128 + event.noteNumber;
585
+ activeNotes[index].push(event);
586
+ break;
587
+ }
588
+ case "noteOff": {
589
+ const index = event.channel * 128 + event.noteNumber;
590
+ const noteOn = activeNotes[index].pop();
591
+ if (noteOn) {
592
+ noteOn.noteOffEvent = event;
593
+ }
594
+ else {
595
+ const eventString = JSON.stringify(event, null, 2);
596
+ console.warn(`noteOff without matching noteOn: ${eventString}`);
597
+ }
598
+ }
599
+ }
600
+ }
617
601
  return { instruments, timeline };
618
602
  }
603
+ stopActiveNotes(channelNumber, velocity, force, scheduleTime) {
604
+ const channel = this.channels[channelNumber];
605
+ const promises = [];
606
+ this.processActiveNotes(channel, scheduleTime, (note) => {
607
+ const promise = this.scheduleNoteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force, undefined);
608
+ this.notePromises.push(promise);
609
+ promises.push(promise);
610
+ });
611
+ return Promise.all(promises);
612
+ }
619
613
  stopChannelNotes(channelNumber, velocity, force, scheduleTime) {
620
614
  const channel = this.channels[channelNumber];
621
615
  const promises = [];
622
616
  this.processScheduledNotes(channel, (note) => {
623
- const promise = this.scheduleNoteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
617
+ const promise = this.scheduleNoteOff(channelNumber, note, velocity, scheduleTime, force);
624
618
  this.notePromises.push(promise);
625
619
  promises.push(promise);
626
620
  });
627
- channel.scheduledNotes.clear();
621
+ channel.scheduledNotes = [];
628
622
  return Promise.all(promises);
629
623
  }
630
624
  stopNotes(velocity, force, scheduleTime) {
@@ -645,9 +639,6 @@ class MidyGMLite {
645
639
  if (!this.isPlaying)
646
640
  return;
647
641
  this.isStopping = true;
648
- for (let i = 0; i < this.channels.length; i++) {
649
- this.resetAllStates(i);
650
- }
651
642
  }
652
643
  pause() {
653
644
  if (!this.isPlaying || this.isPaused)
@@ -682,35 +673,31 @@ class MidyGMLite {
682
673
  return this.resumeTime + now - this.startTime - this.startDelay;
683
674
  }
684
675
  processScheduledNotes(channel, callback) {
685
- channel.scheduledNotes.forEach((noteList) => {
686
- for (let i = 0; i < noteList.length; i++) {
687
- const note = noteList[i];
688
- if (!note)
689
- continue;
690
- callback(note);
691
- }
692
- });
693
- }
694
- getActiveNotes(channel, scheduleTime) {
695
- const activeNotes = new SparseMap(128);
696
- channel.scheduledNotes.forEach((noteList) => {
697
- const activeNote = this.getActiveNote(noteList, scheduleTime);
698
- if (activeNote) {
699
- activeNotes.set(activeNote.noteNumber, activeNote);
700
- }
701
- });
702
- return activeNotes;
676
+ const scheduledNotes = channel.scheduledNotes;
677
+ for (let i = 0; i < scheduledNotes.length; i++) {
678
+ const note = scheduledNotes[i];
679
+ if (!note)
680
+ continue;
681
+ if (note.ending)
682
+ continue;
683
+ callback(note);
684
+ }
703
685
  }
704
- getActiveNote(noteList, scheduleTime) {
705
- for (let i = noteList.length - 1; i >= 0; i--) {
706
- const note = noteList[i];
686
+ processActiveNotes(channel, scheduleTime, callback) {
687
+ const scheduledNotes = channel.scheduledNotes;
688
+ for (let i = 0; i < scheduledNotes.length; i++) {
689
+ const note = scheduledNotes[i];
707
690
  if (!note)
708
- return;
691
+ continue;
692
+ if (note.ending)
693
+ continue;
694
+ const noteOffEvent = note.noteOffEvent;
695
+ if (noteOffEvent && noteOffEvent.startTime < scheduleTime)
696
+ continue;
709
697
  if (scheduleTime < note.startTime)
710
698
  continue;
711
- return (note.ending) ? null : note;
699
+ callback(note);
712
700
  }
713
- return noteList[0];
714
701
  }
715
702
  cbToRatio(cb) {
716
703
  return Math.pow(10, cb / 200);
@@ -857,6 +844,7 @@ class MidyGMLite {
857
844
  this.setVolumeEnvelope(note, now);
858
845
  this.setFilterEnvelope(note, now);
859
846
  this.setPitchEnvelope(note, now);
847
+ this.updateDetune(channel, note, now);
860
848
  if (0 < state.modulationDepth) {
861
849
  this.startModulation(channel, note, now);
862
850
  }
@@ -873,7 +861,7 @@ class MidyGMLite {
873
861
  if (prev) {
874
862
  const [prevNote, prevChannelNumber] = prev;
875
863
  if (prevNote && !prevNote.ending) {
876
- this.scheduleNoteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
864
+ this.scheduleNoteOff(prevChannelNumber, prevNote, 0, // velocity,
877
865
  startTime, true);
878
866
  }
879
867
  }
@@ -889,12 +877,12 @@ class MidyGMLite {
889
877
  const index = drumExclusiveClass * this.channels.length + channelNumber;
890
878
  const prevNote = this.drumExclusiveClassNotes[index];
891
879
  if (prevNote && !prevNote.ending) {
892
- this.scheduleNoteOff(channelNumber, prevNote.noteNumber, 0, // velocity,
880
+ this.scheduleNoteOff(channelNumber, prevNote, 0, // velocity,
893
881
  startTime, true);
894
882
  }
895
883
  this.drumExclusiveClassNotes[index] = note;
896
884
  }
897
- async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
885
+ async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime, noteOffEvent) {
898
886
  const channel = this.channels[channelNumber];
899
887
  const bankNumber = channel.bank;
900
888
  const soundFontIndex = this.soundFontTable[channel.programNumber].get(bankNumber);
@@ -906,6 +894,7 @@ class MidyGMLite {
906
894
  return;
907
895
  const isSF3 = soundFont.parsed.info.version.major === 3;
908
896
  const note = await this.createNote(channel, voice, noteNumber, velocity, startTime, isSF3);
897
+ note.noteOffEvent = noteOffEvent;
909
898
  note.volumeEnvelopeNode.connect(channel.gainL);
910
899
  note.volumeEnvelopeNode.connect(channel.gainR);
911
900
  if (0.5 <= channel.state.sustainPedal) {
@@ -914,33 +903,32 @@ class MidyGMLite {
914
903
  this.handleExclusiveClass(note, channelNumber, startTime);
915
904
  this.handleDrumExclusiveClass(note, channelNumber, startTime);
916
905
  const scheduledNotes = channel.scheduledNotes;
917
- let notes = scheduledNotes.get(noteNumber);
918
- if (notes) {
919
- notes.push(note);
920
- }
921
- else {
922
- notes = [note];
923
- scheduledNotes.set(noteNumber, notes);
924
- }
925
- if (this.isDrumNoteOffException(channel, noteNumber)) {
906
+ note.index = scheduledNotes.length;
907
+ scheduledNotes.push(note);
908
+ if (channel.isDrum) {
926
909
  const stopTime = startTime + note.bufferSource.buffer.duration;
927
- const index = notes.length - 1;
928
910
  const promise = new Promise((resolve) => {
929
911
  note.bufferSource.onended = () => {
930
- this.disconnectNote(note, scheduledNotes, index);
912
+ scheduledNotes[note.index] = undefined;
913
+ this.disconnectNote(note);
931
914
  resolve();
932
915
  };
933
916
  note.bufferSource.stop(stopTime);
934
917
  });
935
918
  this.notePromises.push(promise);
936
919
  }
920
+ else if (noteOffEvent) {
921
+ const notePromise = this.scheduleNoteOff(channelNumber, note, noteOffEvent.velocity, noteOffEvent.startTime, false);
922
+ if (notePromise) {
923
+ this.notePromises.push(notePromise);
924
+ }
925
+ }
937
926
  }
938
927
  noteOn(channelNumber, noteNumber, velocity, scheduleTime) {
939
928
  scheduleTime ??= this.audioContext.currentTime;
940
- return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime);
929
+ return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime, undefined);
941
930
  }
942
- disconnectNote(note, scheduledNotes, index) {
943
- scheduledNotes[index] = null;
931
+ disconnectNote(note) {
944
932
  note.bufferSource.disconnect();
945
933
  note.filterNode.disconnect();
946
934
  note.volumeEnvelopeNode.disconnect();
@@ -950,8 +938,7 @@ class MidyGMLite {
950
938
  note.modulationLFO.stop();
951
939
  }
952
940
  }
953
- stopNote(endTime, stopTime, scheduledNotes, index) {
954
- const note = scheduledNotes[index];
941
+ stopNote(channel, note, endTime, stopTime) {
955
942
  note.volumeEnvelopeNode.gain
956
943
  .cancelScheduledValues(endTime)
957
944
  .linearRampToValueAtTime(0, stopTime);
@@ -961,46 +948,52 @@ class MidyGMLite {
961
948
  }, stopTime);
962
949
  return new Promise((resolve) => {
963
950
  note.bufferSource.onended = () => {
964
- this.disconnectNote(note, scheduledNotes, index);
951
+ channel.scheduledNotes[note.index] = undefined;
952
+ this.disconnectNote(note);
965
953
  resolve();
966
954
  };
967
955
  note.bufferSource.stop(stopTime);
968
956
  });
969
957
  }
970
- scheduleNoteOff(channelNumber, noteNumber, _velocity, endTime, force) {
958
+ scheduleNoteOff(channelNumber, note, _velocity, endTime, force) {
971
959
  const channel = this.channels[channelNumber];
972
960
  if (channel.isDrum)
973
961
  return;
974
962
  if (!force && 0.5 <= channel.state.sustainPedal)
975
963
  return;
976
- if (!channel.scheduledNotes.has(noteNumber))
977
- return;
978
- const scheduledNotes = channel.scheduledNotes.get(noteNumber);
964
+ const volRelease = endTime + note.voiceParams.volRelease;
965
+ const modRelease = endTime + note.voiceParams.modRelease;
966
+ note.filterNode.frequency
967
+ .cancelScheduledValues(endTime)
968
+ .linearRampToValueAtTime(0, modRelease);
969
+ const stopTime = Math.min(volRelease, modRelease);
970
+ return this.stopNote(channel, note, endTime, stopTime);
971
+ }
972
+ findNoteOffTarget(channel, noteNumber) {
973
+ const scheduledNotes = channel.scheduledNotes;
979
974
  for (let i = 0; i < scheduledNotes.length; i++) {
980
975
  const note = scheduledNotes[i];
981
976
  if (!note)
982
977
  continue;
983
978
  if (note.ending)
984
979
  continue;
985
- const volRelease = endTime + note.voiceParams.volRelease;
986
- const modRelease = endTime + note.voiceParams.modRelease;
987
- note.filterNode.frequency
988
- .cancelScheduledValues(endTime)
989
- .linearRampToValueAtTime(0, modRelease);
990
- const stopTime = Math.min(volRelease, modRelease);
991
- return this.stopNote(endTime, stopTime, scheduledNotes, i);
980
+ if (note.noteNumber !== noteNumber)
981
+ continue;
982
+ return note;
992
983
  }
993
984
  }
994
985
  noteOff(channelNumber, noteNumber, velocity, scheduleTime) {
995
986
  scheduleTime ??= this.audioContext.currentTime;
996
- return this.scheduleNoteOff(channelNumber, noteNumber, velocity, scheduleTime, false);
987
+ const channel = this.channels[channelNumber];
988
+ const note = this.findNoteOffTarget(channel, noteNumber);
989
+ return this.scheduleNoteOff(channelNumber, note, velocity, scheduleTime, false);
997
990
  }
998
991
  releaseSustainPedal(channelNumber, halfVelocity, scheduleTime) {
999
992
  const velocity = halfVelocity * 2;
1000
993
  const channel = this.channels[channelNumber];
1001
994
  const promises = [];
1002
995
  for (let i = 0; i < channel.sustainNotes.length; i++) {
1003
- const promise = this.noteOff(channelNumber, channel.sustainNotes[i].noteNumber, velocity, scheduleTime);
996
+ const promise = this.scheduleNoteOff(channelNumber, channel.sustainNotes[i], velocity, scheduleTime);
1004
997
  promises.push(promise);
1005
998
  }
1006
999
  channel.sustainNotes = [];
@@ -1156,20 +1149,20 @@ class MidyGMLite {
1156
1149
  });
1157
1150
  }
1158
1151
  createControlChangeHandlers() {
1159
- return {
1160
- 1: this.setModulationDepth,
1161
- 6: this.dataEntryMSB,
1162
- 7: this.setVolume,
1163
- 10: this.setPan,
1164
- 11: this.setExpression,
1165
- 38: this.dataEntryLSB,
1166
- 64: this.setSustainPedal,
1167
- 100: this.setRPNLSB,
1168
- 101: this.setRPNMSB,
1169
- 120: this.allSoundOff,
1170
- 121: this.resetAllControllers,
1171
- 123: this.allNotesOff,
1172
- };
1152
+ const handlers = new Array(128);
1153
+ handlers[1] = this.setModulationDepth;
1154
+ handlers[6] = this.dataEntryMSB;
1155
+ handlers[7] = this.setVolume;
1156
+ handlers[10] = this.setPan;
1157
+ handlers[11] = this.setExpression;
1158
+ handlers[38] = this.dataEntryLSB;
1159
+ handlers[64] = this.setSustainPedal;
1160
+ handlers[100] = this.setRPNLSB;
1161
+ handlers[101] = this.setRPNMSB;
1162
+ handlers[120] = this.allSoundOff;
1163
+ handlers[121] = this.resetAllControllers;
1164
+ handlers[123] = this.allNotesOff;
1165
+ return handlers;
1173
1166
  }
1174
1167
  handleControlChange(channelNumber, controllerType, value, scheduleTime) {
1175
1168
  const handler = this.controlChangeHandlers[controllerType];
@@ -1311,22 +1304,29 @@ class MidyGMLite {
1311
1304
  }
1312
1305
  allSoundOff(channelNumber, _value, scheduleTime) {
1313
1306
  scheduleTime ??= this.audioContext.currentTime;
1314
- return this.stopChannelNotes(channelNumber, 0, true, scheduleTime);
1307
+ return this.stopActiveNotes(channelNumber, 0, true, scheduleTime);
1315
1308
  }
1316
1309
  resetAllStates(channelNumber) {
1310
+ const scheduleTime = this.audioContext.currentTime;
1317
1311
  const channel = this.channels[channelNumber];
1318
1312
  const state = channel.state;
1319
- for (const type of Object.keys(defaultControllerState)) {
1320
- state[type] = defaultControllerState[type].defaultValue;
1313
+ const entries = Object.entries(defaultControllerState);
1314
+ for (const [key, { type, defaultValue }] of entries) {
1315
+ if (128 <= type) {
1316
+ this.handleControlChange(channelNumber, type - 128, Math.ceil(defaultValue * 127), scheduleTime);
1317
+ }
1318
+ else {
1319
+ state[key] = defaultValue;
1320
+ }
1321
1321
  }
1322
- for (const type of Object.keys(this.constructor.channelSettings)) {
1323
- channel[type] = this.constructor.channelSettings[type];
1322
+ for (const key of Object.keys(this.constructor.channelSettings)) {
1323
+ channel[key] = this.constructor.channelSettings[key];
1324
1324
  }
1325
1325
  this.mode = "GM1";
1326
1326
  }
1327
1327
  // https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/rp15.pdf
1328
- resetAllControllers(channelNumber) {
1329
- const stateTypes = [
1328
+ resetAllControllers(channelNumber, _value, scheduleTime) {
1329
+ const keys = [
1330
1330
  "pitchWheel",
1331
1331
  "expression",
1332
1332
  "modulationDepth",
@@ -1334,10 +1334,17 @@ class MidyGMLite {
1334
1334
  ];
1335
1335
  const channel = this.channels[channelNumber];
1336
1336
  const state = channel.state;
1337
- for (let i = 0; i < stateTypes.length; i++) {
1338
- const type = stateTypes[i];
1339
- state[type] = defaultControllerState[type].defaultValue;
1337
+ for (let i = 0; i < keys.length; i++) {
1338
+ const key = keys[i];
1339
+ const { type, defaultValue } = defaultControllerState[key];
1340
+ if (128 <= type) {
1341
+ this.handleControlChange(channelNumber, type - 128, Math.ceil(defaultValue * 127), scheduleTime);
1342
+ }
1343
+ else {
1344
+ state[key] = defaultValue;
1345
+ }
1340
1346
  }
1347
+ this.setPitchBend(channelNumber, 8192, scheduleTime);
1341
1348
  const settingTypes = [
1342
1349
  "rpnMSB",
1343
1350
  "rpnLSB",
@@ -1349,7 +1356,7 @@ class MidyGMLite {
1349
1356
  }
1350
1357
  allNotesOff(channelNumber, _value, scheduleTime) {
1351
1358
  scheduleTime ??= this.audioContext.currentTime;
1352
- return this.stopChannelNotes(channelNumber, 0, false, scheduleTime);
1359
+ return this.stopActiveNotes(channelNumber, 0, false, scheduleTime);
1353
1360
  }
1354
1361
  handleUniversalNonRealTimeExclusiveMessage(data, scheduleTime) {
1355
1362
  switch (data[2]) {