@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
package/esm/midy-GM1.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { parseMidi } from "./deps/cdn.jsdelivr.net/npm/midi-file@1.2.4/+esm.js";
2
- import { parse, SoundFont, } from "./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.2/+esm.js";
2
+ import { parse, SoundFont, } from "./deps/cdn.jsdelivr.net/npm/@marmooo/soundfont-parser@0.0.4/+esm.js";
3
3
  class Note {
4
4
  constructor(noteNumber, velocity, startTime, instrumentKey) {
5
5
  Object.defineProperty(this, "bufferSource", {
@@ -8,25 +8,43 @@ class Note {
8
8
  writable: true,
9
9
  value: void 0
10
10
  });
11
- Object.defineProperty(this, "gainNode", {
11
+ Object.defineProperty(this, "filterNode", {
12
12
  enumerable: true,
13
13
  configurable: true,
14
14
  writable: true,
15
15
  value: void 0
16
16
  });
17
- Object.defineProperty(this, "filterNode", {
17
+ Object.defineProperty(this, "volumeNode", {
18
+ enumerable: true,
19
+ configurable: true,
20
+ writable: true,
21
+ value: void 0
22
+ });
23
+ Object.defineProperty(this, "volumeDepth", {
24
+ enumerable: true,
25
+ configurable: true,
26
+ writable: true,
27
+ value: void 0
28
+ });
29
+ Object.defineProperty(this, "modulationLFO", {
18
30
  enumerable: true,
19
31
  configurable: true,
20
32
  writable: true,
21
33
  value: void 0
22
34
  });
23
- Object.defineProperty(this, "modLFO", {
35
+ Object.defineProperty(this, "modulationDepth", {
24
36
  enumerable: true,
25
37
  configurable: true,
26
38
  writable: true,
27
39
  value: void 0
28
40
  });
29
- Object.defineProperty(this, "modLFOGain", {
41
+ Object.defineProperty(this, "vibratoLFO", {
42
+ enumerable: true,
43
+ configurable: true,
44
+ writable: true,
45
+ value: void 0
46
+ });
47
+ Object.defineProperty(this, "vibratoDepth", {
30
48
  enumerable: true,
31
49
  configurable: true,
32
50
  writable: true,
@@ -313,7 +331,7 @@ export class MidyGM1 {
313
331
  const t = this.audioContext.currentTime + offset;
314
332
  queueIndex = await this.scheduleTimelineEvents(t, offset, queueIndex);
315
333
  if (this.isPausing) {
316
- await this.stopNotes();
334
+ await this.stopNotes(0, true);
317
335
  this.notePromises = [];
318
336
  resolve();
319
337
  this.isPausing = false;
@@ -321,7 +339,7 @@ export class MidyGM1 {
321
339
  return;
322
340
  }
323
341
  else if (this.isStopping) {
324
- await this.stopNotes();
342
+ await this.stopNotes(0, true);
325
343
  this.notePromises = [];
326
344
  resolve();
327
345
  this.isStopping = false;
@@ -329,7 +347,7 @@ export class MidyGM1 {
329
347
  return;
330
348
  }
331
349
  else if (this.isSeeking) {
332
- this.stopNotes();
350
+ this.stopNotes(0, true);
333
351
  this.startTime = this.audioContext.currentTime;
334
352
  queueIndex = this.getQueueIndex(this.resumeTime);
335
353
  offset = this.resumeTime - this.startTime;
@@ -410,21 +428,25 @@ export class MidyGM1 {
410
428
  }
411
429
  return { instruments, timeline };
412
430
  }
413
- stopNotes() {
431
+ async stopChannelNotes(channelNumber, velocity, stopPedal) {
414
432
  const now = this.audioContext.currentTime;
415
- const velocity = 0;
416
- const stopPedal = true;
417
- this.channels.forEach((channel, channelNumber) => {
418
- channel.scheduledNotes.forEach((scheduledNotes) => {
419
- scheduledNotes.forEach((scheduledNote) => {
420
- if (scheduledNote) {
421
- const promise = this.scheduleNoteRelease(channelNumber, scheduledNote.noteNumber, velocity, now, stopPedal);
422
- this.notePromises.push(promise);
423
- }
424
- });
425
- });
426
- channel.scheduledNotes.clear();
433
+ const channel = this.channels[channelNumber];
434
+ channel.scheduledNotes.forEach((noteList) => {
435
+ for (let i = 0; i < noteList.length; i++) {
436
+ const note = noteList[i];
437
+ if (!note)
438
+ continue;
439
+ const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, stopPedal);
440
+ this.notePromises.push(promise);
441
+ }
427
442
  });
443
+ channel.scheduledNotes.clear();
444
+ await Promise.all(this.notePromises);
445
+ }
446
+ stopNotes(velocity, stopPedal) {
447
+ for (let i = 0; i < this.channels.length; i++) {
448
+ this.stopChannelNotes(i, velocity, stopPedal);
449
+ }
428
450
  return Promise.all(this.notePromises);
429
451
  }
430
452
  async start() {
@@ -508,75 +530,111 @@ export class MidyGM1 {
508
530
  }
509
531
  setVolumeEnvelope(note) {
510
532
  const { instrumentKey, startTime } = note;
511
- note.gainNode = new GainNode(this.audioContext, { gain: 0 });
512
533
  const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
513
534
  const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
514
535
  const volDelay = startTime + instrumentKey.volDelay;
515
536
  const volAttack = volDelay + instrumentKey.volAttack;
516
537
  const volHold = volAttack + instrumentKey.volHold;
517
538
  const volDecay = volHold + instrumentKey.volDecay;
518
- note.gainNode.gain
539
+ note.volumeNode.gain
540
+ .cancelScheduledValues(startTime)
541
+ .setValueAtTime(0, startTime)
519
542
  .setValueAtTime(1e-6, volDelay) // exponentialRampToValueAtTime() requires a non-zero value
520
543
  .exponentialRampToValueAtTime(attackVolume, volAttack)
521
544
  .setValueAtTime(attackVolume, volHold)
522
545
  .linearRampToValueAtTime(sustainVolume, volDecay);
523
546
  }
524
- setFilterEnvelope(channel, note) {
525
- const { instrumentKey, startTime, noteNumber } = note;
526
- const softPedalFactor = 1 -
527
- (0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
528
- const maxFreq = this.audioContext.sampleRate / 2;
529
- const baseFreq = this.centToHz(instrumentKey.initialFilterFc) *
530
- softPedalFactor;
531
- const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc) * softPedalFactor;
532
- const sustainFreq = (baseFreq +
533
- (peekFreq - baseFreq) * (1 - instrumentKey.modSustain)) * softPedalFactor;
547
+ setPitch(note, semitoneOffset) {
548
+ const { instrumentKey, noteNumber, startTime } = note;
549
+ const modEnvToPitch = instrumentKey.modEnvToPitch / 100;
550
+ note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
551
+ if (modEnvToPitch === 0)
552
+ return;
553
+ const basePitch = note.bufferSource.playbackRate.value;
554
+ const peekPitch = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset + modEnvToPitch);
555
+ const modDelay = startTime + instrumentKey.modDelay;
556
+ const modAttack = modDelay + instrumentKey.modAttack;
557
+ const modHold = modAttack + instrumentKey.modHold;
558
+ const modDecay = modHold + instrumentKey.modDecay;
559
+ note.bufferSource.playbackRate.value
560
+ .setValueAtTime(basePitch, modDelay)
561
+ .exponentialRampToValueAtTime(peekPitch, modAttack)
562
+ .setValueAtTime(peekPitch, modHold)
563
+ .linearRampToValueAtTime(basePitch, modDecay);
564
+ }
565
+ clampCutoffFrequency(frequency) {
566
+ const minFrequency = 20; // min Hz of initialFilterFc
567
+ const maxFrequency = 20000; // max Hz of initialFilterFc
568
+ return Math.max(minFrequency, Math.min(frequency, maxFrequency));
569
+ }
570
+ setFilterEnvelope(note) {
571
+ const { instrumentKey, startTime } = note;
572
+ const baseFreq = this.centToHz(instrumentKey.initialFilterFc);
573
+ const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc);
574
+ const sustainFreq = baseFreq +
575
+ (peekFreq - baseFreq) * (1 - instrumentKey.modSustain);
576
+ const adjustedBaseFreq = this.clampCutoffFrequency(baseFreq);
577
+ const adjustedPeekFreq = this.clampCutoffFrequency(peekFreq);
578
+ const adjustedSustainFreq = this.clampCutoffFrequency(sustainFreq);
534
579
  const modDelay = startTime + instrumentKey.modDelay;
535
580
  const modAttack = modDelay + instrumentKey.modAttack;
536
581
  const modHold = modAttack + instrumentKey.modHold;
537
582
  const modDecay = modHold + instrumentKey.modDecay;
538
- const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
539
- const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
540
- const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
541
- note.filterNode = new BiquadFilterNode(this.audioContext, {
542
- type: "lowpass",
543
- Q: instrumentKey.initialFilterQ / 10, // dB
544
- frequency: adjustedBaseFreq,
545
- });
546
583
  note.filterNode.frequency
584
+ .cancelScheduledValues(startTime)
585
+ .setValueAtTime(adjustedBaseFreq, startTime)
547
586
  .setValueAtTime(adjustedBaseFreq, modDelay)
548
587
  .exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
549
588
  .setValueAtTime(adjustedPeekFreq, modHold)
550
589
  .linearRampToValueAtTime(adjustedSustainFreq, modDecay);
551
- note.bufferSource.detune.setValueAtTime(note.bufferSource.detune.value + instrumentKey.modEnvToPitch, modDelay);
552
590
  }
553
- startModulation(channel, note, time) {
591
+ startModulation(channel, note, startTime) {
554
592
  const { instrumentKey } = note;
555
- note.modLFOGain = new GainNode(this.audioContext, {
556
- gain: this.cbToRatio(instrumentKey.modLfoToVolume + channel.modulation),
557
- });
558
- note.modLFO = new OscillatorNode(this.audioContext, {
593
+ const { modLfoToPitch, modLfoToVolume } = instrumentKey;
594
+ note.modulationLFO = new OscillatorNode(this.audioContext, {
559
595
  frequency: this.centToHz(instrumentKey.freqModLFO),
560
596
  });
561
- note.modLFO.start(time);
562
- note.filterNode.frequency.setValueAtTime(note.filterNode.frequency.value + instrumentKey.modLfoToFilterFc, time);
563
- note.bufferSource.detune.setValueAtTime(note.bufferSource.detune.value + instrumentKey.modLfoToPitch, time);
564
- note.modLFO.connect(note.modLFOGain);
565
- note.modLFOGain.connect(note.bufferSource.detune);
597
+ note.filterDepth = new GainNode(this.audioContext, {
598
+ gain: instrumentKey.modLfoToFilterFc,
599
+ });
600
+ const modulationDepth = Math.abs(modLfoToPitch) + channel.modulationDepth;
601
+ const modulationDepthSign = (0 < modLfoToPitch) ? 1 : -1;
602
+ note.modulationDepth = new GainNode(this.audioContext, {
603
+ gain: modulationDepth * modulationDepthSign,
604
+ });
605
+ const volumeDepth = this.cbToRatio(Math.abs(modLfoToVolume)) - 1;
606
+ const volumeDepthSign = (0 < modLfoToVolume) ? 1 : -1;
607
+ note.volumeDepth = new GainNode(this.audioContext, {
608
+ gain: volumeDepth * volumeDepthSign,
609
+ });
610
+ note.modulationLFO.start(startTime + instrumentKey.delayModLFO);
611
+ note.modulationLFO.connect(note.filterDepth);
612
+ note.filterDepth.connect(note.filterNode.frequency);
613
+ note.modulationLFO.connect(note.modulationDepth);
614
+ note.modulationDepth.connect(note.bufferSource.detune);
615
+ note.modulationLFO.connect(note.volumeDepth);
616
+ note.volumeDepth.connect(note.volumeNode.gain);
566
617
  }
567
618
  async createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3) {
568
619
  const semitoneOffset = this.calcSemitoneOffset(channel);
569
620
  const note = new Note(noteNumber, velocity, startTime, instrumentKey);
570
621
  note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
571
- note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
622
+ note.volumeNode = new GainNode(this.audioContext);
623
+ note.filterNode = new BiquadFilterNode(this.audioContext, {
624
+ type: "lowpass",
625
+ Q: instrumentKey.initialFilterQ / 10 * channel.filterResonance, // dB
626
+ });
572
627
  this.setVolumeEnvelope(note);
573
- this.setFilterEnvelope(channel, note);
574
- if (channel.modulation > 0) {
575
- const delayModLFO = startTime + instrumentKey.delayModLFO;
576
- this.startModulation(channel, note, delayModLFO);
628
+ this.setFilterEnvelope(note);
629
+ if (0 < channel.modulationDepth) {
630
+ this.setPitch(note, semitoneOffset);
631
+ this.startModulation(channel, note, startTime);
632
+ }
633
+ else {
634
+ note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
577
635
  }
578
636
  note.bufferSource.connect(note.filterNode);
579
- note.filterNode.connect(note.gainNode);
637
+ note.filterNode.connect(note.volumeNode);
580
638
  note.bufferSource.start(startTime, instrumentKey.start / instrumentKey.sampleRate);
581
639
  return note;
582
640
  }
@@ -592,8 +650,8 @@ export class MidyGM1 {
592
650
  if (!instrumentKey)
593
651
  return;
594
652
  const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
595
- note.gainNode.connect(channel.gainL);
596
- note.gainNode.connect(channel.gainR);
653
+ note.volumeNode.connect(channel.gainL);
654
+ note.volumeNode.connect(channel.gainR);
597
655
  const scheduledNotes = channel.scheduledNotes;
598
656
  if (scheduledNotes.has(noteNumber)) {
599
657
  scheduledNotes.get(noteNumber).push(note);
@@ -606,7 +664,7 @@ export class MidyGM1 {
606
664
  const now = this.audioContext.currentTime;
607
665
  return this.scheduleNoteOn(channelNumber, noteNumber, velocity, now);
608
666
  }
609
- scheduleNoteRelease(channelNumber, noteNumber, velocity, stopTime, stopPedal = false) {
667
+ scheduleNoteRelease(channelNumber, noteNumber, _velocity, stopTime, stopPedal = false) {
610
668
  const channel = this.channels[channelNumber];
611
669
  if (stopPedal && channel.sustainPedal)
612
670
  return;
@@ -619,20 +677,14 @@ export class MidyGM1 {
619
677
  continue;
620
678
  if (note.ending)
621
679
  continue;
622
- const velocityRate = (velocity + 127) / 127;
623
- const volEndTime = stopTime +
624
- note.instrumentKey.volRelease * velocityRate;
625
- note.gainNode.gain
680
+ const volEndTime = stopTime + note.instrumentKey.volRelease;
681
+ note.volumeNode.gain
626
682
  .cancelScheduledValues(stopTime)
627
683
  .linearRampToValueAtTime(0, volEndTime);
628
- const maxFreq = this.audioContext.sampleRate / 2;
629
- const baseFreq = this.centToHz(note.instrumentKey.initialFilterFc);
630
- const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
631
- const modEndTime = stopTime +
632
- note.instrumentKey.modRelease * velocityRate;
684
+ const modRelease = stopTime + note.instrumentKey.modRelease;
633
685
  note.filterNode.frequency
634
686
  .cancelScheduledValues(stopTime)
635
- .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
687
+ .linearRampToValueAtTime(0, modRelease);
636
688
  note.ending = true;
637
689
  this.scheduleTask(() => {
638
690
  note.bufferSource.loop = false;
@@ -641,15 +693,17 @@ export class MidyGM1 {
641
693
  note.bufferSource.onended = () => {
642
694
  scheduledNotes[i] = null;
643
695
  note.bufferSource.disconnect();
696
+ note.volumeNode.disconnect();
644
697
  note.filterNode.disconnect();
645
- note.gainNode.disconnect();
646
- if (note.modLFOGain)
647
- note.modLFOGain.disconnect();
648
- if (note.modLFO)
649
- note.modLFO.stop();
698
+ if (note.volumeDepth)
699
+ note.volumeDepth.disconnect();
700
+ if (note.modulationDepth)
701
+ note.modulationDepth.disconnect();
702
+ if (note.modulationLFO)
703
+ note.modulationLFO.stop();
650
704
  resolve();
651
705
  };
652
- bufferSource.stop(volEndTime);
706
+ note.bufferSource.stop(volEndTime);
653
707
  });
654
708
  }
655
709
  }
@@ -662,14 +716,15 @@ export class MidyGM1 {
662
716
  const channel = this.channels[channelNumber];
663
717
  const promises = [];
664
718
  channel.sustainPedal = false;
665
- channel.scheduledNotes.forEach((scheduledNotes) => {
666
- scheduledNotes.forEach((scheduledNote) => {
667
- if (scheduledNote) {
668
- const { noteNumber } = scheduledNote;
669
- const promise = this.releaseNote(channelNumber, noteNumber, velocity);
670
- promises.push(promise);
671
- }
672
- });
719
+ channel.scheduledNotes.forEach((noteList) => {
720
+ for (let i = 0; i < noteList.length; i++) {
721
+ const note = noteList[i];
722
+ if (!note)
723
+ continue;
724
+ const { noteNumber } = note;
725
+ const promise = this.releaseNote(channelNumber, noteNumber, velocity);
726
+ promises.push(promise);
727
+ }
673
728
  });
674
729
  return promises;
675
730
  }
@@ -710,7 +765,7 @@ export class MidyGM1 {
710
765
  handleControlChange(channelNumber, controller, value) {
711
766
  switch (controller) {
712
767
  case 1:
713
- return this.setModulation(channelNumber, value);
768
+ return this.setModulationDepth(channelNumber, value);
714
769
  case 6:
715
770
  return this.dataEntryMSB(channelNumber, value);
716
771
  case 7:
@@ -739,20 +794,25 @@ export class MidyGM1 {
739
794
  }
740
795
  updateModulation(channel) {
741
796
  const now = this.audioContext.currentTime;
742
- const activeNotes = this.getActiveNotes(channel, now);
743
- activeNotes.forEach((activeNote) => {
744
- if (activeNote.modLFO) {
745
- const { gainNode, instrumentKey } = activeNote;
746
- gainNode.gain.setValueAtTime(this.cbToRatio(instrumentKey.modLfoToVolume + channel.modulation), now);
747
- }
748
- else {
749
- this.startModulation(channel, activeNote, now);
797
+ channel.scheduledNotes.forEach((noteList) => {
798
+ for (let i = 0; i < noteList.length; i++) {
799
+ const note = noteList[i];
800
+ if (!note)
801
+ continue;
802
+ if (note.modulationDepth) {
803
+ note.modulationDepth.gain.setValueAtTime(channel.modulationDepth, now);
804
+ }
805
+ else {
806
+ const semitoneOffset = this.calcSemitoneOffset(channel);
807
+ this.setPitch(note, semitoneOffset);
808
+ this.startModulation(channel, note, now);
809
+ }
750
810
  }
751
811
  });
752
812
  }
753
- setModulation(channelNumber, modulation) {
813
+ setModulationDepth(channelNumber, modulation) {
754
814
  const channel = this.channels[channelNumber];
755
- channel.modulation = (modulation / 127) * channel.modulationDepthRange;
815
+ channel.modulationDepth = (modulation / 127) * channel.modulationDepthRange;
756
816
  this.updateModulation(channel);
757
817
  }
758
818
  setVolume(channelNumber, volume) {
@@ -854,13 +914,17 @@ export class MidyGM1 {
854
914
  }
855
915
  updateDetune(channel, detuneChange) {
856
916
  const now = this.audioContext.currentTime;
857
- const activeNotes = this.getActiveNotes(channel, now);
858
- activeNotes.forEach((activeNote) => {
859
- const { bufferSource } = activeNote;
860
- const detune = bufferSource.detune.value + detuneChange;
861
- bufferSource.detune
862
- .cancelScheduledValues(now)
863
- .setValueAtTime(detune, now);
917
+ channel.scheduledNotes.forEach((noteList) => {
918
+ for (let i = 0; i < noteList.length; i++) {
919
+ const note = noteList[i];
920
+ if (!note)
921
+ continue;
922
+ const { bufferSource } = note;
923
+ const detune = bufferSource.detune.value + detuneChange;
924
+ bufferSource.detune
925
+ .cancelScheduledValues(now)
926
+ .setValueAtTime(detune, now);
927
+ }
864
928
  });
865
929
  }
866
930
  handlePitchBendRangeRPN(channelNumber) {
@@ -904,37 +968,13 @@ export class MidyGM1 {
904
968
  this.updateDetune(channel, detuneChange);
905
969
  }
906
970
  allSoundOff(channelNumber) {
907
- const now = this.audioContext.currentTime;
908
- const channel = this.channels[channelNumber];
909
- const velocity = 0;
910
- const stopPedal = true;
911
- const promises = [];
912
- channel.scheduledNotes.forEach((noteList) => {
913
- const activeNote = this.getActiveNote(noteList, now);
914
- if (activeNote) {
915
- const notePromise = this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, stopPedal);
916
- promises.push(notePromise);
917
- }
918
- });
919
- return promises;
971
+ return this.stopChannelNotes(channelNumber, 0, true);
920
972
  }
921
973
  resetAllControllers(channelNumber) {
922
974
  Object.assign(this.channels[channelNumber], this.effectSettings);
923
975
  }
924
976
  allNotesOff(channelNumber) {
925
- const now = this.audioContext.currentTime;
926
- const channel = this.channels[channelNumber];
927
- const velocity = 0;
928
- const stopPedal = false;
929
- const promises = [];
930
- channel.scheduledNotes.forEach((noteList) => {
931
- const activeNote = this.getActiveNote(noteList, now);
932
- if (activeNote) {
933
- const notePromise = this.scheduleNoteRelease(channelNumber, activeNote.noteNumber, velocity, now, stopPedal);
934
- promises.push(notePromise);
935
- }
936
- });
937
- return promises;
977
+ return this.stopChannelNotes(channelNumber, 0, false);
938
978
  }
939
979
  handleUniversalNonRealTimeExclusiveMessage(data) {
940
980
  switch (data[2]) {
@@ -1029,7 +1069,7 @@ Object.defineProperty(MidyGM1, "channelSettings", {
1029
1069
  pitchBend: 0,
1030
1070
  fineTuning: 0, // cb
1031
1071
  coarseTuning: 0, // cb
1032
- modulationDepthRange: 0.5, // cb
1072
+ modulationDepthRange: 50, // cent
1033
1073
  }
1034
1074
  });
1035
1075
  Object.defineProperty(MidyGM1, "effectSettings", {
@@ -1038,7 +1078,7 @@ Object.defineProperty(MidyGM1, "effectSettings", {
1038
1078
  writable: true,
1039
1079
  value: {
1040
1080
  expression: 1,
1041
- modulation: 0,
1081
+ modulationDepth: 0,
1042
1082
  sustainPedal: false,
1043
1083
  rpnMSB: 127,
1044
1084
  rpnLSB: 127,
package/esm/midy-GM2.d.ts CHANGED
@@ -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":"AAwBA;IAkCE;;;;;;;;;;;;;;;;;;;;MAoBE;IAEF;;;;;;;;;;;MAWE;IAEF;;;;;;;MAOE;IAgCF;;;;;OAWC;IAtHD,qBAAmB;IACnB,kBAAc;IACd,yBAAqB;IACrB,2BAAuB;IACvB;;;MAGE;IACF;;;;;;MAME;IACF,cAAa;IACb,cAAa;IACb,0BAAwB;IACxB,kBAAc;IACd,mBAAiB;IACjB,kBAAc;IACd,mBAAe;IACf,kBAAgB;IAChB,sBAA2C;IAC3C,mBAAkB;IAClB,mBAAkB;IAClB,kBAAiB;IACjB,oBAAmB;IACnB,mBAAkB;IAClB,gBAAc;IACd,mBAAiB;IACjB,oBAAkB;IA8ClB;;;;;MA4BE;IAGA,kBAAgC;IAChC;;;;;MAAqD;IACrD,gBAA4C;IAC5C,gBAAiD;IACjD;;;MAA8D;IAC9D;;;;;;;;MAAyD;IAO3D,4BAMC;IAED,mCASC;IAED,gDAMC;IAED,sCASC;IAED;;;;MAeC;IAED,yCAcC;IAED,+DAyBC;IAED,mEAWC;IAED,qDAOC;IAED,2EAkDC;IAED,mCAOC;IAED,0BA+CC;IAED,uDAEC;IAED,wDAEC;IAED;;;MAgGC;IAED,mFAmBC;IAED,yDAKC;IAED,uBAKC;IAED,aAGC;IAED,cAKC;IAED,wBAIC;IAED,0BAKC;IAED,wBAOC;IAED,sBAGC;IAED,uDASC;IAED,6CAQC;IAED,kFAuBC;IAED;;;;MAWC;IAED,gFAUC;IAED,mFAYC;IAED,sGAcC;IAID;;;MA+BC;IAED;;;;;;;;MA0CC;IAED,2BAEC;IAED,4BAEC;IAED,sCAKC;IAED,mFAGC;IAED,mCAeC;IAED,+CAwBC;IAED,6CAIC;IAED,iDAyBC;IAED,+DA0BC;IAED,4DAiBC;IAED,wHA0CC;IAED,gDAQC;IAED,kGAgCC;IAED,0EAGC;IAED,uIA4CC;IAED,0FAGC;IAED,kEAeC;IAED,oEAYC;IAED,gFAmBC;IAED,4DAIC;IAED,+DAcC;IAED,qEAGC;IAED,uDAOC;IAED,2FAuDC;IAED,+CAEC;IAED,qCAkBC;IAED,8DAIC;IAED,iEAEC;IAED,iDAIC;IAED;;;MAMC;IAED,2CAIC;IAED,yDAIC;IAED,+CAEC;IAED,mDAGC;IAED,sCAUC;IAED,sDAMC;IAGD,oDAEC;IAED,mEAWC;IAED,mEAWC;IAED,wDAWC;IAED,uDAGC;IAED,kFAeC;IAED,2DAMC;IAED,oCAqBC;IAED,gDAEC;IAED,gDAEC;IAED,mDAGC;IAED,oDAaC;IAED,kDAKC;IAED,iEAOC;IAED,8CAKC;IAED,yDAMC;IAED,gDAKC;IAED,6DAMC;IAED,wDAKC;IAED,6EAKC;IAED,+CAEC;IAED,8CAEC;IAED,+CAEC;IAED,gBAEC;IAED,eAEC;IAED,eAEC;IAED,eAEC;IAED,4DAmBC;IAED,oBAQC;IAED,oBAQC;IAED,yDAiDC;IAED,yCAGC;IAED,mCAQC;IAED,6CAGC;IAED,2CAMC;IAED,+CAGC;IAED,+CAMC;IAED,mDAeC;IAED,4CAOC;IAED,+BAKC;IAED,qDAiBC;IAED,gCAMC;IAED,kCAEC;IA6BD,4CAEC;IAED,4CAaC;IAED,+BAiBC;IAED,wFAKC;IAED,mCAQC;IAED,qCAEC;IAED,oCAUC;IAED,sCAEC;IAED,oCAaC;IAED,sCAEC;IAED,wCAWC;IAED,0CAEC;IAED,wCAEC;IAED,6BASC;IAED,0DAUC;CACF;AAhyDD;IAUE,gFAKC;IAdD,kBAAa;IACb,gBAAW;IACX,gBAAW;IACX,iBAAY;IACZ,mBAAc;IACd,qBAAgB;IAChB,gBAAW;IACX,kBAAa;IAGX,gBAA4B;IAC5B,cAAwB;IACxB,eAA0B;IAC1B,mBAAkC;CAErC"}