@marmooo/midy 0.3.7 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/esm/midy-GM2.js CHANGED
@@ -272,6 +272,18 @@ export class MidyGM2 {
272
272
  writable: true,
273
273
  value: 0
274
274
  });
275
+ Object.defineProperty(this, "lastActiveSensing", {
276
+ enumerable: true,
277
+ configurable: true,
278
+ writable: true,
279
+ value: 0
280
+ });
281
+ Object.defineProperty(this, "activeSensingThreshold", {
282
+ enumerable: true,
283
+ configurable: true,
284
+ writable: true,
285
+ value: 0.3
286
+ });
275
287
  Object.defineProperty(this, "noteCheckInterval", {
276
288
  enumerable: true,
277
289
  configurable: true,
@@ -312,7 +324,7 @@ export class MidyGM2 {
312
324
  enumerable: true,
313
325
  configurable: true,
314
326
  writable: true,
315
- value: this.initSoundFontTable()
327
+ value: Array.from({ length: 128 }, () => [])
316
328
  });
317
329
  Object.defineProperty(this, "voiceCounter", {
318
330
  enumerable: true,
@@ -399,8 +411,10 @@ export class MidyGM2 {
399
411
  length: 1,
400
412
  sampleRate: audioContext.sampleRate,
401
413
  });
414
+ this.messageHandlers = this.createMessageHandlers();
402
415
  this.voiceParamsHandlers = this.createVoiceParamsHandlers();
403
416
  this.controlChangeHandlers = this.createControlChangeHandlers();
417
+ this.keyBasedControllerHandlers = this.createKeyBasedControllerHandlers();
404
418
  this.channels = this.createChannels(audioContext);
405
419
  this.reverbEffect = this.createReverbEffect(audioContext);
406
420
  this.chorusEffect = this.createChorusEffect(audioContext);
@@ -410,21 +424,14 @@ export class MidyGM2 {
410
424
  this.scheduler.connect(audioContext.destination);
411
425
  this.GM2SystemOn();
412
426
  }
413
- initSoundFontTable() {
414
- const table = new Array(128);
415
- for (let i = 0; i < 128; i++) {
416
- table[i] = new Map();
417
- }
418
- return table;
419
- }
420
427
  addSoundFont(soundFont) {
421
428
  const index = this.soundFonts.length;
422
429
  this.soundFonts.push(soundFont);
423
430
  const presetHeaders = soundFont.parsed.presetHeaders;
431
+ const soundFontTable = this.soundFontTable;
424
432
  for (let i = 0; i < presetHeaders.length; i++) {
425
- const presetHeader = presetHeaders[i];
426
- const banks = this.soundFontTable[presetHeader.preset];
427
- banks.set(presetHeader.bank, index);
433
+ const { preset, bank } = presetHeaders[i];
434
+ soundFontTable[preset][bank] = index;
428
435
  }
429
436
  }
430
437
  async toUint8Array(input) {
@@ -502,13 +509,17 @@ export class MidyGM2 {
502
509
  this.GM2SystemOn();
503
510
  }
504
511
  getVoiceId(channel, noteNumber, velocity) {
505
- const bankNumber = this.calcBank(channel);
506
- const soundFontIndex = this.soundFontTable[channel.programNumber]
507
- .get(bankNumber);
512
+ const programNumber = channel.programNumber;
513
+ const bankTable = this.soundFontTable[programNumber];
514
+ if (!bankTable)
515
+ return;
516
+ const bankLSB = channel.isDrum ? 128 : channel.bankLSB;
517
+ const bank = bankTable[bankLSB] !== undefined ? bankLSB : 0;
518
+ const soundFontIndex = bankTable[bank];
508
519
  if (soundFontIndex === undefined)
509
520
  return;
510
521
  const soundFont = this.soundFonts[soundFontIndex];
511
- const voice = soundFont.getVoice(bankNumber, channel.programNumber, noteNumber, velocity);
522
+ const voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
512
523
  const { instrument, sampleID } = voice.generators;
513
524
  return soundFontIndex * (2 ** 32) + (instrument << 16) + sampleID;
514
525
  }
@@ -577,13 +588,16 @@ export class MidyGM2 {
577
588
  }
578
589
  return bufferSource;
579
590
  }
580
- async scheduleTimelineEvents(t, resumeTime, queueIndex) {
581
- while (queueIndex < this.timeline.length) {
582
- const event = this.timeline[queueIndex];
583
- if (event.startTime > t + this.lookAhead)
591
+ async scheduleTimelineEvents(scheduleTime, queueIndex) {
592
+ const timeOffset = this.resumeTime - this.startTime;
593
+ const lookAheadCheckTime = scheduleTime + timeOffset + this.lookAhead;
594
+ const schedulingOffset = this.startDelay - timeOffset;
595
+ const timeline = this.timeline;
596
+ while (queueIndex < timeline.length) {
597
+ const event = timeline[queueIndex];
598
+ if (lookAheadCheckTime < event.startTime)
584
599
  break;
585
- const delay = this.startDelay - resumeTime;
586
- const startTime = event.startTime + delay;
600
+ const startTime = event.startTime + schedulingOffset;
587
601
  switch (event.type) {
588
602
  case "noteOn":
589
603
  await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime);
@@ -658,13 +672,18 @@ export class MidyGM2 {
658
672
  this.isPaused = false;
659
673
  this.startTime = this.audioContext.currentTime;
660
674
  let queueIndex = this.getQueueIndex(this.resumeTime);
661
- let resumeTime = this.resumeTime - this.startTime;
662
675
  let finished = false;
663
676
  this.notePromises = [];
664
677
  while (queueIndex < this.timeline.length) {
665
678
  const now = this.audioContext.currentTime;
666
- const t = now + resumeTime;
667
- queueIndex = await this.scheduleTimelineEvents(t, resumeTime, queueIndex);
679
+ if (0 < this.lastActiveSensing &&
680
+ this.activeSensingThreshold < performance.now() - this.lastActiveSensing) {
681
+ await this.stopNotes(0, true, now);
682
+ await this.audioContext.suspend();
683
+ finished = true;
684
+ break;
685
+ }
686
+ queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
668
687
  if (this.isPausing) {
669
688
  await this.stopNotes(0, true, now);
670
689
  await this.audioContext.suspend();
@@ -683,7 +702,6 @@ export class MidyGM2 {
683
702
  const nextQueueIndex = this.getQueueIndex(this.resumeTime);
684
703
  this.updateStates(queueIndex, nextQueueIndex);
685
704
  queueIndex = nextQueueIndex;
686
- resumeTime = this.resumeTime - this.startTime;
687
705
  this.isSeeking = false;
688
706
  continue;
689
707
  }
@@ -693,6 +711,7 @@ export class MidyGM2 {
693
711
  if (finished) {
694
712
  this.notePromises = [];
695
713
  this.resetAllStates();
714
+ this.lastActiveSensing = 0;
696
715
  }
697
716
  this.isPlaying = false;
698
717
  }
@@ -702,17 +721,17 @@ export class MidyGM2 {
702
721
  secondToTicks(second, secondsPerBeat) {
703
722
  return second * this.ticksPerBeat / secondsPerBeat;
704
723
  }
724
+ getSoundFontId(channel) {
725
+ const programNumber = channel.programNumber;
726
+ const bankNumber = channel.isDrum ? 128 : channel.bankLSB;
727
+ const bank = bankNumber.toString().padStart(3, "0");
728
+ const program = programNumber.toString().padStart(3, "0");
729
+ return `${bank}:${program}`;
730
+ }
705
731
  extractMidiData(midi) {
706
732
  const instruments = new Set();
707
733
  const timeline = [];
708
- const tmpChannels = new Array(this.channels.length);
709
- for (let i = 0; i < tmpChannels.length; i++) {
710
- tmpChannels[i] = {
711
- programNumber: -1,
712
- bankMSB: this.channels[i].bankMSB,
713
- bankLSB: this.channels[i].bankLSB,
714
- };
715
- }
734
+ const channels = this.channels;
716
735
  for (let i = 0; i < midi.tracks.length; i++) {
717
736
  const track = midi.tracks[i];
718
737
  let currentTicks = 0;
@@ -722,48 +741,40 @@ export class MidyGM2 {
722
741
  event.ticks = currentTicks;
723
742
  switch (event.type) {
724
743
  case "noteOn": {
725
- const channel = tmpChannels[event.channel];
726
- if (channel.programNumber < 0) {
727
- channel.programNumber = event.programNumber;
728
- switch (channel.bankMSB) {
729
- case 120:
730
- instruments.add(`128:0`);
731
- break;
732
- case 121:
733
- instruments.add(`${channel.bankLSB}:0`);
734
- break;
735
- default: {
736
- const bankNumber = channel.bankMSB * 128 + channel.bankLSB;
737
- instruments.add(`${bankNumber}:0`);
738
- }
739
- }
740
- channel.programNumber = 0;
741
- }
744
+ const channel = channels[event.channel];
745
+ instruments.add(this.getSoundFontId(channel));
742
746
  break;
743
747
  }
744
748
  case "controller":
745
749
  switch (event.controllerType) {
746
750
  case 0:
747
- tmpChannels[event.channel].bankMSB = event.value;
751
+ this.setBankMSB(event.channel, event.value);
748
752
  break;
749
753
  case 32:
750
- tmpChannels[event.channel].bankLSB = event.value;
754
+ this.setBankLSB(event.channel, event.value);
751
755
  break;
752
756
  }
753
757
  break;
754
758
  case "programChange": {
755
- const channel = tmpChannels[event.channel];
756
- channel.programNumber = event.programNumber;
757
- switch (channel.bankMSB) {
758
- case 120:
759
- instruments.add(`128:${channel.programNumber}`);
760
- break;
761
- case 121:
762
- instruments.add(`${channel.bankLSB}:${channel.programNumber}`);
763
- break;
764
- default: {
765
- const bankNumber = channel.bankMSB * 128 + channel.bankLSB;
766
- instruments.add(`${bankNumber}:${channel.programNumber}`);
759
+ const channel = channels[event.channel];
760
+ this.setProgramChange(event.channel, event.programNumber);
761
+ instruments.add(this.getSoundFontId(channel));
762
+ break;
763
+ }
764
+ case "sysEx": {
765
+ const data = event.data;
766
+ if (data[0] === 126 && data[1] === 9 && data[2] === 3) {
767
+ switch (data[3]) {
768
+ case 1:
769
+ this.GM1SystemOn(scheduleTime);
770
+ break;
771
+ case 2: // GM System Off
772
+ break;
773
+ case 3:
774
+ this.GM2SystemOn(scheduleTime);
775
+ break;
776
+ default:
777
+ console.warn(`Unsupported Exclusive Message: ${data}`);
767
778
  }
768
779
  }
769
780
  }
@@ -1086,7 +1097,7 @@ export class MidyGM2 {
1086
1097
  updateDetune(channel, note, scheduleTime) {
1087
1098
  const noteDetune = this.calcNoteDetune(channel, note);
1088
1099
  const detune = channel.detune + noteDetune;
1089
- if (0.5 <= channel.state.portamento && 0 <= note.portamentoNoteNumber) {
1100
+ if (this.isPortamento(channel, note)) {
1090
1101
  const startTime = note.startTime;
1091
1102
  const deltaCent = (note.noteNumber - note.portamentoNoteNumber) * 100;
1092
1103
  const portamentoTime = startTime + this.getPortamentoTime(channel, note);
@@ -1337,7 +1348,7 @@ export class MidyGM2 {
1337
1348
  if (prevNote && prevNote.noteNumber !== noteNumber) {
1338
1349
  note.portamentoNoteNumber = prevNote.noteNumber;
1339
1350
  }
1340
- if (0.5 <= channel.state.portamento && 0 <= note.portamentoNoteNumber) {
1351
+ if (!channel.isDrum && this.isPortamento(channel, note)) {
1341
1352
  this.setPortamentoVolumeEnvelope(channel, note, now);
1342
1353
  this.setPortamentoFilterEnvelope(channel, note, now);
1343
1354
  this.setPortamentoPitchEnvelope(note, now);
@@ -1365,22 +1376,6 @@ export class MidyGM2 {
1365
1376
  note.bufferSource.start(startTime);
1366
1377
  return note;
1367
1378
  }
1368
- calcBank(channel) {
1369
- switch (this.mode) {
1370
- case "GM1":
1371
- if (channel.isDrum)
1372
- return 128;
1373
- return 0;
1374
- case "GM2":
1375
- if (channel.bankMSB === 121)
1376
- return 0;
1377
- if (channel.isDrum)
1378
- return 128;
1379
- return channel.bank;
1380
- default:
1381
- return channel.bank;
1382
- }
1383
- }
1384
1379
  handleExclusiveClass(note, channelNumber, startTime) {
1385
1380
  const exclusiveClass = note.voiceParams.exclusiveClass;
1386
1381
  if (exclusiveClass === 0)
@@ -1416,13 +1411,17 @@ export class MidyGM2 {
1416
1411
  }
1417
1412
  async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
1418
1413
  const channel = this.channels[channelNumber];
1419
- const bankNumber = this.calcBank(channel, channelNumber);
1420
- const soundFontIndex = this.soundFontTable[channel.programNumber]
1421
- .get(bankNumber);
1414
+ const programNumber = channel.programNumber;
1415
+ const bankTable = this.soundFontTable[programNumber];
1416
+ if (!bankTable)
1417
+ return;
1418
+ const bankLSB = channel.isDrum ? 128 : channel.bankLSB;
1419
+ const bank = bankTable[bankLSB] !== undefined ? bankLSB : 0;
1420
+ const soundFontIndex = bankTable[bank];
1422
1421
  if (soundFontIndex === undefined)
1423
1422
  return;
1424
1423
  const soundFont = this.soundFonts[soundFontIndex];
1425
- const voice = soundFont.getVoice(bankNumber, channel.programNumber, noteNumber, velocity);
1424
+ const voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
1426
1425
  if (!voice)
1427
1426
  return;
1428
1427
  const note = await this.createNote(channel, voice, noteNumber, velocity, startTime);
@@ -1574,41 +1573,45 @@ export class MidyGM2 {
1574
1573
  channel.sostenutoNotes = [];
1575
1574
  return promises;
1576
1575
  }
1577
- handleMIDIMessage(statusByte, data1, data2, scheduleTime) {
1578
- const channelNumber = statusByte & 0x0F;
1579
- const messageType = statusByte & 0xF0;
1580
- switch (messageType) {
1581
- case 0x80:
1582
- return this.noteOff(channelNumber, data1, data2, scheduleTime);
1583
- case 0x90:
1584
- return this.noteOn(channelNumber, data1, data2, scheduleTime);
1585
- case 0xB0:
1586
- return this.setControlChange(channelNumber, data1, data2, scheduleTime);
1587
- case 0xC0:
1588
- return this.setProgramChange(channelNumber, data1, scheduleTime);
1589
- case 0xD0:
1590
- return this.setChannelPressure(channelNumber, data1, scheduleTime);
1591
- case 0xE0:
1592
- return this.handlePitchBendMessage(channelNumber, data1, data2, scheduleTime);
1593
- default:
1594
- console.warn(`Unsupported MIDI message: ${messageType.toString(16)}`);
1576
+ createMessageHandlers() {
1577
+ const handlers = new Array(256);
1578
+ // Channel Message
1579
+ handlers[0x80] = (data, scheduleTime) => this.noteOff(data[0] & 0x0F, data[1], data[2], scheduleTime);
1580
+ handlers[0x90] = (data, scheduleTime) => this.noteOn(data[0] & 0x0F, data[1], data[2], scheduleTime);
1581
+ handlers[0xB0] = (data, scheduleTime) => this.setControlChange(data[0] & 0x0F, data[1], data[2], scheduleTime);
1582
+ handlers[0xC0] = (data, scheduleTime) => this.setProgramChange(data[0] & 0x0F, data[1], scheduleTime);
1583
+ handlers[0xD0] = (data, scheduleTime) => this.setChannelPressure(data[0] & 0x0F, data[1], scheduleTime);
1584
+ handlers[0xE0] = (data, scheduleTime) => this.handlePitchBendMessage(data[0] & 0x0F, data[1], data[2], scheduleTime);
1585
+ // System Real Time Message
1586
+ handlers[0xFE] = (_data, _scheduleTime) => this.activeSensing();
1587
+ return handlers;
1588
+ }
1589
+ handleMessage(data, scheduleTime) {
1590
+ const status = data[0];
1591
+ if (status === 0xF0) {
1592
+ return this.handleSysEx(data.subarray(1), scheduleTime);
1595
1593
  }
1594
+ const handler = this.messageHandlers[status];
1595
+ if (handler)
1596
+ handler(data, scheduleTime);
1597
+ }
1598
+ activeSensing() {
1599
+ this.lastActiveSensing = performance.now();
1596
1600
  }
1597
1601
  setProgramChange(channelNumber, programNumber, _scheduleTime) {
1598
1602
  const channel = this.channels[channelNumber];
1599
- channel.bank = channel.bankMSB * 128 + channel.bankLSB;
1600
1603
  channel.programNumber = programNumber;
1601
1604
  if (this.mode === "GM2") {
1602
1605
  switch (channel.bankMSB) {
1603
1606
  case 120:
1604
1607
  channel.isDrum = true;
1608
+ channel.keyBasedTable.fill(-1);
1605
1609
  break;
1606
1610
  case 121:
1607
1611
  channel.isDrum = false;
1608
1612
  break;
1609
1613
  }
1610
1614
  }
1611
- channel.keyBasedTable.fill(-1);
1612
1615
  }
1613
1616
  setChannelPressure(channelNumber, value, scheduleTime) {
1614
1617
  const channel = this.channels[channelNumber];
@@ -1933,22 +1936,20 @@ export class MidyGM2 {
1933
1936
  this.updateModulation(channel, scheduleTime);
1934
1937
  }
1935
1938
  updatePortamento(channel, scheduleTime) {
1939
+ if (channel.isDrum)
1940
+ return;
1936
1941
  this.processScheduledNotes(channel, (note) => {
1937
- if (0.5 <= channel.state.portamento) {
1938
- if (0 <= note.portamentoNoteNumber) {
1939
- this.setPortamentoVolumeEnvelope(channel, note, scheduleTime);
1940
- this.setPortamentoFilterEnvelope(channel, note, scheduleTime);
1941
- this.setPortamentoPitchEnvelope(note, scheduleTime);
1942
- this.updateDetune(channel, note, scheduleTime);
1943
- }
1942
+ if (this.isPortamento(channel, note)) {
1943
+ this.setPortamentoVolumeEnvelope(channel, note, scheduleTime);
1944
+ this.setPortamentoFilterEnvelope(channel, note, scheduleTime);
1945
+ this.setPortamentoPitchEnvelope(note, scheduleTime);
1946
+ this.updateDetune(channel, note, scheduleTime);
1944
1947
  }
1945
1948
  else {
1946
- if (0 <= note.portamentoNoteNumber) {
1947
- this.setVolumeEnvelope(channel, note, scheduleTime);
1948
- this.setFilterEnvelope(channel, note, scheduleTime);
1949
- this.setPitchEnvelope(note, scheduleTime);
1950
- this.updateDetune(channel, note, scheduleTime);
1951
- }
1949
+ this.setVolumeEnvelope(channel, note, scheduleTime);
1950
+ this.setFilterEnvelope(channel, note, scheduleTime);
1951
+ this.setPitchEnvelope(note, scheduleTime);
1952
+ this.updateDetune(channel, note, scheduleTime);
1952
1953
  }
1953
1954
  });
1954
1955
  }
@@ -2054,6 +2055,9 @@ export class MidyGM2 {
2054
2055
  this.releaseSustainPedal(channelNumber, value, scheduleTime);
2055
2056
  }
2056
2057
  }
2058
+ isPortamento(channel, note) {
2059
+ return 0.5 <= channel.state.portamento && 0 <= note.portamentoNoteNumber;
2060
+ }
2057
2061
  setPortamento(channelNumber, value, scheduleTime) {
2058
2062
  const channel = this.channels[channelNumber];
2059
2063
  if (channel.isDrum)
@@ -2090,7 +2094,7 @@ export class MidyGM2 {
2090
2094
  scheduleTime ??= this.audioContext.currentTime;
2091
2095
  state.softPedal = softPedal / 127;
2092
2096
  this.processScheduledNotes(channel, (note) => {
2093
- if (0.5 <= state.portamento && 0 <= note.portamentoNoteNumber) {
2097
+ if (this.isPortamento(channel, note)) {
2094
2098
  this.setPortamentoVolumeEnvelope(channel, note, scheduleTime);
2095
2099
  this.setPortamentoFilterEnvelope(channel, note, scheduleTime);
2096
2100
  }
@@ -2358,11 +2362,9 @@ export class MidyGM2 {
2358
2362
  const channel = this.channels[i];
2359
2363
  channel.bankMSB = 0;
2360
2364
  channel.bankLSB = 0;
2361
- channel.bank = 0;
2362
2365
  channel.isDrum = false;
2363
2366
  }
2364
2367
  this.channels[9].bankMSB = 1;
2365
- this.channels[9].bank = 128;
2366
2368
  this.channels[9].isDrum = true;
2367
2369
  }
2368
2370
  GM2SystemOn(scheduleTime) {
@@ -2373,11 +2375,9 @@ export class MidyGM2 {
2373
2375
  const channel = this.channels[i];
2374
2376
  channel.bankMSB = 121;
2375
2377
  channel.bankLSB = 0;
2376
- channel.bank = 121 * 128;
2377
2378
  channel.isDrum = false;
2378
2379
  }
2379
2380
  this.channels[9].bankMSB = 120;
2380
- this.channels[9].bank = 120 * 128;
2381
2381
  this.channels[9].isDrum = true;
2382
2382
  }
2383
2383
  handleUniversalRealTimeExclusiveMessage(data, scheduleTime) {
@@ -2422,16 +2422,11 @@ export class MidyGM2 {
2422
2422
  const volume = (data[5] * 128 + data[4]) / 16383;
2423
2423
  this.setMasterVolume(volume, scheduleTime);
2424
2424
  }
2425
- setMasterVolume(volume, scheduleTime) {
2425
+ setMasterVolume(value, scheduleTime) {
2426
2426
  scheduleTime ??= this.audioContext.currentTime;
2427
- if (volume < 0 && 1 < volume) {
2428
- console.error("Master Volume is out of range");
2429
- }
2430
- else {
2431
- this.masterVolume.gain
2432
- .cancelScheduledValues(scheduleTime)
2433
- .setValueAtTime(volume * volume, scheduleTime);
2434
- }
2427
+ this.masterVolume.gain
2428
+ .cancelScheduledValues(scheduleTime)
2429
+ .setValueAtTime(value * value, scheduleTime);
2435
2430
  }
2436
2431
  handleMasterFineTuningSysEx(data, scheduleTime) {
2437
2432
  const value = (data[5] * 128 + data[4]) / 16383;
@@ -2794,6 +2789,22 @@ export class MidyGM2 {
2794
2789
  const controlValue = channel.keyBasedTable[index];
2795
2790
  return controlValue;
2796
2791
  }
2792
+ createKeyBasedControllerHandlers() {
2793
+ const handlers = new Array(128);
2794
+ handlers[7] = (channel, keyNumber, scheduleTime) => this.updateKeyBasedVolume(channel, keyNumber, scheduleTime);
2795
+ handlers[10] = (channel, keyNumber, scheduleTime) => this.updateKeyBasedVolume(channel, keyNumber, scheduleTime);
2796
+ handlers[91] = (channel, keyNumber, scheduleTime) => this.processScheduledNotes(channel, (note) => {
2797
+ if (note.noteNumber === keyNumber) {
2798
+ this.setReverbSend(channel, note, scheduleTime);
2799
+ }
2800
+ });
2801
+ handlers[93] = (channel, keyNumber, scheduleTime) => this.processScheduledNotes(channel, (note) => {
2802
+ if (note.noteNumber === keyNumber) {
2803
+ this.setChorusSend(channel, note, scheduleTime);
2804
+ }
2805
+ });
2806
+ return handlers;
2807
+ }
2797
2808
  handleKeyBasedInstrumentControlSysEx(data, scheduleTime) {
2798
2809
  const channelNumber = data[4];
2799
2810
  const channel = this.channels[channelNumber];
@@ -2806,26 +2817,9 @@ export class MidyGM2 {
2806
2817
  const value = data[i + 1];
2807
2818
  const index = keyNumber * 128 + controllerType;
2808
2819
  table[index] = value;
2809
- switch (controllerType) {
2810
- case 7:
2811
- case 10:
2812
- this.updateKeyBasedVolume(channel, keyNumber, scheduleTime);
2813
- break;
2814
- case 91:
2815
- this.processScheduledNotes(channel, (note) => {
2816
- if (note.noteNumber === keyNumber) {
2817
- this.setReverbSend(channel, note, scheduleTime);
2818
- }
2819
- });
2820
- break;
2821
- case 93:
2822
- this.processScheduledNotes(channel, (note) => {
2823
- if (note.noteNumber === keyNumber) {
2824
- this.setChorusSend(channel, note, scheduleTime);
2825
- }
2826
- });
2827
- break;
2828
- }
2820
+ const handler = this.keyBasedControllerHandlers[controllerType];
2821
+ if (handler)
2822
+ handler(channel, keyNumber, scheduleTime);
2829
2823
  }
2830
2824
  }
2831
2825
  handleSysEx(data, scheduleTime) {
@@ -2866,7 +2860,6 @@ Object.defineProperty(MidyGM2, "channelSettings", {
2866
2860
  scheduleIndex: 0,
2867
2861
  detune: 0,
2868
2862
  programNumber: 0,
2869
- bank: 121 * 128,
2870
2863
  bankMSB: 121,
2871
2864
  bankLSB: 0,
2872
2865
  dataMSB: 0,
@@ -3,7 +3,6 @@ export class MidyGMLite {
3
3
  scheduleIndex: number;
4
4
  detune: number;
5
5
  programNumber: number;
6
- bank: number;
7
6
  dataMSB: number;
8
7
  dataLSB: number;
9
8
  rpnMSB: number;
@@ -21,7 +20,7 @@ export class MidyGMLite {
21
20
  startTime: number;
22
21
  resumeTime: number;
23
22
  soundFonts: any[];
24
- soundFontTable: any[];
23
+ soundFontTable: never[][];
25
24
  voiceCounter: Map<any, any>;
26
25
  voiceCache: Map<any, any>;
27
26
  isPlaying: boolean;
@@ -39,6 +38,7 @@ export class MidyGMLite {
39
38
  masterVolume: any;
40
39
  scheduler: any;
41
40
  schedulerBuffer: any;
41
+ messageHandlers: any[];
42
42
  voiceParamsHandlers: {
43
43
  modLfoToPitch: (channel: any, note: any, scheduleTime: any) => void;
44
44
  vibLfoToPitch: (_channel: any, _note: any, _scheduleTime: any) => void;
@@ -53,7 +53,6 @@ export class MidyGMLite {
53
53
  };
54
54
  controlChangeHandlers: any[];
55
55
  channels: any[];
56
- initSoundFontTable(): any[];
57
56
  addSoundFont(soundFont: any): void;
58
57
  toUint8Array(input: any): Promise<Uint8Array<ArrayBuffer>>;
59
58
  loadSoundFont(input: any): Promise<void>;
@@ -68,13 +67,14 @@ export class MidyGMLite {
68
67
  createChannels(audioContext: any): any[];
69
68
  createAudioBuffer(voiceParams: any): Promise<any>;
70
69
  createBufferSource(channel: any, voiceParams: any, audioBuffer: any): any;
71
- scheduleTimelineEvents(t: any, resumeTime: any, queueIndex: any): Promise<any>;
70
+ scheduleTimelineEvents(scheduleTime: any, queueIndex: any): Promise<any>;
72
71
  getQueueIndex(second: any): number;
73
72
  resetAllStates(): void;
74
73
  updateStates(queueIndex: any, nextQueueIndex: any): void;
75
74
  playNotes(): Promise<void>;
76
75
  ticksToSecond(ticks: any, secondsPerBeat: any): number;
77
76
  secondToTicks(second: any, secondsPerBeat: any): number;
77
+ getSoundFontId(channel: any): string;
78
78
  extractMidiData(midi: any): {
79
79
  instruments: Set<any>;
80
80
  timeline: any[];
@@ -116,7 +116,9 @@ export class MidyGMLite {
116
116
  findNoteOffIndex(channel: any, noteNumber: any): any;
117
117
  noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): void;
118
118
  releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
119
- handleMIDIMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<void>;
119
+ createMessageHandlers(): any[];
120
+ handleMessage(data: any, scheduleTime: any): void;
121
+ handleChannelMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<void>;
120
122
  setProgramChange(channelNumber: any, programNumber: any, _scheduleTime: any): void;
121
123
  handlePitchBendMessage(channelNumber: any, lsb: any, msb: any, scheduleTime: any): void;
122
124
  setPitchBend(channelNumber: any, value: any, scheduleTime: any): void;
@@ -168,7 +170,7 @@ export class MidyGMLite {
168
170
  GM1SystemOn(scheduleTime: any): void;
169
171
  handleUniversalRealTimeExclusiveMessage(data: any, scheduleTime: any): void;
170
172
  handleMasterVolumeSysEx(data: any, scheduleTime: any): void;
171
- setMasterVolume(volume: any, scheduleTime: any): void;
173
+ setMasterVolume(value: any, scheduleTime: any): void;
172
174
  handleSysEx(data: any, scheduleTime: any): void;
173
175
  scheduleTask(callback: any, scheduleTime: any): Promise<any>;
174
176
  }
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AA0GA;IA4BE;;;;;;;;;;MAUE;IAEF,+BAcC;IArDD,aAAa;IACb,oBAAiB;IACjB,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,4BAAyB;IACzB,0BAAuB;IACvB,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,iBAAY;IACZ,gBAAc;IACd,oBAAkB;IAClB,sBAAwB;IACxB,2BAAqC;IACrC,+BAEE;IAeA,kBAAgC;IAChC,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF;;;;;;;;;;;MAA2D;IAC3D,6BAA+D;IAC/D,gBAAiD;IAMnD,4BAMC;IAED,mCASC;IAED,2DAYC;IAED,yCAmBC;IAED,oCASC;IAED,sBAoCC;IAED,8DAcC;IAED;;;;MAeC;IAED,yCAaC;IAED,kDAUC;IAED,0EAUC;IAED,+EAkDC;IAED,mCAOC;IAED,uBAQC;IAED,yDA2BC;IAED,2BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAgEC;IAED,kGAeC;IAED,mGAeC;IAED,wEAMC;IAED,uBAMC;IAED,sBAKC;IAED,uBAQC;IAED,wBAKC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,yDAQC;IAED,yEASC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,wCAIC;IAED,2DAIC;IAED,+DAIC;IAED,sDAeC;IAED,qDAoBC;IAED,6CAIC;IAED,sDAsBC;IAED,kEAoBC;IAED,6FAyBC;IAED,oGAuCC;IAED,0EAiBC;IAED,8EAiBC;IAED,kGAoCC;IAED,6FASC;IAED,gCASC;IAED,iEAoBC;IAED,qGAkBC;IAED,6CAUC;IAED,qDAUC;IAED,qFASC;IAED,sFAeC;IAED,oGA2BC;IAED,mFAGC;IAED,wFAGC;IAED,sEAUC;IAED,mEAWC;IAED,wDAKC;IAED,sDAOC;IAED,mDAMC;IAED,kDAKC;IAED;;;;;;;;;;;MAiCC;IAED,oFAMC;IAED,6EA2BC;IAED,qCAeC;IAED,+FAWC;IAED,wDASC;IAED,iFAKC;IAED,oEAKC;IAED;;;MAMC;IAED,8DAKC;IAED,4EAKC;IAED,sEAGC;IAED,2DAUC;IAED,yEAWC;IAED,kFAeC;IAED,uDAYC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAUC;IAED,gFAGC;IAED,6CAqBC;IAGD,8EAgCC;IAED,gFAGC;IAED,+EAgBC;IAED,qCAWC;IAED,4EAaC;IAED,4DAGC;IAED,sDASC;IAED,gDAYC;IAGD,6DAgBC;CACF;AArhDD;IAWE,0FAMC;IAhBD,cAAW;IACX,gBAAe;IACf,kBAAa;IACb,gBAAW;IACX,iBAAY;IACZ,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}
1
+ {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AA0GA;IA4BE;;;;;;;;;MASE;IAEF,+BAeC;IArDD,aAAa;IACb,oBAAiB;IACjB,qBAAmB;IACnB,kBAAc;IACd,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,0BAAuD;IACvD,4BAAyB;IACzB,0BAAuB;IACvB,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,iBAAY;IACZ,gBAAc;IACd,oBAAkB;IAClB,sBAAwB;IACxB,2BAAqC;IACrC,+BAEE;IAcA,kBAAgC;IAChC,kBAA8C;IAC9C,eAAwD;IACxD,qBAGE;IACF,uBAAmD;IACnD;;;;;;;;;;;MAA2D;IAC3D,6BAA+D;IAC/D,gBAAiD;IAMnD,mCASC;IAED,2DAYC;IAED,yCAmBC;IAED,oCASC;IAED,sBAoCC;IAED,8DAWC;IAED;;;;MAeC;IAED,yCAaC;IAED,kDAUC;IAED,0EAUC;IAED,yEAqDC;IAED,mCAOC;IAED,uBAQC;IAED,yDA2BC;IAED,2BAwCC;IAED,uDAEC;IAED,wDAEC;IAED,qCAKC;IAED;;;MAwDC;IAED,kGAeC;IAED,mGAeC;IAED,wEAMC;IAED,uBAMC;IAED,sBAKC;IAED,uBAQC;IAED,wBAKC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,yDAQC;IAED,yEASC;IAED,2BAEC;IAED,8BAEC;IAED,8BAEC;IAED,4BAEC;IAED,wCAIC;IAED,2DAIC;IAED,+DAIC;IAED,sDAeC;IAED,qDAoBC;IAED,6CAIC;IAED,sDAsBC;IAED,kEAoBC;IAED,6FAyBC;IAED,oGA2CC;IAED,0EAiBC;IAED,8EAiBC;IAED,kGAiCC;IAED,6FASC;IAED,gCASC;IAED,iEAoBC;IAED,qGAkBC;IAED,6CAUC;IAED,qDAUC;IAED,qFASC;IAED,sFAeC;IAED,+BAmBC;IAED,kDAOC;IAED,uGA2BC;IAED,mFAGC;IAED,wFAGC;IAED,sEAUC;IAED,mEAWC;IAED,wDAKC;IAED,sDAOC;IAED,mDAMC;IAED,kDAKC;IAED;;;;;;;;;;;MAiCC;IAED,oFAMC;IAED,6EA2BC;IAED,qCAeC;IAED,+FAWC;IAED,wDASC;IAED,iFAKC;IAED,oEAKC;IAED;;;MAMC;IAED,8DAKC;IAED,4EAKC;IAED,sEAGC;IAED,2DAUC;IAED,yEAWC;IAED,kFAeC;IAED,uDAYC;IAED,gDAEC;IAED,gDAEC;IAED,sEAGC;IAED,qEAKC;IAED,2EAUC;IAED,gFAGC;IAED,6CAqBC;IAGD,8EAgCC;IAED,gFAGC;IAED,+EAgBC;IAED,qCASC;IAED,4EAaC;IAED,4DAGC;IAED,qDAKC;IAED,gDAYC;IAGD,6DAgBC;CACF;AA9hDD;IAWE,0FAMC;IAhBD,cAAW;IACX,gBAAe;IACf,kBAAa;IACb,gBAAW;IACX,iBAAY;IACZ,wBAAmB;IACnB,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAGd,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,WAAkB;IAClB,iBAA8B;CAEjC"}