@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.
@@ -275,6 +275,18 @@ class MidyGM2 {
275
275
  writable: true,
276
276
  value: 0
277
277
  });
278
+ Object.defineProperty(this, "lastActiveSensing", {
279
+ enumerable: true,
280
+ configurable: true,
281
+ writable: true,
282
+ value: 0
283
+ });
284
+ Object.defineProperty(this, "activeSensingThreshold", {
285
+ enumerable: true,
286
+ configurable: true,
287
+ writable: true,
288
+ value: 0.3
289
+ });
278
290
  Object.defineProperty(this, "noteCheckInterval", {
279
291
  enumerable: true,
280
292
  configurable: true,
@@ -315,7 +327,7 @@ class MidyGM2 {
315
327
  enumerable: true,
316
328
  configurable: true,
317
329
  writable: true,
318
- value: this.initSoundFontTable()
330
+ value: Array.from({ length: 128 }, () => [])
319
331
  });
320
332
  Object.defineProperty(this, "voiceCounter", {
321
333
  enumerable: true,
@@ -402,8 +414,10 @@ class MidyGM2 {
402
414
  length: 1,
403
415
  sampleRate: audioContext.sampleRate,
404
416
  });
417
+ this.messageHandlers = this.createMessageHandlers();
405
418
  this.voiceParamsHandlers = this.createVoiceParamsHandlers();
406
419
  this.controlChangeHandlers = this.createControlChangeHandlers();
420
+ this.keyBasedControllerHandlers = this.createKeyBasedControllerHandlers();
407
421
  this.channels = this.createChannels(audioContext);
408
422
  this.reverbEffect = this.createReverbEffect(audioContext);
409
423
  this.chorusEffect = this.createChorusEffect(audioContext);
@@ -413,21 +427,14 @@ class MidyGM2 {
413
427
  this.scheduler.connect(audioContext.destination);
414
428
  this.GM2SystemOn();
415
429
  }
416
- initSoundFontTable() {
417
- const table = new Array(128);
418
- for (let i = 0; i < 128; i++) {
419
- table[i] = new Map();
420
- }
421
- return table;
422
- }
423
430
  addSoundFont(soundFont) {
424
431
  const index = this.soundFonts.length;
425
432
  this.soundFonts.push(soundFont);
426
433
  const presetHeaders = soundFont.parsed.presetHeaders;
434
+ const soundFontTable = this.soundFontTable;
427
435
  for (let i = 0; i < presetHeaders.length; i++) {
428
- const presetHeader = presetHeaders[i];
429
- const banks = this.soundFontTable[presetHeader.preset];
430
- banks.set(presetHeader.bank, index);
436
+ const { preset, bank } = presetHeaders[i];
437
+ soundFontTable[preset][bank] = index;
431
438
  }
432
439
  }
433
440
  async toUint8Array(input) {
@@ -505,13 +512,17 @@ class MidyGM2 {
505
512
  this.GM2SystemOn();
506
513
  }
507
514
  getVoiceId(channel, noteNumber, velocity) {
508
- const bankNumber = this.calcBank(channel);
509
- const soundFontIndex = this.soundFontTable[channel.programNumber]
510
- .get(bankNumber);
515
+ const programNumber = channel.programNumber;
516
+ const bankTable = this.soundFontTable[programNumber];
517
+ if (!bankTable)
518
+ return;
519
+ const bankLSB = channel.isDrum ? 128 : channel.bankLSB;
520
+ const bank = bankTable[bankLSB] !== undefined ? bankLSB : 0;
521
+ const soundFontIndex = bankTable[bank];
511
522
  if (soundFontIndex === undefined)
512
523
  return;
513
524
  const soundFont = this.soundFonts[soundFontIndex];
514
- const voice = soundFont.getVoice(bankNumber, channel.programNumber, noteNumber, velocity);
525
+ const voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
515
526
  const { instrument, sampleID } = voice.generators;
516
527
  return soundFontIndex * (2 ** 32) + (instrument << 16) + sampleID;
517
528
  }
@@ -580,13 +591,16 @@ class MidyGM2 {
580
591
  }
581
592
  return bufferSource;
582
593
  }
583
- async scheduleTimelineEvents(t, resumeTime, queueIndex) {
584
- while (queueIndex < this.timeline.length) {
585
- const event = this.timeline[queueIndex];
586
- if (event.startTime > t + this.lookAhead)
594
+ async scheduleTimelineEvents(scheduleTime, queueIndex) {
595
+ const timeOffset = this.resumeTime - this.startTime;
596
+ const lookAheadCheckTime = scheduleTime + timeOffset + this.lookAhead;
597
+ const schedulingOffset = this.startDelay - timeOffset;
598
+ const timeline = this.timeline;
599
+ while (queueIndex < timeline.length) {
600
+ const event = timeline[queueIndex];
601
+ if (lookAheadCheckTime < event.startTime)
587
602
  break;
588
- const delay = this.startDelay - resumeTime;
589
- const startTime = event.startTime + delay;
603
+ const startTime = event.startTime + schedulingOffset;
590
604
  switch (event.type) {
591
605
  case "noteOn":
592
606
  await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime);
@@ -661,13 +675,18 @@ class MidyGM2 {
661
675
  this.isPaused = false;
662
676
  this.startTime = this.audioContext.currentTime;
663
677
  let queueIndex = this.getQueueIndex(this.resumeTime);
664
- let resumeTime = this.resumeTime - this.startTime;
665
678
  let finished = false;
666
679
  this.notePromises = [];
667
680
  while (queueIndex < this.timeline.length) {
668
681
  const now = this.audioContext.currentTime;
669
- const t = now + resumeTime;
670
- queueIndex = await this.scheduleTimelineEvents(t, resumeTime, queueIndex);
682
+ if (0 < this.lastActiveSensing &&
683
+ this.activeSensingThreshold < performance.now() - this.lastActiveSensing) {
684
+ await this.stopNotes(0, true, now);
685
+ await this.audioContext.suspend();
686
+ finished = true;
687
+ break;
688
+ }
689
+ queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
671
690
  if (this.isPausing) {
672
691
  await this.stopNotes(0, true, now);
673
692
  await this.audioContext.suspend();
@@ -686,7 +705,6 @@ class MidyGM2 {
686
705
  const nextQueueIndex = this.getQueueIndex(this.resumeTime);
687
706
  this.updateStates(queueIndex, nextQueueIndex);
688
707
  queueIndex = nextQueueIndex;
689
- resumeTime = this.resumeTime - this.startTime;
690
708
  this.isSeeking = false;
691
709
  continue;
692
710
  }
@@ -696,6 +714,7 @@ class MidyGM2 {
696
714
  if (finished) {
697
715
  this.notePromises = [];
698
716
  this.resetAllStates();
717
+ this.lastActiveSensing = 0;
699
718
  }
700
719
  this.isPlaying = false;
701
720
  }
@@ -705,17 +724,17 @@ class MidyGM2 {
705
724
  secondToTicks(second, secondsPerBeat) {
706
725
  return second * this.ticksPerBeat / secondsPerBeat;
707
726
  }
727
+ getSoundFontId(channel) {
728
+ const programNumber = channel.programNumber;
729
+ const bankNumber = channel.isDrum ? 128 : channel.bankLSB;
730
+ const bank = bankNumber.toString().padStart(3, "0");
731
+ const program = programNumber.toString().padStart(3, "0");
732
+ return `${bank}:${program}`;
733
+ }
708
734
  extractMidiData(midi) {
709
735
  const instruments = new Set();
710
736
  const timeline = [];
711
- const tmpChannels = new Array(this.channels.length);
712
- for (let i = 0; i < tmpChannels.length; i++) {
713
- tmpChannels[i] = {
714
- programNumber: -1,
715
- bankMSB: this.channels[i].bankMSB,
716
- bankLSB: this.channels[i].bankLSB,
717
- };
718
- }
737
+ const channels = this.channels;
719
738
  for (let i = 0; i < midi.tracks.length; i++) {
720
739
  const track = midi.tracks[i];
721
740
  let currentTicks = 0;
@@ -725,48 +744,40 @@ class MidyGM2 {
725
744
  event.ticks = currentTicks;
726
745
  switch (event.type) {
727
746
  case "noteOn": {
728
- const channel = tmpChannels[event.channel];
729
- if (channel.programNumber < 0) {
730
- channel.programNumber = event.programNumber;
731
- switch (channel.bankMSB) {
732
- case 120:
733
- instruments.add(`128:0`);
734
- break;
735
- case 121:
736
- instruments.add(`${channel.bankLSB}:0`);
737
- break;
738
- default: {
739
- const bankNumber = channel.bankMSB * 128 + channel.bankLSB;
740
- instruments.add(`${bankNumber}:0`);
741
- }
742
- }
743
- channel.programNumber = 0;
744
- }
747
+ const channel = channels[event.channel];
748
+ instruments.add(this.getSoundFontId(channel));
745
749
  break;
746
750
  }
747
751
  case "controller":
748
752
  switch (event.controllerType) {
749
753
  case 0:
750
- tmpChannels[event.channel].bankMSB = event.value;
754
+ this.setBankMSB(event.channel, event.value);
751
755
  break;
752
756
  case 32:
753
- tmpChannels[event.channel].bankLSB = event.value;
757
+ this.setBankLSB(event.channel, event.value);
754
758
  break;
755
759
  }
756
760
  break;
757
761
  case "programChange": {
758
- const channel = tmpChannels[event.channel];
759
- channel.programNumber = event.programNumber;
760
- switch (channel.bankMSB) {
761
- case 120:
762
- instruments.add(`128:${channel.programNumber}`);
763
- break;
764
- case 121:
765
- instruments.add(`${channel.bankLSB}:${channel.programNumber}`);
766
- break;
767
- default: {
768
- const bankNumber = channel.bankMSB * 128 + channel.bankLSB;
769
- instruments.add(`${bankNumber}:${channel.programNumber}`);
762
+ const channel = channels[event.channel];
763
+ this.setProgramChange(event.channel, event.programNumber);
764
+ instruments.add(this.getSoundFontId(channel));
765
+ break;
766
+ }
767
+ case "sysEx": {
768
+ const data = event.data;
769
+ if (data[0] === 126 && data[1] === 9 && data[2] === 3) {
770
+ switch (data[3]) {
771
+ case 1:
772
+ this.GM1SystemOn(scheduleTime);
773
+ break;
774
+ case 2: // GM System Off
775
+ break;
776
+ case 3:
777
+ this.GM2SystemOn(scheduleTime);
778
+ break;
779
+ default:
780
+ console.warn(`Unsupported Exclusive Message: ${data}`);
770
781
  }
771
782
  }
772
783
  }
@@ -1089,7 +1100,7 @@ class MidyGM2 {
1089
1100
  updateDetune(channel, note, scheduleTime) {
1090
1101
  const noteDetune = this.calcNoteDetune(channel, note);
1091
1102
  const detune = channel.detune + noteDetune;
1092
- if (0.5 <= channel.state.portamento && 0 <= note.portamentoNoteNumber) {
1103
+ if (this.isPortamento(channel, note)) {
1093
1104
  const startTime = note.startTime;
1094
1105
  const deltaCent = (note.noteNumber - note.portamentoNoteNumber) * 100;
1095
1106
  const portamentoTime = startTime + this.getPortamentoTime(channel, note);
@@ -1340,7 +1351,7 @@ class MidyGM2 {
1340
1351
  if (prevNote && prevNote.noteNumber !== noteNumber) {
1341
1352
  note.portamentoNoteNumber = prevNote.noteNumber;
1342
1353
  }
1343
- if (0.5 <= channel.state.portamento && 0 <= note.portamentoNoteNumber) {
1354
+ if (!channel.isDrum && this.isPortamento(channel, note)) {
1344
1355
  this.setPortamentoVolumeEnvelope(channel, note, now);
1345
1356
  this.setPortamentoFilterEnvelope(channel, note, now);
1346
1357
  this.setPortamentoPitchEnvelope(note, now);
@@ -1368,22 +1379,6 @@ class MidyGM2 {
1368
1379
  note.bufferSource.start(startTime);
1369
1380
  return note;
1370
1381
  }
1371
- calcBank(channel) {
1372
- switch (this.mode) {
1373
- case "GM1":
1374
- if (channel.isDrum)
1375
- return 128;
1376
- return 0;
1377
- case "GM2":
1378
- if (channel.bankMSB === 121)
1379
- return 0;
1380
- if (channel.isDrum)
1381
- return 128;
1382
- return channel.bank;
1383
- default:
1384
- return channel.bank;
1385
- }
1386
- }
1387
1382
  handleExclusiveClass(note, channelNumber, startTime) {
1388
1383
  const exclusiveClass = note.voiceParams.exclusiveClass;
1389
1384
  if (exclusiveClass === 0)
@@ -1419,13 +1414,17 @@ class MidyGM2 {
1419
1414
  }
1420
1415
  async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
1421
1416
  const channel = this.channels[channelNumber];
1422
- const bankNumber = this.calcBank(channel, channelNumber);
1423
- const soundFontIndex = this.soundFontTable[channel.programNumber]
1424
- .get(bankNumber);
1417
+ const programNumber = channel.programNumber;
1418
+ const bankTable = this.soundFontTable[programNumber];
1419
+ if (!bankTable)
1420
+ return;
1421
+ const bankLSB = channel.isDrum ? 128 : channel.bankLSB;
1422
+ const bank = bankTable[bankLSB] !== undefined ? bankLSB : 0;
1423
+ const soundFontIndex = bankTable[bank];
1425
1424
  if (soundFontIndex === undefined)
1426
1425
  return;
1427
1426
  const soundFont = this.soundFonts[soundFontIndex];
1428
- const voice = soundFont.getVoice(bankNumber, channel.programNumber, noteNumber, velocity);
1427
+ const voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
1429
1428
  if (!voice)
1430
1429
  return;
1431
1430
  const note = await this.createNote(channel, voice, noteNumber, velocity, startTime);
@@ -1577,41 +1576,45 @@ class MidyGM2 {
1577
1576
  channel.sostenutoNotes = [];
1578
1577
  return promises;
1579
1578
  }
1580
- handleMIDIMessage(statusByte, data1, data2, scheduleTime) {
1581
- const channelNumber = statusByte & 0x0F;
1582
- const messageType = statusByte & 0xF0;
1583
- switch (messageType) {
1584
- case 0x80:
1585
- return this.noteOff(channelNumber, data1, data2, scheduleTime);
1586
- case 0x90:
1587
- return this.noteOn(channelNumber, data1, data2, scheduleTime);
1588
- case 0xB0:
1589
- return this.setControlChange(channelNumber, data1, data2, scheduleTime);
1590
- case 0xC0:
1591
- return this.setProgramChange(channelNumber, data1, scheduleTime);
1592
- case 0xD0:
1593
- return this.setChannelPressure(channelNumber, data1, scheduleTime);
1594
- case 0xE0:
1595
- return this.handlePitchBendMessage(channelNumber, data1, data2, scheduleTime);
1596
- default:
1597
- console.warn(`Unsupported MIDI message: ${messageType.toString(16)}`);
1579
+ createMessageHandlers() {
1580
+ const handlers = new Array(256);
1581
+ // Channel Message
1582
+ handlers[0x80] = (data, scheduleTime) => this.noteOff(data[0] & 0x0F, data[1], data[2], scheduleTime);
1583
+ handlers[0x90] = (data, scheduleTime) => this.noteOn(data[0] & 0x0F, data[1], data[2], scheduleTime);
1584
+ handlers[0xB0] = (data, scheduleTime) => this.setControlChange(data[0] & 0x0F, data[1], data[2], scheduleTime);
1585
+ handlers[0xC0] = (data, scheduleTime) => this.setProgramChange(data[0] & 0x0F, data[1], scheduleTime);
1586
+ handlers[0xD0] = (data, scheduleTime) => this.setChannelPressure(data[0] & 0x0F, data[1], scheduleTime);
1587
+ handlers[0xE0] = (data, scheduleTime) => this.handlePitchBendMessage(data[0] & 0x0F, data[1], data[2], scheduleTime);
1588
+ // System Real Time Message
1589
+ handlers[0xFE] = (_data, _scheduleTime) => this.activeSensing();
1590
+ return handlers;
1591
+ }
1592
+ handleMessage(data, scheduleTime) {
1593
+ const status = data[0];
1594
+ if (status === 0xF0) {
1595
+ return this.handleSysEx(data.subarray(1), scheduleTime);
1598
1596
  }
1597
+ const handler = this.messageHandlers[status];
1598
+ if (handler)
1599
+ handler(data, scheduleTime);
1600
+ }
1601
+ activeSensing() {
1602
+ this.lastActiveSensing = performance.now();
1599
1603
  }
1600
1604
  setProgramChange(channelNumber, programNumber, _scheduleTime) {
1601
1605
  const channel = this.channels[channelNumber];
1602
- channel.bank = channel.bankMSB * 128 + channel.bankLSB;
1603
1606
  channel.programNumber = programNumber;
1604
1607
  if (this.mode === "GM2") {
1605
1608
  switch (channel.bankMSB) {
1606
1609
  case 120:
1607
1610
  channel.isDrum = true;
1611
+ channel.keyBasedTable.fill(-1);
1608
1612
  break;
1609
1613
  case 121:
1610
1614
  channel.isDrum = false;
1611
1615
  break;
1612
1616
  }
1613
1617
  }
1614
- channel.keyBasedTable.fill(-1);
1615
1618
  }
1616
1619
  setChannelPressure(channelNumber, value, scheduleTime) {
1617
1620
  const channel = this.channels[channelNumber];
@@ -1936,22 +1939,20 @@ class MidyGM2 {
1936
1939
  this.updateModulation(channel, scheduleTime);
1937
1940
  }
1938
1941
  updatePortamento(channel, scheduleTime) {
1942
+ if (channel.isDrum)
1943
+ return;
1939
1944
  this.processScheduledNotes(channel, (note) => {
1940
- if (0.5 <= channel.state.portamento) {
1941
- if (0 <= note.portamentoNoteNumber) {
1942
- this.setPortamentoVolumeEnvelope(channel, note, scheduleTime);
1943
- this.setPortamentoFilterEnvelope(channel, note, scheduleTime);
1944
- this.setPortamentoPitchEnvelope(note, scheduleTime);
1945
- this.updateDetune(channel, note, scheduleTime);
1946
- }
1945
+ if (this.isPortamento(channel, note)) {
1946
+ this.setPortamentoVolumeEnvelope(channel, note, scheduleTime);
1947
+ this.setPortamentoFilterEnvelope(channel, note, scheduleTime);
1948
+ this.setPortamentoPitchEnvelope(note, scheduleTime);
1949
+ this.updateDetune(channel, note, scheduleTime);
1947
1950
  }
1948
1951
  else {
1949
- if (0 <= note.portamentoNoteNumber) {
1950
- this.setVolumeEnvelope(channel, note, scheduleTime);
1951
- this.setFilterEnvelope(channel, note, scheduleTime);
1952
- this.setPitchEnvelope(note, scheduleTime);
1953
- this.updateDetune(channel, note, scheduleTime);
1954
- }
1952
+ this.setVolumeEnvelope(channel, note, scheduleTime);
1953
+ this.setFilterEnvelope(channel, note, scheduleTime);
1954
+ this.setPitchEnvelope(note, scheduleTime);
1955
+ this.updateDetune(channel, note, scheduleTime);
1955
1956
  }
1956
1957
  });
1957
1958
  }
@@ -2057,6 +2058,9 @@ class MidyGM2 {
2057
2058
  this.releaseSustainPedal(channelNumber, value, scheduleTime);
2058
2059
  }
2059
2060
  }
2061
+ isPortamento(channel, note) {
2062
+ return 0.5 <= channel.state.portamento && 0 <= note.portamentoNoteNumber;
2063
+ }
2060
2064
  setPortamento(channelNumber, value, scheduleTime) {
2061
2065
  const channel = this.channels[channelNumber];
2062
2066
  if (channel.isDrum)
@@ -2093,7 +2097,7 @@ class MidyGM2 {
2093
2097
  scheduleTime ??= this.audioContext.currentTime;
2094
2098
  state.softPedal = softPedal / 127;
2095
2099
  this.processScheduledNotes(channel, (note) => {
2096
- if (0.5 <= state.portamento && 0 <= note.portamentoNoteNumber) {
2100
+ if (this.isPortamento(channel, note)) {
2097
2101
  this.setPortamentoVolumeEnvelope(channel, note, scheduleTime);
2098
2102
  this.setPortamentoFilterEnvelope(channel, note, scheduleTime);
2099
2103
  }
@@ -2361,11 +2365,9 @@ class MidyGM2 {
2361
2365
  const channel = this.channels[i];
2362
2366
  channel.bankMSB = 0;
2363
2367
  channel.bankLSB = 0;
2364
- channel.bank = 0;
2365
2368
  channel.isDrum = false;
2366
2369
  }
2367
2370
  this.channels[9].bankMSB = 1;
2368
- this.channels[9].bank = 128;
2369
2371
  this.channels[9].isDrum = true;
2370
2372
  }
2371
2373
  GM2SystemOn(scheduleTime) {
@@ -2376,11 +2378,9 @@ class MidyGM2 {
2376
2378
  const channel = this.channels[i];
2377
2379
  channel.bankMSB = 121;
2378
2380
  channel.bankLSB = 0;
2379
- channel.bank = 121 * 128;
2380
2381
  channel.isDrum = false;
2381
2382
  }
2382
2383
  this.channels[9].bankMSB = 120;
2383
- this.channels[9].bank = 120 * 128;
2384
2384
  this.channels[9].isDrum = true;
2385
2385
  }
2386
2386
  handleUniversalRealTimeExclusiveMessage(data, scheduleTime) {
@@ -2425,16 +2425,11 @@ class MidyGM2 {
2425
2425
  const volume = (data[5] * 128 + data[4]) / 16383;
2426
2426
  this.setMasterVolume(volume, scheduleTime);
2427
2427
  }
2428
- setMasterVolume(volume, scheduleTime) {
2428
+ setMasterVolume(value, scheduleTime) {
2429
2429
  scheduleTime ??= this.audioContext.currentTime;
2430
- if (volume < 0 && 1 < volume) {
2431
- console.error("Master Volume is out of range");
2432
- }
2433
- else {
2434
- this.masterVolume.gain
2435
- .cancelScheduledValues(scheduleTime)
2436
- .setValueAtTime(volume * volume, scheduleTime);
2437
- }
2430
+ this.masterVolume.gain
2431
+ .cancelScheduledValues(scheduleTime)
2432
+ .setValueAtTime(value * value, scheduleTime);
2438
2433
  }
2439
2434
  handleMasterFineTuningSysEx(data, scheduleTime) {
2440
2435
  const value = (data[5] * 128 + data[4]) / 16383;
@@ -2797,6 +2792,22 @@ class MidyGM2 {
2797
2792
  const controlValue = channel.keyBasedTable[index];
2798
2793
  return controlValue;
2799
2794
  }
2795
+ createKeyBasedControllerHandlers() {
2796
+ const handlers = new Array(128);
2797
+ handlers[7] = (channel, keyNumber, scheduleTime) => this.updateKeyBasedVolume(channel, keyNumber, scheduleTime);
2798
+ handlers[10] = (channel, keyNumber, scheduleTime) => this.updateKeyBasedVolume(channel, keyNumber, scheduleTime);
2799
+ handlers[91] = (channel, keyNumber, scheduleTime) => this.processScheduledNotes(channel, (note) => {
2800
+ if (note.noteNumber === keyNumber) {
2801
+ this.setReverbSend(channel, note, scheduleTime);
2802
+ }
2803
+ });
2804
+ handlers[93] = (channel, keyNumber, scheduleTime) => this.processScheduledNotes(channel, (note) => {
2805
+ if (note.noteNumber === keyNumber) {
2806
+ this.setChorusSend(channel, note, scheduleTime);
2807
+ }
2808
+ });
2809
+ return handlers;
2810
+ }
2800
2811
  handleKeyBasedInstrumentControlSysEx(data, scheduleTime) {
2801
2812
  const channelNumber = data[4];
2802
2813
  const channel = this.channels[channelNumber];
@@ -2809,26 +2820,9 @@ class MidyGM2 {
2809
2820
  const value = data[i + 1];
2810
2821
  const index = keyNumber * 128 + controllerType;
2811
2822
  table[index] = value;
2812
- switch (controllerType) {
2813
- case 7:
2814
- case 10:
2815
- this.updateKeyBasedVolume(channel, keyNumber, scheduleTime);
2816
- break;
2817
- case 91:
2818
- this.processScheduledNotes(channel, (note) => {
2819
- if (note.noteNumber === keyNumber) {
2820
- this.setReverbSend(channel, note, scheduleTime);
2821
- }
2822
- });
2823
- break;
2824
- case 93:
2825
- this.processScheduledNotes(channel, (note) => {
2826
- if (note.noteNumber === keyNumber) {
2827
- this.setChorusSend(channel, note, scheduleTime);
2828
- }
2829
- });
2830
- break;
2831
- }
2823
+ const handler = this.keyBasedControllerHandlers[controllerType];
2824
+ if (handler)
2825
+ handler(channel, keyNumber, scheduleTime);
2832
2826
  }
2833
2827
  }
2834
2828
  handleSysEx(data, scheduleTime) {
@@ -2870,7 +2864,6 @@ Object.defineProperty(MidyGM2, "channelSettings", {
2870
2864
  scheduleIndex: 0,
2871
2865
  detune: 0,
2872
2866
  programNumber: 0,
2873
- bank: 121 * 128,
2874
2867
  bankMSB: 121,
2875
2868
  bankLSB: 0,
2876
2869
  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"}