@marmooo/midy 0.3.8 → 0.4.1

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
@@ -1,7 +1,19 @@
1
1
  import { parseMidi } from "midi-file";
2
2
  import { parse, SoundFont } from "@marmooo/soundfont-parser";
3
3
  class Note {
4
- constructor(noteNumber, velocity, startTime, voice, voiceParams) {
4
+ constructor(noteNumber, velocity, startTime) {
5
+ Object.defineProperty(this, "voice", {
6
+ enumerable: true,
7
+ configurable: true,
8
+ writable: true,
9
+ value: void 0
10
+ });
11
+ Object.defineProperty(this, "voiceParams", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: void 0
16
+ });
5
17
  Object.defineProperty(this, "index", {
6
18
  enumerable: true,
7
19
  configurable: true,
@@ -14,6 +26,12 @@ class Note {
14
26
  writable: true,
15
27
  value: false
16
28
  });
29
+ Object.defineProperty(this, "pending", {
30
+ enumerable: true,
31
+ configurable: true,
32
+ writable: true,
33
+ value: true
34
+ });
17
35
  Object.defineProperty(this, "bufferSource", {
18
36
  enumerable: true,
19
37
  configurable: true,
@@ -89,8 +107,6 @@ class Note {
89
107
  this.noteNumber = noteNumber;
90
108
  this.velocity = velocity;
91
109
  this.startTime = startTime;
92
- this.voice = voice;
93
- this.voiceParams = voiceParams;
94
110
  }
95
111
  }
96
112
  const drumExclusiveClassesByKit = new Array(57);
@@ -135,12 +151,12 @@ const defaultControllerState = {
135
151
  pitchWheelSensitivity: { type: 16, defaultValue: 2 / 128 },
136
152
  link: { type: 127, defaultValue: 0 },
137
153
  // bankMSB: { type: 128 + 0, defaultValue: 121, },
138
- modulationDepth: { type: 128 + 1, defaultValue: 0 },
139
- portamentoTime: { type: 128 + 5, defaultValue: 0 },
154
+ modulationDepthMSB: { type: 128 + 1, defaultValue: 0 },
155
+ portamentoTimeMSB: { type: 128 + 5, defaultValue: 0 },
140
156
  // dataMSB: { type: 128 + 6, defaultValue: 0, },
141
- volume: { type: 128 + 7, defaultValue: 100 / 127 },
142
- pan: { type: 128 + 10, defaultValue: 64 / 127 },
143
- expression: { type: 128 + 11, defaultValue: 1 },
157
+ volumeMSB: { type: 128 + 7, defaultValue: 100 / 127 },
158
+ panMSB: { type: 128 + 10, defaultValue: 64 / 127 },
159
+ expressionMSB: { type: 128 + 11, defaultValue: 1 },
144
160
  // bankLSB: { type: 128 + 32, defaultValue: 0, },
145
161
  // dataLSB: { type: 128 + 38, defaultValue: 0, },
146
162
  sustainPedal: { type: 128 + 64, defaultValue: 0 },
@@ -338,6 +354,12 @@ export class MidyGM2 {
338
354
  writable: true,
339
355
  value: new Map()
340
356
  });
357
+ Object.defineProperty(this, "realtimeVoiceCache", {
358
+ enumerable: true,
359
+ configurable: true,
360
+ writable: true,
361
+ value: new Map()
362
+ });
341
363
  Object.defineProperty(this, "isPlaying", {
342
364
  enumerable: true,
343
365
  configurable: true,
@@ -524,7 +546,7 @@ export class MidyGM2 {
524
546
  return soundFontIndex * (2 ** 32) + (instrument << 16) + sampleID;
525
547
  }
526
548
  createChannelAudioNodes(audioContext) {
527
- const { gainLeft, gainRight } = this.panToGain(defaultControllerState.pan.defaultValue);
549
+ const { gainLeft, gainRight } = this.panToGain(defaultControllerState.panMSB.defaultValue);
528
550
  const gainL = new GainNode(audioContext, { gain: gainLeft });
529
551
  const gainR = new GainNode(audioContext, { gain: gainRight });
530
552
  const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
@@ -565,10 +587,9 @@ export class MidyGM2 {
565
587
  return channels;
566
588
  }
567
589
  async createAudioBuffer(voiceParams) {
568
- const sample = voiceParams.sample;
569
- const sampleStart = voiceParams.start;
570
- const sampleEnd = sample.data.length + voiceParams.end;
571
- const audioBuffer = await sample.toAudioBuffer(this.audioContext, sampleStart, sampleEnd);
590
+ const { sample, start, end } = voiceParams;
591
+ const sampleEnd = sample.data.length + end;
592
+ const audioBuffer = await sample.toAudioBuffer(this.audioContext, start, sampleEnd);
572
593
  return audioBuffer;
573
594
  }
574
595
  isLoopDrum(channel, noteNumber) {
@@ -600,12 +621,10 @@ export class MidyGM2 {
600
621
  const startTime = event.startTime + schedulingOffset;
601
622
  switch (event.type) {
602
623
  case "noteOn":
603
- await this.scheduleNoteOn(event.channel, event.noteNumber, event.velocity, startTime);
624
+ await this.noteOn(event.channel, event.noteNumber, event.velocity, startTime);
604
625
  break;
605
626
  case "noteOff": {
606
- const notePromise = this.scheduleNoteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
607
- if (notePromise)
608
- this.notePromises.push(notePromise);
627
+ this.noteOff(event.channel, event.noteNumber, event.velocity, startTime, false);
609
628
  break;
610
629
  }
611
630
  case "controller":
@@ -639,6 +658,7 @@ export class MidyGM2 {
639
658
  this.exclusiveClassNotes.fill(undefined);
640
659
  this.drumExclusiveClassNotes.fill(undefined);
641
660
  this.voiceCache.clear();
661
+ this.realtimeVoiceCache.clear();
642
662
  for (let i = 0; i < this.channels.length; i++) {
643
663
  this.channels[i].scheduledNotes = [];
644
664
  this.resetChannelStates(i);
@@ -683,7 +703,6 @@ export class MidyGM2 {
683
703
  finished = true;
684
704
  break;
685
705
  }
686
- queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
687
706
  if (this.isPausing) {
688
707
  await this.stopNotes(0, true, now);
689
708
  await this.audioContext.suspend();
@@ -705,9 +724,16 @@ export class MidyGM2 {
705
724
  this.isSeeking = false;
706
725
  continue;
707
726
  }
727
+ queueIndex = await this.scheduleTimelineEvents(now, queueIndex);
708
728
  const waitTime = now + this.noteCheckInterval;
709
729
  await this.scheduleTask(() => { }, waitTime);
710
730
  }
731
+ if (this.timeline.length <= queueIndex) {
732
+ const now = this.audioContext.currentTime;
733
+ await this.stopNotes(0, true, now);
734
+ await this.audioContext.suspend();
735
+ finished = true;
736
+ }
711
737
  if (finished) {
712
738
  this.notePromises = [];
713
739
  this.resetAllStates();
@@ -813,7 +839,7 @@ export class MidyGM2 {
813
839
  const channel = this.channels[channelNumber];
814
840
  const promises = [];
815
841
  this.processActiveNotes(channel, scheduleTime, (note) => {
816
- const promise = this.scheduleNoteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
842
+ const promise = this.noteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
817
843
  this.notePromises.push(promise);
818
844
  promises.push(promise);
819
845
  });
@@ -823,7 +849,7 @@ export class MidyGM2 {
823
849
  const channel = this.channels[channelNumber];
824
850
  const promises = [];
825
851
  this.processScheduledNotes(channel, (note) => {
826
- const promise = this.scheduleNoteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
852
+ const promise = this.noteOff(channelNumber, note.noteNumber, velocity, scheduleTime, force);
827
853
  this.notePromises.push(promise);
828
854
  promises.push(promise);
829
855
  });
@@ -856,7 +882,7 @@ export class MidyGM2 {
856
882
  if (!this.isPlaying || this.isPaused)
857
883
  return;
858
884
  const now = this.audioContext.currentTime;
859
- this.resumeTime += now - this.startTime - this.startDelay;
885
+ this.resumeTime = now - this.startTime - this.startDelay;
860
886
  this.isPausing = true;
861
887
  await this.playPromise;
862
888
  this.isPausing = false;
@@ -882,11 +908,13 @@ export class MidyGM2 {
882
908
  if (totalTime < event.startTime)
883
909
  totalTime = event.startTime;
884
910
  }
885
- return totalTime;
911
+ return totalTime + this.startDelay;
886
912
  }
887
913
  currentTime() {
914
+ if (!this.isPlaying)
915
+ return this.resumeTime;
888
916
  const now = this.audioContext.currentTime;
889
- return this.resumeTime + now - this.startTime - this.startDelay;
917
+ return now + this.resumeTime - this.startTime;
890
918
  }
891
919
  processScheduledNotes(channel, callback) {
892
920
  const scheduledNotes = channel.scheduledNotes;
@@ -1114,7 +1142,7 @@ export class MidyGM2 {
1114
1142
  }
1115
1143
  getPortamentoTime(channel, note) {
1116
1144
  const deltaSemitone = Math.abs(note.noteNumber - note.portamentoNoteNumber);
1117
- const value = Math.ceil(channel.state.portamentoTime * 127);
1145
+ const value = Math.ceil(channel.state.portamentoTimeMSB * 127);
1118
1146
  return deltaSemitone / this.getPitchIncrementSpeed(value) / 10;
1119
1147
  }
1120
1148
  getPitchIncrementSpeed(value) {
@@ -1313,31 +1341,42 @@ export class MidyGM2 {
1313
1341
  note.vibratoLFO.connect(note.vibratoDepth);
1314
1342
  note.vibratoDepth.connect(note.bufferSource.detune);
1315
1343
  }
1316
- async getAudioBuffer(channel, noteNumber, velocity, voiceParams) {
1344
+ async getAudioBuffer(channel, noteNumber, velocity, voiceParams, realtime) {
1317
1345
  const audioBufferId = this.getVoiceId(channel, noteNumber, velocity);
1318
- const cache = this.voiceCache.get(audioBufferId);
1319
- if (cache) {
1320
- cache.counter += 1;
1321
- if (cache.maxCount <= cache.counter) {
1322
- this.voiceCache.delete(audioBufferId);
1323
- }
1324
- return cache.audioBuffer;
1325
- }
1326
- else {
1327
- const maxCount = this.voiceCounter.get(audioBufferId) ?? 0;
1346
+ if (realtime) {
1347
+ const cachedAudioBuffer = this.realtimeVoiceCache.get(audioBufferId);
1348
+ if (cachedAudioBuffer)
1349
+ return cachedAudioBuffer;
1328
1350
  const audioBuffer = await this.createAudioBuffer(voiceParams);
1329
- const cache = { audioBuffer, maxCount, counter: 1 };
1330
- this.voiceCache.set(audioBufferId, cache);
1351
+ this.realtimeVoiceCache.set(audioBufferId, audioBuffer);
1331
1352
  return audioBuffer;
1332
1353
  }
1354
+ else {
1355
+ const cache = this.voiceCache.get(audioBufferId);
1356
+ if (cache) {
1357
+ cache.counter += 1;
1358
+ if (cache.maxCount <= cache.counter) {
1359
+ this.voiceCache.delete(audioBufferId);
1360
+ }
1361
+ return cache.audioBuffer;
1362
+ }
1363
+ else {
1364
+ const maxCount = this.voiceCounter.get(audioBufferId) ?? 0;
1365
+ const audioBuffer = await this.createAudioBuffer(voiceParams);
1366
+ const cache = { audioBuffer, maxCount, counter: 1 };
1367
+ this.voiceCache.set(audioBufferId, cache);
1368
+ return audioBuffer;
1369
+ }
1370
+ }
1333
1371
  }
1334
- async createNote(channel, voice, noteNumber, velocity, startTime) {
1372
+ async setNoteAudioNode(channel, note, realtime) {
1335
1373
  const now = this.audioContext.currentTime;
1374
+ const { noteNumber, velocity, startTime } = note;
1336
1375
  const state = channel.state;
1337
1376
  const controllerState = this.getControllerState(channel, noteNumber, velocity);
1338
- const voiceParams = voice.getAllParams(controllerState);
1339
- const note = new Note(noteNumber, velocity, startTime, voice, voiceParams);
1340
- const audioBuffer = await this.getAudioBuffer(channel, noteNumber, velocity, voiceParams);
1377
+ const voiceParams = note.voice.getAllParams(controllerState);
1378
+ note.voiceParams = voiceParams;
1379
+ const audioBuffer = await this.getAudioBuffer(channel, noteNumber, velocity, voiceParams, realtime);
1341
1380
  note.bufferSource = this.createBufferSource(channel, noteNumber, voiceParams, audioBuffer);
1342
1381
  note.volumeEnvelopeNode = new GainNode(this.audioContext);
1343
1382
  note.filterNode = new BiquadFilterNode(this.audioContext, {
@@ -1362,7 +1401,7 @@ export class MidyGM2 {
1362
1401
  if (0 < state.vibratoDepth) {
1363
1402
  this.startVibrato(channel, note, now);
1364
1403
  }
1365
- if (0 < state.modulationDepth) {
1404
+ if (0 < state.modulationDepthMSB) {
1366
1405
  this.startModulation(channel, note, now);
1367
1406
  }
1368
1407
  if (channel.mono && channel.currentBufferSource) {
@@ -1373,7 +1412,13 @@ export class MidyGM2 {
1373
1412
  note.filterNode.connect(note.volumeEnvelopeNode);
1374
1413
  this.setChorusSend(channel, note, now);
1375
1414
  this.setReverbSend(channel, note, now);
1376
- note.bufferSource.start(startTime);
1415
+ if (voiceParams.sample.type === "compressed") {
1416
+ const offset = voiceParams.start / audioBuffer.sampleRate;
1417
+ note.bufferSource.start(startTime, offset);
1418
+ }
1419
+ else {
1420
+ note.bufferSource.start(startTime);
1421
+ }
1377
1422
  return note;
1378
1423
  }
1379
1424
  handleExclusiveClass(note, channelNumber, startTime) {
@@ -1384,7 +1429,7 @@ export class MidyGM2 {
1384
1429
  if (prev) {
1385
1430
  const [prevNote, prevChannelNumber] = prev;
1386
1431
  if (prevNote && !prevNote.ending) {
1387
- this.scheduleNoteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
1432
+ this.noteOff(prevChannelNumber, prevNote.noteNumber, 0, // velocity,
1388
1433
  startTime, true);
1389
1434
  }
1390
1435
  }
@@ -1404,27 +1449,14 @@ export class MidyGM2 {
1404
1449
  channelNumber;
1405
1450
  const prevNote = this.drumExclusiveClassNotes[index];
1406
1451
  if (prevNote && !prevNote.ending) {
1407
- this.scheduleNoteOff(channelNumber, prevNote.noteNumber, 0, // velocity,
1452
+ this.noteOff(channelNumber, prevNote.noteNumber, 0, // velocity,
1408
1453
  startTime, true);
1409
1454
  }
1410
1455
  this.drumExclusiveClassNotes[index] = note;
1411
1456
  }
1412
- async scheduleNoteOn(channelNumber, noteNumber, velocity, startTime) {
1457
+ setNoteRouting(channelNumber, note, startTime) {
1413
1458
  const channel = this.channels[channelNumber];
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];
1421
- if (soundFontIndex === undefined)
1422
- return;
1423
- const soundFont = this.soundFonts[soundFontIndex];
1424
- const voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
1425
- if (!voice)
1426
- return;
1427
- const note = await this.createNote(channel, voice, noteNumber, velocity, startTime);
1459
+ const { noteNumber, volumeEnvelopeNode } = note;
1428
1460
  if (channel.isDrum) {
1429
1461
  const { keyBasedGainLs, keyBasedGainRs } = channel;
1430
1462
  let gainL = keyBasedGainLs[noteNumber];
@@ -1434,25 +1466,48 @@ export class MidyGM2 {
1434
1466
  gainL = keyBasedGainLs[noteNumber] = audioNodes.gainL;
1435
1467
  gainR = keyBasedGainRs[noteNumber] = audioNodes.gainR;
1436
1468
  }
1437
- note.volumeEnvelopeNode.connect(gainL);
1438
- note.volumeEnvelopeNode.connect(gainR);
1469
+ volumeEnvelopeNode.connect(gainL);
1470
+ volumeEnvelopeNode.connect(gainR);
1439
1471
  }
1440
1472
  else {
1441
- note.volumeEnvelopeNode.connect(channel.gainL);
1442
- note.volumeEnvelopeNode.connect(channel.gainR);
1473
+ volumeEnvelopeNode.connect(channel.gainL);
1474
+ volumeEnvelopeNode.connect(channel.gainR);
1443
1475
  }
1444
1476
  if (0.5 <= channel.state.sustainPedal) {
1445
1477
  channel.sustainNotes.push(note);
1446
1478
  }
1447
1479
  this.handleExclusiveClass(note, channelNumber, startTime);
1448
1480
  this.handleDrumExclusiveClass(note, channelNumber, startTime);
1481
+ }
1482
+ async noteOn(channelNumber, noteNumber, velocity, startTime) {
1483
+ const channel = this.channels[channelNumber];
1484
+ const realtime = startTime === undefined;
1485
+ if (realtime)
1486
+ startTime = this.audioContext.currentTime;
1487
+ const note = new Note(noteNumber, velocity, startTime);
1449
1488
  const scheduledNotes = channel.scheduledNotes;
1450
1489
  note.index = scheduledNotes.length;
1451
1490
  scheduledNotes.push(note);
1452
- }
1453
- noteOn(channelNumber, noteNumber, velocity, scheduleTime) {
1454
- scheduleTime ??= this.audioContext.currentTime;
1455
- return this.scheduleNoteOn(channelNumber, noteNumber, velocity, scheduleTime, undefined);
1491
+ const programNumber = channel.programNumber;
1492
+ const bankTable = this.soundFontTable[programNumber];
1493
+ if (!bankTable)
1494
+ return;
1495
+ const bankLSB = channel.isDrum ? 128 : channel.bankLSB;
1496
+ const bank = bankTable[bankLSB] !== undefined ? bankLSB : 0;
1497
+ const soundFontIndex = bankTable[bank];
1498
+ if (soundFontIndex === undefined)
1499
+ return;
1500
+ const soundFont = this.soundFonts[soundFontIndex];
1501
+ note.voice = soundFont.getVoice(bank, programNumber, noteNumber, velocity);
1502
+ if (!note.voice)
1503
+ return;
1504
+ await this.setNoteAudioNode(channel, note, realtime);
1505
+ this.setNoteRouting(channelNumber, note, startTime);
1506
+ note.pending = false;
1507
+ const off = note.offEvent;
1508
+ if (off) {
1509
+ this.noteOff(channelNumber, noteNumber, off.velocity, off.startTime);
1510
+ }
1456
1511
  }
1457
1512
  disconnectNote(note) {
1458
1513
  note.bufferSource.disconnect();
@@ -1475,6 +1530,7 @@ export class MidyGM2 {
1475
1530
  }
1476
1531
  }
1477
1532
  releaseNote(channel, note, endTime) {
1533
+ endTime ??= this.audioContext.currentTime;
1478
1534
  const volRelease = endTime + note.voiceParams.volRelease;
1479
1535
  const modRelease = endTime + note.voiceParams.modRelease;
1480
1536
  const stopTime = Math.min(volRelease, modRelease);
@@ -1495,7 +1551,7 @@ export class MidyGM2 {
1495
1551
  }, stopTime);
1496
1552
  });
1497
1553
  }
1498
- scheduleNoteOff(channelNumber, noteNumber, _velocity, endTime, force) {
1554
+ noteOff(channelNumber, noteNumber, velocity, endTime, force) {
1499
1555
  const channel = this.channels[channelNumber];
1500
1556
  const state = channel.state;
1501
1557
  if (!force) {
@@ -1514,9 +1570,15 @@ export class MidyGM2 {
1514
1570
  if (index < 0)
1515
1571
  return;
1516
1572
  const note = channel.scheduledNotes[index];
1573
+ if (note.pending) {
1574
+ note.offEvent = { velocity, startTime: endTime };
1575
+ return;
1576
+ }
1517
1577
  note.ending = true;
1518
1578
  this.setNoteIndex(channel, index);
1519
- this.releaseNote(channel, note, endTime);
1579
+ const promise = this.releaseNote(channel, note, endTime);
1580
+ this.notePromises.push(promise);
1581
+ return promise;
1520
1582
  }
1521
1583
  setNoteIndex(channel, index) {
1522
1584
  let allEnds = true;
@@ -1544,16 +1606,12 @@ export class MidyGM2 {
1544
1606
  }
1545
1607
  return -1;
1546
1608
  }
1547
- noteOff(channelNumber, noteNumber, velocity, scheduleTime) {
1548
- scheduleTime ??= this.audioContext.currentTime;
1549
- return this.scheduleNoteOff(channelNumber, noteNumber, velocity, scheduleTime, false);
1550
- }
1551
1609
  releaseSustainPedal(channelNumber, halfVelocity, scheduleTime) {
1552
1610
  const velocity = halfVelocity * 2;
1553
1611
  const channel = this.channels[channelNumber];
1554
1612
  const promises = [];
1555
1613
  for (let i = 0; i < channel.sustainNotes.length; i++) {
1556
- const promise = this.scheduleNoteOff(channelNumber, channel.sustainNotes[i].noteNumber, velocity, scheduleTime);
1614
+ const promise = this.noteOff(channelNumber, channel.sustainNotes[i].noteNumber, velocity, scheduleTime);
1557
1615
  promises.push(promise);
1558
1616
  }
1559
1617
  channel.sustainNotes = [];
@@ -1567,7 +1625,7 @@ export class MidyGM2 {
1567
1625
  channel.state.sostenutoPedal = 0;
1568
1626
  for (let i = 0; i < sostenutoNotes.length; i++) {
1569
1627
  const note = sostenutoNotes[i];
1570
- const promise = this.scheduleNoteOff(channelNumber, note.noteNumber, velocity, scheduleTime);
1628
+ const promise = this.noteOff(channelNumber, note.noteNumber, velocity, scheduleTime);
1571
1629
  promises.push(promise);
1572
1630
  }
1573
1631
  channel.sostenutoNotes = [];
@@ -1652,7 +1710,8 @@ export class MidyGM2 {
1652
1710
  if (note.modulationDepth) {
1653
1711
  const modLfoToPitch = note.voiceParams.modLfoToPitch +
1654
1712
  this.getLFOPitchDepth(channel, note);
1655
- const baseDepth = Math.abs(modLfoToPitch) + channel.state.modulationDepth;
1713
+ const baseDepth = Math.abs(modLfoToPitch) +
1714
+ channel.state.modulationDepthMSB;
1656
1715
  const depth = baseDepth * Math.sign(modLfoToPitch);
1657
1716
  note.modulationDepth.gain
1658
1717
  .cancelScheduledValues(scheduleTime)
@@ -1784,7 +1843,7 @@ export class MidyGM2 {
1784
1843
  createVoiceParamsHandlers() {
1785
1844
  return {
1786
1845
  modLfoToPitch: (channel, note, scheduleTime) => {
1787
- if (0 < channel.state.modulationDepth) {
1846
+ if (0 < channel.state.modulationDepthMSB) {
1788
1847
  this.setModLfoToPitch(channel, note, scheduleTime);
1789
1848
  }
1790
1849
  },
@@ -1794,12 +1853,12 @@ export class MidyGM2 {
1794
1853
  }
1795
1854
  },
1796
1855
  modLfoToFilterFc: (channel, note, scheduleTime) => {
1797
- if (0 < channel.state.modulationDepth) {
1856
+ if (0 < channel.state.modulationDepthMSB) {
1798
1857
  this.setModLfoToFilterFc(channel, note, scheduleTime);
1799
1858
  }
1800
1859
  },
1801
1860
  modLfoToVolume: (channel, note, scheduleTime) => {
1802
- if (0 < channel.state.modulationDepth) {
1861
+ if (0 < channel.state.modulationDepthMSB) {
1803
1862
  this.setModLfoToVolume(channel, note, scheduleTime);
1804
1863
  }
1805
1864
  },
@@ -1810,12 +1869,12 @@ export class MidyGM2 {
1810
1869
  this.setReverbSend(channel, note, scheduleTime);
1811
1870
  },
1812
1871
  delayModLFO: (_channel, note, _scheduleTime) => {
1813
- if (0 < channel.state.modulationDepth) {
1872
+ if (0 < channel.state.modulationDepthMSB) {
1814
1873
  this.setDelayModLFO(note);
1815
1874
  }
1816
1875
  },
1817
1876
  freqModLFO: (_channel, note, scheduleTime) => {
1818
- if (0 < channel.state.modulationDepth) {
1877
+ if (0 < channel.state.modulationDepthMSB) {
1819
1878
  this.setFreqModLFO(note, scheduleTime);
1820
1879
  }
1821
1880
  },
@@ -1917,7 +1976,8 @@ export class MidyGM2 {
1917
1976
  this.channels[channelNumber].bankMSB = msb;
1918
1977
  }
1919
1978
  updateModulation(channel, scheduleTime) {
1920
- const depth = channel.state.modulationDepth * channel.modulationDepthRange;
1979
+ const depth = channel.state.modulationDepthMSB *
1980
+ channel.modulationDepthRange;
1921
1981
  this.processScheduledNotes(channel, (note) => {
1922
1982
  if (note.modulationDepth) {
1923
1983
  note.modulationDepth.gain.setValueAtTime(depth, scheduleTime);
@@ -1932,7 +1992,7 @@ export class MidyGM2 {
1932
1992
  if (channel.isDrum)
1933
1993
  return;
1934
1994
  scheduleTime ??= this.audioContext.currentTime;
1935
- channel.state.modulationDepth = modulation / 127;
1995
+ channel.state.modulationDepthMSB = modulation / 127;
1936
1996
  this.updateModulation(channel, scheduleTime);
1937
1997
  }
1938
1998
  updatePortamento(channel, scheduleTime) {
@@ -1954,9 +2014,9 @@ export class MidyGM2 {
1954
2014
  });
1955
2015
  }
1956
2016
  setPortamentoTime(channelNumber, portamentoTime, scheduleTime) {
1957
- const channel = this.channels[channelNumber];
1958
2017
  scheduleTime ??= this.audioContext.currentTime;
1959
- channel.state.portamentoTime = portamentoTime / 127;
2018
+ const channel = this.channels[channelNumber];
2019
+ channel.state.portamentoTimeMSB = portamentoTime / 127;
1960
2020
  if (channel.isDrum)
1961
2021
  return;
1962
2022
  this.updatePortamento(channel, scheduleTime);
@@ -1964,7 +2024,7 @@ export class MidyGM2 {
1964
2024
  setVolume(channelNumber, volume, scheduleTime) {
1965
2025
  scheduleTime ??= this.audioContext.currentTime;
1966
2026
  const channel = this.channels[channelNumber];
1967
- channel.state.volume = volume / 127;
2027
+ channel.state.volumeMSB = volume / 127;
1968
2028
  if (channel.isDrum) {
1969
2029
  for (let i = 0; i < 128; i++) {
1970
2030
  this.updateKeyBasedVolume(channel, i, scheduleTime);
@@ -1984,7 +2044,7 @@ export class MidyGM2 {
1984
2044
  setPan(channelNumber, pan, scheduleTime) {
1985
2045
  scheduleTime ??= this.audioContext.currentTime;
1986
2046
  const channel = this.channels[channelNumber];
1987
- channel.state.pan = pan / 127;
2047
+ channel.state.panMSB = pan / 127;
1988
2048
  if (channel.isDrum) {
1989
2049
  for (let i = 0; i < 128; i++) {
1990
2050
  this.updateKeyBasedVolume(channel, i, scheduleTime);
@@ -1997,7 +2057,7 @@ export class MidyGM2 {
1997
2057
  setExpression(channelNumber, expression, scheduleTime) {
1998
2058
  scheduleTime ??= this.audioContext.currentTime;
1999
2059
  const channel = this.channels[channelNumber];
2000
- channel.state.expression = expression / 127;
2060
+ channel.state.expressionMSB = expression / 127;
2001
2061
  this.updateChannelVolume(channel, scheduleTime);
2002
2062
  }
2003
2063
  setBankLSB(channelNumber, lsb) {
@@ -2009,8 +2069,8 @@ export class MidyGM2 {
2009
2069
  }
2010
2070
  updateChannelVolume(channel, scheduleTime) {
2011
2071
  const state = channel.state;
2012
- const volume = state.volume * state.expression;
2013
- const { gainLeft, gainRight } = this.panToGain(state.pan);
2072
+ const volume = state.volumeMSB * state.expressionMSB;
2073
+ const { gainLeft, gainRight } = this.panToGain(state.panMSB);
2014
2074
  channel.gainL.gain
2015
2075
  .cancelScheduledValues(scheduleTime)
2016
2076
  .setValueAtTime(volume * gainLeft, scheduleTime);
@@ -2024,8 +2084,8 @@ export class MidyGM2 {
2024
2084
  return;
2025
2085
  const gainR = channel.keyBasedGainRs[keyNumber];
2026
2086
  const state = channel.state;
2027
- const defaultVolume = state.volume * state.expression;
2028
- const defaultPan = state.pan;
2087
+ const defaultVolume = state.volumeMSB * state.expressionMSB;
2088
+ const defaultPan = state.panMSB;
2029
2089
  const keyBasedVolume = this.getKeyBasedValue(channel, keyNumber, 7);
2030
2090
  const volume = (0 <= keyBasedVolume)
2031
2091
  ? defaultVolume * keyBasedVolume / 64
@@ -2276,8 +2336,8 @@ export class MidyGM2 {
2276
2336
  const keys = [
2277
2337
  "channelPressure",
2278
2338
  "pitchWheel",
2279
- "expression",
2280
- "modulationDepth",
2339
+ "expressionMSB",
2340
+ "modulationDepthMSB",
2281
2341
  "sustainPedal",
2282
2342
  "portamento",
2283
2343
  "sostenutoPedal",
@@ -23,6 +23,7 @@ export class MidyGMLite {
23
23
  soundFontTable: never[][];
24
24
  voiceCounter: Map<any, any>;
25
25
  voiceCache: Map<any, any>;
26
+ realtimeVoiceCache: Map<any, any>;
26
27
  isPlaying: boolean;
27
28
  isPausing: boolean;
28
29
  isPaused: boolean;
@@ -103,22 +104,21 @@ export class MidyGMLite {
103
104
  clampCutoffFrequency(frequency: any): number;
104
105
  setFilterEnvelope(note: any, scheduleTime: any): void;
105
106
  startModulation(channel: any, note: any, scheduleTime: any): void;
106
- getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any): Promise<any>;
107
- createNote(channel: any, voice: any, noteNumber: any, velocity: any, startTime: any): Promise<Note>;
107
+ getAudioBuffer(channel: any, noteNumber: any, velocity: any, voiceParams: any, realtime: any): Promise<any>;
108
+ setNoteAudioNode(channel: any, note: any, realtime: any): Promise<any>;
108
109
  handleExclusiveClass(note: any, channelNumber: any, startTime: any): void;
109
110
  handleDrumExclusiveClass(note: any, channelNumber: any, startTime: any): void;
110
- scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
111
- noteOn(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): Promise<void>;
111
+ setNoteRouting(channelNumber: any, note: any, startTime: any): void;
112
+ noteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
112
113
  disconnectNote(note: any): void;
113
114
  releaseNote(channel: any, note: any, endTime: any): Promise<any>;
114
- scheduleNoteOff(channelNumber: any, noteNumber: any, _velocity: any, endTime: any, force: any): void;
115
+ noteOff(channelNumber: any, noteNumber: any, velocity: any, endTime: any, force: any): Promise<any> | undefined;
115
116
  setNoteIndex(channel: any, index: any): void;
116
117
  findNoteOffIndex(channel: any, noteNumber: any): any;
117
- noteOff(channelNumber: any, noteNumber: any, velocity: any, scheduleTime: any): void;
118
- releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): void[];
118
+ releaseSustainPedal(channelNumber: any, halfVelocity: any, scheduleTime: any): (Promise<any> | undefined)[];
119
119
  createMessageHandlers(): any[];
120
120
  handleMessage(data: any, scheduleTime: any): void;
121
- handleChannelMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<void>;
121
+ handleChannelMessage(statusByte: any, data1: any, data2: any, scheduleTime: any): void | Promise<any>;
122
122
  setProgramChange(channelNumber: any, programNumber: any, _scheduleTime: any): void;
123
123
  handlePitchBendMessage(channelNumber: any, lsb: any, msb: any, scheduleTime: any): void;
124
124
  setPitchBend(channelNumber: any, value: any, scheduleTime: any): void;
@@ -174,22 +174,4 @@ export class MidyGMLite {
174
174
  handleSysEx(data: any, scheduleTime: any): void;
175
175
  scheduleTask(callback: any, scheduleTime: any): Promise<any>;
176
176
  }
177
- declare class Note {
178
- constructor(noteNumber: any, velocity: any, startTime: any, voice: any, voiceParams: any);
179
- index: number;
180
- ending: boolean;
181
- bufferSource: any;
182
- filterNode: any;
183
- filterDepth: any;
184
- volumeEnvelopeNode: any;
185
- volumeDepth: any;
186
- modulationLFO: any;
187
- modulationDepth: any;
188
- noteNumber: any;
189
- velocity: any;
190
- startTime: any;
191
- voice: any;
192
- voiceParams: any;
193
- }
194
- export {};
195
177
  //# sourceMappingURL=midy-GMLite.d.ts.map
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"midy-GMLite.d.ts","sourceRoot":"","sources":["../src/midy-GMLite.js"],"names":[],"mappings":"AA2GA;IA6BE;;;;;;;;;MASE;IAEF,+BAeC;IAtDD,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,kCAA+B;IAC/B,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,kDASC;IAED,0EAUC;IAED,yEAoDC;IAED,mCAOC;IAED,uBASC;IAED,yDA2BC;IAED,2BA8CC;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,sBAIC;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,4GAkCC;IAED,uEA4CC;IAED,0EAiBC;IAED,8EAiBC;IAED,oEAUC;IAED,0FAwBC;IAED,gCASC;IAED,iEAqBC;IAED,gHAwBC;IAED,6CAUC;IAED,qDAUC;IAED,4GAeC;IAED,+BAmBC;IAED,kDAOC;IAED,sGA2BC;IAED,mFAGC;IAED,wFAGC;IAED,sEAUC;IAED,mEAYC;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"}