@marmooo/midy 0.1.2 → 0.1.4

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.
Files changed (35) hide show
  1. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.d.ts +153 -0
  2. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.d.ts.map +1 -0
  3. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.2 → soundfont-parser@0.0.4}/+esm.js +73 -66
  4. package/esm/midy-GM1.d.ts +19 -13
  5. package/esm/midy-GM1.d.ts.map +1 -1
  6. package/esm/midy-GM1.js +171 -131
  7. package/esm/midy-GM2.d.ts +22 -14
  8. package/esm/midy-GM2.d.ts.map +1 -1
  9. package/esm/midy-GM2.js +186 -133
  10. package/esm/midy-GMLite.d.ts +17 -13
  11. package/esm/midy-GMLite.d.ts.map +1 -1
  12. package/esm/midy-GMLite.js +159 -131
  13. package/esm/midy.d.ts +30 -16
  14. package/esm/midy.d.ts.map +1 -1
  15. package/esm/midy.js +266 -166
  16. package/package.json +1 -1
  17. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.d.ts +153 -0
  18. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.d.ts.map +1 -0
  19. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/{soundfont-parser@0.0.2 → soundfont-parser@0.0.4}/+esm.js +75 -68
  20. package/script/midy-GM1.d.ts +19 -13
  21. package/script/midy-GM1.d.ts.map +1 -1
  22. package/script/midy-GM1.js +171 -131
  23. package/script/midy-GM2.d.ts +22 -14
  24. package/script/midy-GM2.d.ts.map +1 -1
  25. package/script/midy-GM2.js +186 -133
  26. package/script/midy-GMLite.d.ts +17 -13
  27. package/script/midy-GMLite.d.ts.map +1 -1
  28. package/script/midy-GMLite.js +159 -131
  29. package/script/midy.d.ts +30 -16
  30. package/script/midy.d.ts.map +1 -1
  31. package/script/midy.js +266 -166
  32. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.d.ts +0 -135
  33. package/esm/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.d.ts.map +0 -1
  34. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.d.ts +0 -135
  35. package/script/deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.d.ts.map +0 -1
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MidyGM1 = void 0;
4
4
  const _esm_js_1 = require("./deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js");
5
- const _esm_js_2 = require("./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.js");
5
+ const _esm_js_2 = require("./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.js");
6
6
  class Note {
7
7
  constructor(noteNumber, velocity, startTime, instrumentKey) {
8
8
  Object.defineProperty(this, "bufferSource", {
@@ -11,25 +11,43 @@ class Note {
11
11
  writable: true,
12
12
  value: void 0
13
13
  });
14
- Object.defineProperty(this, "gainNode", {
14
+ Object.defineProperty(this, "filterNode", {
15
15
  enumerable: true,
16
16
  configurable: true,
17
17
  writable: true,
18
18
  value: void 0
19
19
  });
20
- Object.defineProperty(this, "filterNode", {
20
+ Object.defineProperty(this, "volumeNode", {
21
+ enumerable: true,
22
+ configurable: true,
23
+ writable: true,
24
+ value: void 0
25
+ });
26
+ Object.defineProperty(this, "volumeDepth", {
27
+ enumerable: true,
28
+ configurable: true,
29
+ writable: true,
30
+ value: void 0
31
+ });
32
+ Object.defineProperty(this, "modulationLFO", {
21
33
  enumerable: true,
22
34
  configurable: true,
23
35
  writable: true,
24
36
  value: void 0
25
37
  });
26
- Object.defineProperty(this, "modLFO", {
38
+ Object.defineProperty(this, "modulationDepth", {
27
39
  enumerable: true,
28
40
  configurable: true,
29
41
  writable: true,
30
42
  value: void 0
31
43
  });
32
- Object.defineProperty(this, "modLFOGain", {
44
+ Object.defineProperty(this, "vibratoLFO", {
45
+ enumerable: true,
46
+ configurable: true,
47
+ writable: true,
48
+ value: void 0
49
+ });
50
+ Object.defineProperty(this, "vibratoDepth", {
33
51
  enumerable: true,
34
52
  configurable: true,
35
53
  writable: true,
@@ -316,7 +334,7 @@ class MidyGM1 {
316
334
  const t = this.audioContext.currentTime + offset;
317
335
  queueIndex = await this.scheduleTimelineEvents(t, offset, queueIndex);
318
336
  if (this.isPausing) {
319
- await this.stopNotes();
337
+ await this.stopNotes(0, true);
320
338
  this.notePromises = [];
321
339
  resolve();
322
340
  this.isPausing = false;
@@ -324,7 +342,7 @@ class MidyGM1 {
324
342
  return;
325
343
  }
326
344
  else if (this.isStopping) {
327
- await this.stopNotes();
345
+ await this.stopNotes(0, true);
328
346
  this.notePromises = [];
329
347
  resolve();
330
348
  this.isStopping = false;
@@ -332,7 +350,7 @@ class MidyGM1 {
332
350
  return;
333
351
  }
334
352
  else if (this.isSeeking) {
335
- this.stopNotes();
353
+ this.stopNotes(0, true);
336
354
  this.startTime = this.audioContext.currentTime;
337
355
  queueIndex = this.getQueueIndex(this.resumeTime);
338
356
  offset = this.resumeTime - this.startTime;
@@ -413,21 +431,25 @@ class MidyGM1 {
413
431
  }
414
432
  return { instruments, timeline };
415
433
  }
416
- stopNotes() {
434
+ async stopChannelNotes(channelNumber, velocity, stopPedal) {
417
435
  const now = this.audioContext.currentTime;
418
- const velocity = 0;
419
- const stopPedal = true;
420
- this.channels.forEach((channel, channelNumber) => {
421
- channel.scheduledNotes.forEach((scheduledNotes) => {
422
- scheduledNotes.forEach((scheduledNote) => {
423
- if (scheduledNote) {
424
- const promise = this.scheduleNoteRelease(channelNumber, scheduledNote.noteNumber, velocity, now, stopPedal);
425
- this.notePromises.push(promise);
426
- }
427
- });
428
- });
429
- channel.scheduledNotes.clear();
436
+ const channel = this.channels[channelNumber];
437
+ channel.scheduledNotes.forEach((noteList) => {
438
+ for (let i = 0; i < noteList.length; i++) {
439
+ const note = noteList[i];
440
+ if (!note)
441
+ continue;
442
+ const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, stopPedal);
443
+ this.notePromises.push(promise);
444
+ }
430
445
  });
446
+ channel.scheduledNotes.clear();
447
+ await Promise.all(this.notePromises);
448
+ }
449
+ stopNotes(velocity, stopPedal) {
450
+ for (let i = 0; i < this.channels.length; i++) {
451
+ this.stopChannelNotes(i, velocity, stopPedal);
452
+ }
431
453
  return Promise.all(this.notePromises);
432
454
  }
433
455
  async start() {
@@ -511,75 +533,111 @@ class MidyGM1 {
511
533
  }
512
534
  setVolumeEnvelope(note) {
513
535
  const { instrumentKey, startTime } = note;
514
- note.gainNode = new GainNode(this.audioContext, { gain: 0 });
515
536
  const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
516
537
  const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
517
538
  const volDelay = startTime + instrumentKey.volDelay;
518
539
  const volAttack = volDelay + instrumentKey.volAttack;
519
540
  const volHold = volAttack + instrumentKey.volHold;
520
541
  const volDecay = volHold + instrumentKey.volDecay;
521
- note.gainNode.gain
542
+ note.volumeNode.gain
543
+ .cancelScheduledValues(startTime)
544
+ .setValueAtTime(0, startTime)
522
545
  .setValueAtTime(1e-6, volDelay) // exponentialRampToValueAtTime() requires a non-zero value
523
546
  .exponentialRampToValueAtTime(attackVolume, volAttack)
524
547
  .setValueAtTime(attackVolume, volHold)
525
548
  .linearRampToValueAtTime(sustainVolume, volDecay);
526
549
  }
527
- setFilterEnvelope(channel, note) {
528
- const { instrumentKey, startTime, noteNumber } = note;
529
- const softPedalFactor = 1 -
530
- (0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
531
- const maxFreq = this.audioContext.sampleRate / 2;
532
- const baseFreq = this.centToHz(instrumentKey.initialFilterFc) *
533
- softPedalFactor;
534
- const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc) * softPedalFactor;
535
- const sustainFreq = (baseFreq +
536
- (peekFreq - baseFreq) * (1 - instrumentKey.modSustain)) * softPedalFactor;
550
+ setPitch(note, semitoneOffset) {
551
+ const { instrumentKey, noteNumber, startTime } = note;
552
+ const modEnvToPitch = instrumentKey.modEnvToPitch / 100;
553
+ note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
554
+ if (modEnvToPitch === 0)
555
+ return;
556
+ const basePitch = note.bufferSource.playbackRate.value;
557
+ const peekPitch = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset + modEnvToPitch);
558
+ const modDelay = startTime + instrumentKey.modDelay;
559
+ const modAttack = modDelay + instrumentKey.modAttack;
560
+ const modHold = modAttack + instrumentKey.modHold;
561
+ const modDecay = modHold + instrumentKey.modDecay;
562
+ note.bufferSource.playbackRate.value
563
+ .setValueAtTime(basePitch, modDelay)
564
+ .exponentialRampToValueAtTime(peekPitch, modAttack)
565
+ .setValueAtTime(peekPitch, modHold)
566
+ .linearRampToValueAtTime(basePitch, modDecay);
567
+ }
568
+ clampCutoffFrequency(frequency) {
569
+ const minFrequency = 20; // min Hz of initialFilterFc
570
+ const maxFrequency = 20000; // max Hz of initialFilterFc
571
+ return Math.max(minFrequency, Math.min(frequency, maxFrequency));
572
+ }
573
+ setFilterEnvelope(note) {
574
+ const { instrumentKey, startTime } = note;
575
+ const baseFreq = this.centToHz(instrumentKey.initialFilterFc);
576
+ const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc);
577
+ const sustainFreq = baseFreq +
578
+ (peekFreq - baseFreq) * (1 - instrumentKey.modSustain);
579
+ const adjustedBaseFreq = this.clampCutoffFrequency(baseFreq);
580
+ const adjustedPeekFreq = this.clampCutoffFrequency(peekFreq);
581
+ const adjustedSustainFreq = this.clampCutoffFrequency(sustainFreq);
537
582
  const modDelay = startTime + instrumentKey.modDelay;
538
583
  const modAttack = modDelay + instrumentKey.modAttack;
539
584
  const modHold = modAttack + instrumentKey.modHold;
540
585
  const modDecay = modHold + instrumentKey.modDecay;
541
- const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
542
- const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
543
- const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
544
- note.filterNode = new BiquadFilterNode(this.audioContext, {
545
- type: "lowpass",
546
- Q: instrumentKey.initialFilterQ / 10, // dB
547
- frequency: adjustedBaseFreq,
548
- });
549
586
  note.filterNode.frequency
587
+ .cancelScheduledValues(startTime)
588
+ .setValueAtTime(adjustedBaseFreq, startTime)
550
589
  .setValueAtTime(adjustedBaseFreq, modDelay)
551
590
  .exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
552
591
  .setValueAtTime(adjustedPeekFreq, modHold)
553
592
  .linearRampToValueAtTime(adjustedSustainFreq, modDecay);
554
- note.bufferSource.detune.setValueAtTime(note.bufferSource.detune.value + instrumentKey.modEnvToPitch, modDelay);
555
593
  }
556
- startModulation(channel, note, time) {
594
+ startModulation(channel, note, startTime) {
557
595
  const { instrumentKey } = note;
558
- note.modLFOGain = new GainNode(this.audioContext, {
559
- gain: this.cbToRatio(instrumentKey.modLfoToVolume + channel.modulation),
560
- });
561
- note.modLFO = new OscillatorNode(this.audioContext, {
596
+ const { modLfoToPitch, modLfoToVolume } = instrumentKey;
597
+ note.modulationLFO = new OscillatorNode(this.audioContext, {
562
598
  frequency: this.centToHz(instrumentKey.freqModLFO),
563
599
  });
564
- note.modLFO.start(time);
565
- note.filterNode.frequency.setValueAtTime(note.filterNode.frequency.value + instrumentKey.modLfoToFilterFc, time);
566
- note.bufferSource.detune.setValueAtTime(note.bufferSource.detune.value + instrumentKey.modLfoToPitch, time);
567
- note.modLFO.connect(note.modLFOGain);
568
- note.modLFOGain.connect(note.bufferSource.detune);
600
+ note.filterDepth = new GainNode(this.audioContext, {
601
+ gain: instrumentKey.modLfoToFilterFc,
602
+ });
603
+ const modulationDepth = Math.abs(modLfoToPitch) + channel.modulationDepth;
604
+ const modulationDepthSign = (0 < modLfoToPitch) ? 1 : -1;
605
+ note.modulationDepth = new GainNode(this.audioContext, {
606
+ gain: modulationDepth * modulationDepthSign,
607
+ });
608
+ const volumeDepth = this.cbToRatio(Math.abs(modLfoToVolume)) - 1;
609
+ const volumeDepthSign = (0 < modLfoToVolume) ? 1 : -1;
610
+ note.volumeDepth = new GainNode(this.audioContext, {
611
+ gain: volumeDepth * volumeDepthSign,
612
+ });
613
+ note.modulationLFO.start(startTime + instrumentKey.delayModLFO);
614
+ note.modulationLFO.connect(note.filterDepth);
615
+ note.filterDepth.connect(note.filterNode.frequency);
616
+ note.modulationLFO.connect(note.modulationDepth);
617
+ note.modulationDepth.connect(note.bufferSource.detune);
618
+ note.modulationLFO.connect(note.volumeDepth);
619
+ note.volumeDepth.connect(note.volumeNode.gain);
569
620
  }
570
621
  async createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3) {
571
622
  const semitoneOffset = this.calcSemitoneOffset(channel);
572
623
  const note = new Note(noteNumber, velocity, startTime, instrumentKey);
573
624
  note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
574
- note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
625
+ note.volumeNode = new GainNode(this.audioContext);
626
+ note.filterNode = new BiquadFilterNode(this.audioContext, {
627
+ type: "lowpass",
628
+ Q: instrumentKey.initialFilterQ / 10 * channel.filterResonance, // dB
629
+ });
575
630
  this.setVolumeEnvelope(note);
576
- this.setFilterEnvelope(channel, note);
577
- if (channel.modulation > 0) {
578
- const delayModLFO = startTime + instrumentKey.delayModLFO;
579
- this.startModulation(channel, note, delayModLFO);
631
+ this.setFilterEnvelope(note);
632
+ if (0 < channel.modulationDepth) {
633
+ this.setPitch(note, semitoneOffset);
634
+ this.startModulation(channel, note, startTime);
635
+ }
636
+ else {
637
+ note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
580
638
  }
581
639
  note.bufferSource.connect(note.filterNode);
582
- note.filterNode.connect(note.gainNode);
640
+ note.filterNode.connect(note.volumeNode);
583
641
  note.bufferSource.start(startTime, instrumentKey.start / instrumentKey.sampleRate);
584
642
  return note;
585
643
  }
@@ -595,8 +653,8 @@ class MidyGM1 {
595
653
  if (!instrumentKey)
596
654
  return;
597
655
  const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
598
- note.gainNode.connect(channel.gainL);
599
- note.gainNode.connect(channel.gainR);
656
+ note.volumeNode.connect(channel.gainL);
657
+ note.volumeNode.connect(channel.gainR);
600
658
  const scheduledNotes = channel.scheduledNotes;
601
659
  if (scheduledNotes.has(noteNumber)) {
602
660
  scheduledNotes.get(noteNumber).push(note);
@@ -609,7 +667,7 @@ class MidyGM1 {
609
667
  const now = this.audioContext.currentTime;
610
668
  return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now);
611
669
  }
612
- scheduleNoteRelease(channelNumber, noteNumber, velocity, stopTime, stopPedal = false) {
670
+ scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, stopPedal = false) {
613
671
  const channel = this.channels[channelNumber];
614
672
  if (stopPedal && channel.sustainPedal)
615
673
  return;
@@ -622,20 +680,14 @@ class MidyGM1 {
622
680
  continue;
623
681
  if (note.ending)
624
682
  continue;
625
- const velocityRate = (velocity + 127) / 127;
626
- const volEndTime = stopTime +
627
- note.instrumentKey.volRelease * velocityRate;
628
- note.gainNode.gain
683
+ const volEndTime = stopTime + note.instrumentKey.volRelease;
684
+ note.volumeNode.gain
629
685
  .cancelScheduledValues(stopTime)
630
686
  .linearRampToValueAtTime(0, volEndTime);
631
- const maxFreq = this.audioContext.sampleRate / 2;
632
- const baseFreq = this.centToHz(note.instrumentKey.initialFilterFc);
633
- const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
634
- const modEndTime = stopTime +
635
- note.instrumentKey.modRelease * velocityRate;
687
+ const modRelease = stopTime + note.instrumentKey.modRelease;
636
688
  note.filterNode.frequency
637
689
  .cancelScheduledValues(stopTime)
638
- .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
690
+ .linearRampToValueAtTime(0, modRelease);
639
691
  note.ending = true;
640
692
  this.scheduleTask(() => {
641
693
  note.bufferSource.loop = false;
@@ -644,15 +696,17 @@ class MidyGM1 {
644
696
  note.bufferSource.onended = () => {
645
697
  scheduledNotes[i] = null;
646
698
  note.bufferSource.disconnect();
699
+ note.volumeNode.disconnect();
647
700
  note.filterNode.disconnect();
648
- note.gainNode.disconnect();
649
- if (note.modLFOGain)
650
- note.modLFOGain.disconnect();
651
- if (note.modLFO)
652
- note.modLFO.stop();
701
+ if (note.volumeDepth)
702
+ note.volumeDepth.disconnect();
703
+ if (note.modulationDepth)
704
+ note.modulationDepth.disconnect();
705
+ if (note.modulationLFO)
706
+ note.modulationLFO.stop();
653
707
  resolve();
654
708
  };
655
- bufferSource.stop(volEndTime);
709
+ note.bufferSource.stop(volEndTime);
656
710
  });
657
711
  }
658
712
  }
@@ -665,14 +719,15 @@ class MidyGM1 {
665
719
  const channel = this.channels[channelNumber];
666
720
  const promises = [];
667
721
  channel.sustainPedal = false;
668
- channel.scheduledNotes.forEach((scheduledNotes) => {
669
- scheduledNotes.forEach((scheduledNote) => {
670
- if (scheduledNote) {
671
- const { noteNumber } = scheduledNote;
672
- const promise = this.releaseNote(channelNumber, noteNumber, velocity);
673
- promises.push(promise);
674
- }
675
- });
722
+ channel.scheduledNotes.forEach((noteList) => {
723
+ for (let i = 0; i < noteList.length; i++) {
724
+ const note = noteList[i];
725
+ if (!note)
726
+ continue;
727
+ const { noteNumber } = note;
728
+ const promise = this.releaseNote(channelNumber, noteNumber, velocity);
729
+ promises.push(promise);
730
+ }
676
731
  });
677
732
  return promises;
678
733
  }
@@ -713,7 +768,7 @@ class MidyGM1 {
713
768
  handleControlChange(channelNumber, controller, value) {
714
769
  switch (controller) {
715
770
  case 1:
716
- return this.setModulation(channelNumber, value);
771
+ return this.setModulationDepth(channelNumber, value);
717
772
  case 6:
718
773
  return this.dataEntryMSB(channelNumber, value);
719
774
  case 7:
@@ -742,20 +797,25 @@ class MidyGM1 {
742
797
  }
743
798
  updateModulation(channel) {
744
799
  const now = this.audioContext.currentTime;
745
- const activeNotes = this.getActiveNotes(channel, now);
746
- activeNotes.forEach((activeNote) => {
747
- if (activeNote.modLFO) {
748
- const { gainNode, instrumentKey } = activeNote;
749
- gainNode.gain.setValueAtTime(this.cbToRatio(instrumentKey.modLfoToVolume + channel.modulation), now);
750
- }
751
- else {
752
- this.startModulation(channel, activeNote, now);
800
+ channel.scheduledNotes.forEach((noteList) => {
801
+ for (let i = 0; i < noteList.length; i++) {
802
+ const note = noteList[i];
803
+ if (!note)
804
+ continue;
805
+ if (note.modulationDepth) {
806
+ note.modulationDepth.gain.setValueAtTime(channel.modulationDepth, now);
807
+ }
808
+ else {
809
+ const semitoneOffset = this.calcSemitoneOffset(channel);
810
+ this.setPitch(note, semitoneOffset);
811
+ this.startModulation(channel, note, now);
812
+ }
753
813
  }
754
814
  });
755
815
  }
756
- setModulation(channelNumber, modulation) {
816
+ setModulationDepth(channelNumber, modulation) {
757
817
  const channel = this.channels[channelNumber];
758
- channel.modulation = (modulation / 127) * channel.modulationDepthRange;
818
+ channel.modulationDepth = (modulation / 127) * channel.modulationDepthRange;
759
819
  this.updateModulation(channel);
760
820
  }
761
821
  setVolume(channelNumber, volume) {
@@ -857,13 +917,17 @@ class MidyGM1 {
857
917
  }
858
918
  updateDetune(channel, detuneChange) {
859
919
  const now = this.audioContext.currentTime;
860
- const activeNotes = this.getActiveNotes(channel, now);
861
- activeNotes.forEach((activeNote) => {
862
- const { bufferSource } = activeNote;
863
- const detune = bufferSource.detune.value + detuneChange;
864
- bufferSource.detune
865
- .cancelScheduledValues(now)
866
- .setValueAtTime(detune, now);
920
+ channel.scheduledNotes.forEach((noteList) => {
921
+ for (let i = 0; i < noteList.length; i++) {
922
+ const note = noteList[i];
923
+ if (!note)
924
+ continue;
925
+ const { bufferSource } = note;
926
+ const detune = bufferSource.detune.value + detuneChange;
927
+ bufferSource.detune
928
+ .cancelScheduledValues(now)
929
+ .setValueAtTime(detune, now);
930
+ }
867
931
  });
868
932
  }
869
933
  handlePitchBendRangeRPN(channelNumber) {
@@ -907,37 +971,13 @@ class MidyGM1 {
907
971
  this.updateDetune(channel, detuneChange);
908
972
  }
909
973
  allSoundOff(channelNumber) {
910
- const now = this.audioContext.currentTime;
911
- const channel = this.channels[channelNumber];
912
- const velocity = 0;
913
- const stopPedal = true;
914
- const promises = [];
915
- channel.scheduledNotes.forEach((noteList) => {
916
- const activeNote = this.getActiveNote(noteList, now);
917
- if (activeNote) {
918
- const notePromise = this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, stopPedal);
919
- promises.push(notePromise);
920
- }
921
- });
922
- return promises;
974
+ return this.stopChannelNotes(channelNumber, 0, true);
923
975
  }
924
976
  resetAllControllers(channelNumber) {
925
977
  Object.assign(this.channels[channelNumber], this.effectSettings);
926
978
  }
927
979
  allNotesOff(channelNumber) {
928
- const now = this.audioContext.currentTime;
929
- const channel = this.channels[channelNumber];
930
- const velocity = 0;
931
- const stopPedal = false;
932
- const promises = [];
933
- channel.scheduledNotes.forEach((noteList) => {
934
- const activeNote = this.getActiveNote(noteList, now);
935
- if (activeNote) {
936
- const notePromise = this.scheduleNoteRelease(channelNumber, activeNote.noteNumber, velocity, now, stopPedal);
937
- promises.push(notePromise);
938
- }
939
- });
940
- return promises;
980
+ return this.stopChannelNotes(channelNumber, 0, false);
941
981
  }
942
982
  handleUniversalNonRealTimeExclusiveMessage(data) {
943
983
  switch (data[2]) {
@@ -1033,7 +1073,7 @@ Object.defineProperty(MidyGM1, "channelSettings", {
1033
1073
  pitchBend: 0,
1034
1074
  fineTuning: 0, // cb
1035
1075
  coarseTuning: 0, // cb
1036
- modulationDepthRange: 0.5, // cb
1076
+ modulationDepthRange: 50, // cent
1037
1077
  }
1038
1078
  });
1039
1079
  Object.defineProperty(MidyGM1, "effectSettings", {
@@ -1042,7 +1082,7 @@ Object.defineProperty(MidyGM1, "effectSettings", {
1042
1082
  writable: true,
1043
1083
  value: {
1044
1084
  expression: 1,
1045
- modulation: 0,
1085
+ modulationDepth: 0,
1046
1086
  sustainPedal: false,
1047
1087
  rpnMSB: 127,
1048
1088
  rpnLSB: 127,
@@ -6,6 +6,9 @@ export class MidyGM2 {
6
6
  portamentoTime: number;
7
7
  reverbSendLevel: number;
8
8
  chorusSendLevel: number;
9
+ vibratoRate: number;
10
+ vibratoDepth: number;
11
+ vibratoDelay: number;
9
12
  bank: number;
10
13
  bankMSB: number;
11
14
  bankLSB: number;
@@ -19,7 +22,7 @@ export class MidyGM2 {
19
22
  };
20
23
  static effectSettings: {
21
24
  expression: number;
22
- modulation: number;
25
+ modulationDepth: number;
23
26
  sustainPedal: boolean;
24
27
  portamento: boolean;
25
28
  sostenutoPedal: boolean;
@@ -125,7 +128,8 @@ export class MidyGM2 {
125
128
  instruments: Set<any>;
126
129
  timeline: any[];
127
130
  };
128
- stopNotes(): Promise<any[]>;
131
+ stopChannelNotes(channelNumber: any, velocity: any, stopPedal: any): Promise<void>;
132
+ stopNotes(velocity: any, stopPedal: any): Promise<any[]>;
129
133
  start(): Promise<void>;
130
134
  stop(): void;
131
135
  pause(): void;
@@ -162,25 +166,28 @@ export class MidyGM2 {
162
166
  calcSemitoneOffset(channel: any): any;
163
167
  calcPlaybackRate(instrumentKey: any, noteNumber: any, semitoneOffset: any): number;
164
168
  setVolumeEnvelope(note: any): void;
169
+ setPitch(note: any, semitoneOffset: any): void;
170
+ clampCutoffFrequency(frequency: any): number;
165
171
  setFilterEnvelope(channel: any, note: any): void;
166
- startModulation(channel: any, note: any, time: any): void;
172
+ startModulation(channel: any, note: any, startTime: any): void;
173
+ startVibrato(channel: any, note: any, startTime: any): void;
167
174
  createNote(channel: any, instrumentKey: any, noteNumber: any, velocity: any, startTime: any, isSF3: any): Promise<Note>;
168
175
  calcBank(channel: any, channelNumber: any): any;
169
176
  scheduleNoteOn(channelNumber: any, noteNumber: any, velocity: any, startTime: any): Promise<void>;
170
177
  noteOn(channelNumber: any, noteNumber: any, velocity: any): Promise<void>;
171
- scheduleNoteRelease(channelNumber: any, noteNumber: any, velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
178
+ scheduleNoteRelease(channelNumber: any, noteNumber: any, _velocity: any, stopTime: any, stopPedal?: boolean): Promise<any> | undefined;
172
179
  releaseNote(channelNumber: any, noteNumber: any, velocity: any): Promise<any> | undefined;
173
180
  releaseSustainPedal(channelNumber: any, halfVelocity: any): any[];
174
181
  releaseSostenutoPedal(channelNumber: any, halfVelocity: any): any[];
175
- handleMIDIMessage(statusByte: any, data1: any, data2: any): void | any[] | Promise<any>;
182
+ handleMIDIMessage(statusByte: any, data1: any, data2: any): void | Promise<any>;
176
183
  handleProgramChange(channelNumber: any, program: any): void;
177
184
  handleChannelPressure(channelNumber: any, pressure: any): void;
178
185
  handlePitchBendMessage(channelNumber: any, lsb: any, msb: any): void;
179
186
  setPitchBend(channelNumber: any, pitchBend: any): void;
180
- handleControlChange(channelNumber: any, controller: any, value: any): void | any[];
187
+ handleControlChange(channelNumber: any, controller: any, value: any): void | Promise<void>;
181
188
  setBankMSB(channelNumber: any, msb: any): void;
182
189
  updateModulation(channel: any): void;
183
- setModulation(channelNumber: any, modulation: any): void;
190
+ setModulationDepth(channelNumber: any, modulation: any): void;
184
191
  setPortamentoTime(channelNumber: any, portamentoTime: any): void;
185
192
  setVolume(channelNumber: any, volume: any): void;
186
193
  panToGain(pan: any): {
@@ -213,9 +220,9 @@ export class MidyGM2 {
213
220
  setCoarseTuning(channelNumber: any, coarseTuning: any): void;
214
221
  handleModulationDepthRangeRPN(channelNumber: any): void;
215
222
  setModulationDepthRange(channelNumber: any, modulationDepthRange: any): void;
216
- allSoundOff(channelNumber: any): any[];
223
+ allSoundOff(channelNumber: any): Promise<void>;
217
224
  resetAllControllers(channelNumber: any): void;
218
- allNotesOff(channelNumber: any): any[];
225
+ allNotesOff(channelNumber: any): Promise<void>;
219
226
  omniOff(): void;
220
227
  omniOn(): void;
221
228
  monoOn(): void;
@@ -255,12 +262,13 @@ export class MidyGM2 {
255
262
  declare class Note {
256
263
  constructor(noteNumber: any, velocity: any, startTime: any, instrumentKey: any);
257
264
  bufferSource: any;
258
- gainNode: any;
259
265
  filterNode: any;
260
- modLFO: any;
261
- modLFOGain: any;
262
- vibLFO: any;
263
- vibLFOGain: any;
266
+ volumeNode: any;
267
+ volumeDepth: any;
268
+ modulationLFO: any;
269
+ modulationDepth: any;
270
+ vibratoLFO: any;
271
+ vibratoDepth: any;
264
272
  noteNumber: any;
265
273
  velocity: any;
266
274
  startTime: any;
@@ -1 +1 @@
1
- {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"midy-GM2.d.ts","sourceRoot":"","sources":["../src/midy-GM2.js"],"names":[],"mappings":"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"}