@marmooo/midy 0.1.2 → 0.1.3

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 +17 -12
  5. package/esm/midy-GM1.d.ts.map +1 -1
  6. package/esm/midy-GM1.js +125 -96
  7. package/esm/midy-GM2.d.ts +21 -14
  8. package/esm/midy-GM2.d.ts.map +1 -1
  9. package/esm/midy-GM2.js +146 -107
  10. package/esm/midy-GMLite.d.ts +15 -12
  11. package/esm/midy-GMLite.d.ts.map +1 -1
  12. package/esm/midy-GMLite.js +115 -98
  13. package/esm/midy.d.ts +18 -15
  14. package/esm/midy.d.ts.map +1 -1
  15. package/esm/midy.js +147 -134
  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 +17 -12
  21. package/script/midy-GM1.d.ts.map +1 -1
  22. package/script/midy-GM1.js +125 -96
  23. package/script/midy-GM2.d.ts +21 -14
  24. package/script/midy-GM2.d.ts.map +1 -1
  25. package/script/midy-GM2.js +146 -107
  26. package/script/midy-GMLite.d.ts +15 -12
  27. package/script/midy-GMLite.d.ts.map +1 -1
  28. package/script/midy-GMLite.js +115 -98
  29. package/script/midy.d.ts +18 -15
  30. package/script/midy.d.ts.map +1 -1
  31. package/script/midy.js +147 -134
  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.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,37 +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", {
18
24
  enumerable: true,
19
25
  configurable: true,
20
26
  writable: true,
21
27
  value: void 0
22
28
  });
23
- Object.defineProperty(this, "modLFO", {
29
+ Object.defineProperty(this, "modulationLFO", {
24
30
  enumerable: true,
25
31
  configurable: true,
26
32
  writable: true,
27
33
  value: void 0
28
34
  });
29
- Object.defineProperty(this, "modLFOGain", {
35
+ Object.defineProperty(this, "modulationDepth", {
30
36
  enumerable: true,
31
37
  configurable: true,
32
38
  writable: true,
33
39
  value: void 0
34
40
  });
35
- Object.defineProperty(this, "vibLFO", {
41
+ Object.defineProperty(this, "vibratoLFO", {
36
42
  enumerable: true,
37
43
  configurable: true,
38
44
  writable: true,
39
45
  value: void 0
40
46
  });
41
- Object.defineProperty(this, "vibLFOGain", {
47
+ Object.defineProperty(this, "vibratoDepth", {
42
48
  enumerable: true,
43
49
  configurable: true,
44
50
  writable: true,
@@ -410,7 +416,7 @@ export class Midy {
410
416
  const t = this.audioContext.currentTime + offset;
411
417
  queueIndex = await this.scheduleTimelineEvents(t, offset, queueIndex);
412
418
  if (this.isPausing) {
413
- await this.stopNotes();
419
+ await this.stopNotes(0, true);
414
420
  this.notePromises = [];
415
421
  resolve();
416
422
  this.isPausing = false;
@@ -418,7 +424,7 @@ export class Midy {
418
424
  return;
419
425
  }
420
426
  else if (this.isStopping) {
421
- await this.stopNotes();
427
+ await this.stopNotes(0, true);
422
428
  this.notePromises = [];
423
429
  resolve();
424
430
  this.isStopping = false;
@@ -426,7 +432,7 @@ export class Midy {
426
432
  return;
427
433
  }
428
434
  else if (this.isSeeking) {
429
- this.stopNotes();
435
+ this.stopNotes(0, true);
430
436
  this.startTime = this.audioContext.currentTime;
431
437
  queueIndex = this.getQueueIndex(this.resumeTime);
432
438
  offset = this.resumeTime - this.startTime;
@@ -541,21 +547,24 @@ export class Midy {
541
547
  }
542
548
  return { instruments, timeline };
543
549
  }
544
- stopNotes() {
550
+ async stopChannelNotes(channelNumber, velocity, stopPedal) {
545
551
  const now = this.audioContext.currentTime;
546
- const velocity = 0;
547
- const stopPedal = true;
548
- this.channels.forEach((channel, channelNumber) => {
549
- channel.scheduledNotes.forEach((scheduledNotes) => {
550
- scheduledNotes.forEach((scheduledNote) => {
551
- if (scheduledNote) {
552
- const promise = this.scheduleNoteRelease(channelNumber, scheduledNote.noteNumber, velocity, now, stopPedal);
553
- this.notePromises.push(promise);
554
- }
555
- });
552
+ const channel = this.channels[channelNumber];
553
+ channel.scheduledNotes.forEach((noteList) => {
554
+ noteList.forEach((note) => {
555
+ if (note) {
556
+ const promise = this.scheduleNoteRelease(channelNumber, note.noteNumber, velocity, now, stopPedal);
557
+ this.notePromises.push(promise);
558
+ }
556
559
  });
557
- channel.scheduledNotes.clear();
558
560
  });
561
+ channel.scheduledNotes.clear();
562
+ await Promise.all(this.notePromises);
563
+ }
564
+ stopNotes(velocity, stopPedal) {
565
+ for (let i = 0; i < this.channels.length; i++) {
566
+ this.stopChannelNotes(i, velocity, stopPedal);
567
+ }
559
568
  return Promise.all(this.notePromises);
560
569
  }
561
570
  async start() {
@@ -770,36 +779,54 @@ export class Midy {
770
779
  }
771
780
  setVolumeEnvelope(note) {
772
781
  const { instrumentKey, startTime } = note;
773
- note.gainNode = new GainNode(this.audioContext, { gain: 0 });
782
+ note.volumeNode = new GainNode(this.audioContext, { gain: 0 });
774
783
  const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
775
784
  const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
776
785
  const volDelay = startTime + instrumentKey.volDelay;
777
786
  const volAttack = volDelay + instrumentKey.volAttack;
778
787
  const volHold = volAttack + instrumentKey.volHold;
779
788
  const volDecay = volHold + instrumentKey.volDecay;
780
- note.gainNode.gain
789
+ note.volumeNode.gain
781
790
  .setValueAtTime(1e-6, volDelay) // exponentialRampToValueAtTime() requires a non-zero value
782
791
  .exponentialRampToValueAtTime(attackVolume, volAttack)
783
792
  .setValueAtTime(attackVolume, volHold)
784
793
  .linearRampToValueAtTime(sustainVolume, volDecay);
785
794
  }
786
- setFilterEnvelope(channel, note) {
787
- const { instrumentKey, startTime, noteNumber } = note;
795
+ setPitch(note, semitoneOffset) {
796
+ const { instrumentKey, noteNumber, startTime } = note;
797
+ const modEnvToPitch = instrumentKey.modEnvToPitch / 100;
798
+ note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
799
+ if (modEnvToPitch === 0)
800
+ return;
801
+ const basePitch = note.bufferSource.playbackRate.value;
802
+ const peekPitch = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset + modEnvToPitch);
803
+ const modDelay = startTime + instrumentKey.modDelay;
804
+ const modAttack = modDelay + instrumentKey.modAttack;
805
+ const modHold = modAttack + instrumentKey.modHold;
806
+ const modDecay = modHold + instrumentKey.modDecay;
807
+ note.bufferSource.playbackRate.value
808
+ .setValueAtTime(basePitch, modDelay)
809
+ .exponentialRampToValueAtTime(peekPitch, modAttack)
810
+ .setValueAtTime(peekPitch, modHold)
811
+ .linearRampToValueAtTime(basePitch, modDecay);
812
+ }
813
+ setFilterNode(channel, note) {
814
+ const { instrumentKey, noteNumber, startTime } = note;
788
815
  const softPedalFactor = 1 -
789
816
  (0.1 + (noteNumber / 127) * 0.2) * channel.softPedal;
790
817
  const maxFreq = this.audioContext.sampleRate / 2;
791
818
  const baseFreq = this.centToHz(instrumentKey.initialFilterFc) *
792
819
  softPedalFactor;
793
820
  const peekFreq = this.centToHz(instrumentKey.initialFilterFc + instrumentKey.modEnvToFilterFc) * softPedalFactor;
794
- const sustainFreq = (baseFreq +
795
- (peekFreq - baseFreq) * (1 - instrumentKey.modSustain)) * softPedalFactor;
821
+ const sustainFreq = baseFreq +
822
+ (peekFreq - baseFreq) * (1 - instrumentKey.modSustain);
823
+ const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
824
+ const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
825
+ const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
796
826
  const modDelay = startTime + instrumentKey.modDelay;
797
827
  const modAttack = modDelay + instrumentKey.modAttack;
798
828
  const modHold = modAttack + instrumentKey.modHold;
799
829
  const modDecay = modHold + instrumentKey.modDecay;
800
- const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
801
- const adjustedPeekFreq = Math.min(maxFreq, peekFreq);
802
- const adjustedSustainFreq = Math.min(maxFreq, sustainFreq);
803
830
  note.filterNode = new BiquadFilterNode(this.audioContext, {
804
831
  type: "lowpass",
805
832
  Q: instrumentKey.initialFilterQ / 10, // dB
@@ -810,56 +837,72 @@ export class Midy {
810
837
  .exponentialRampToValueAtTime(adjustedPeekFreq, modAttack)
811
838
  .setValueAtTime(adjustedPeekFreq, modHold)
812
839
  .linearRampToValueAtTime(adjustedSustainFreq, modDecay);
813
- note.bufferSource.detune.setValueAtTime(note.bufferSource.detune.value + instrumentKey.modEnvToPitch, modDelay);
814
840
  }
815
- startModulation(channel, note, time) {
841
+ startModulation(channel, note, startTime) {
816
842
  const { instrumentKey } = note;
817
- note.modLFOGain = new GainNode(this.audioContext, {
818
- gain: this.cbToRatio(instrumentKey.modLfoToVolume + channel.modulation),
819
- });
820
- note.modLFO = new OscillatorNode(this.audioContext, {
843
+ const { modLfoToPitch, modLfoToVolume } = instrumentKey;
844
+ note.modulationLFO = new OscillatorNode(this.audioContext, {
821
845
  frequency: this.centToHz(instrumentKey.freqModLFO),
822
846
  });
823
- note.modLFO.start(time);
824
- note.filterNode.frequency.setValueAtTime(note.filterNode.frequency.value + instrumentKey.modLfoToFilterFc, time);
825
- note.bufferSource.detune.setValueAtTime(note.bufferSource.detune.value + instrumentKey.modLfoToPitch, time);
826
- note.modLFO.connect(note.modLFOGain);
827
- note.modLFOGain.connect(note.bufferSource.detune);
828
- }
829
- startVibrato(channel, note, time) {
830
- const { instrumentKey } = note;
831
- note.vibLFOGain = new GainNode(this.audioContext, {
832
- gain: channel.vibratoDepth,
847
+ note.filterDepth = new GainNode(this.audioContext, {
848
+ gain: instrumentKey.modLfoToFilterFc,
849
+ });
850
+ const modulationDepth = Math.abs(modLfoToPitch) + channel.modulationDepth;
851
+ const modulationDepthSign = (0 < modLfoToPitch) ? 1 : -1;
852
+ note.modulationDepth = new GainNode(this.audioContext, {
853
+ gain: modulationDepth * modulationDepthSign,
854
+ });
855
+ const volumeDepth = this.cbToRatio(Math.abs(modLfoToVolume)) - 1;
856
+ const volumeDepthSign = (0 < modLfoToVolume) ? 1 : -1;
857
+ note.volumeDepth = new GainNode(this.audioContext, {
858
+ gain: volumeDepth * volumeDepthSign,
833
859
  });
834
- note.vibLFO = new OscillatorNode(this.audioContext, {
835
- frequency: this.centToHz(instrumentKey.freqModLFO) +
860
+ note.modulationLFO.start(startTime + instrumentKey.delayModLFO);
861
+ note.modulationLFO.connect(note.filterDepth);
862
+ note.filterDepth.connect(note.filterNode.frequency);
863
+ note.modulationLFO.connect(note.modulationDepth);
864
+ note.modulationDepth.connect(note.bufferSource.detune);
865
+ note.modulationLFO.connect(note.volumeDepth);
866
+ note.volumeDepth.connect(note.volumeNode.gain);
867
+ }
868
+ startVibrato(channel, note, startTime) {
869
+ const { instrumentKey } = note;
870
+ const { vibLfoToPitch } = instrumentKey;
871
+ note.vibratoLFO = new OscillatorNode(this.audioContext, {
872
+ frequency: this.centToHz(instrumentKey.freqVibLFO) *
836
873
  channel.vibratoRate,
837
874
  });
838
- note.vibLFO.start(time + channel.vibratoDelay);
839
- note.vibLFO.connect(note.vibLFOGain);
840
- note.vibLFOGain.connect(note.bufferSource.detune);
875
+ const vibratoDepth = Math.abs(vibLfoToPitch) * channel.vibratoDepth;
876
+ const vibratoDepthSign = 0 < vibLfoToPitch;
877
+ note.vibratoDepth = new GainNode(this.audioContext, {
878
+ gain: vibratoDepth * vibratoDepthSign,
879
+ });
880
+ note.vibratoLFO.start(startTime + instrumentKey.delayVibLFO * channel.vibratoDelay);
881
+ note.vibratoLFO.connect(note.vibratoDepth);
882
+ note.vibratoDepth.connect(note.bufferSource.detune);
841
883
  }
842
884
  async createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3) {
843
885
  const semitoneOffset = this.calcSemitoneOffset(channel);
844
886
  const note = new Note(noteNumber, velocity, startTime, instrumentKey);
845
887
  note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
846
- note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
888
+ this.setFilterNode(channel, note);
847
889
  this.setVolumeEnvelope(note);
848
- this.setFilterEnvelope(channel, note);
849
- if (channel.modulation > 0) {
850
- const delayModLFO = startTime + instrumentKey.delayModLFO;
851
- this.startModulation(channel, note, delayModLFO);
890
+ if (0 < channel.vibratoDepth) {
891
+ this.startVibrato(channel, note, startTime);
852
892
  }
853
- if (channel.vibratoDepth > 0) {
854
- const delayVibLFO = startTime + instrumentKey.delayVibLFO;
855
- this.startVibrato(channel, note, delayVibLFO);
893
+ if (0 < channel.modulationDepth) {
894
+ this.setPitch(note, semitoneOffset);
895
+ this.startModulation(channel, note, startTime);
896
+ }
897
+ else {
898
+ note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
856
899
  }
857
900
  if (this.mono && channel.currentBufferSource) {
858
901
  channel.currentBufferSource.stop(startTime);
859
902
  channel.currentBufferSource = note.bufferSource;
860
903
  }
861
904
  note.bufferSource.connect(note.filterNode);
862
- note.filterNode.connect(note.gainNode);
905
+ note.filterNode.connect(note.volumeNode);
863
906
  note.bufferSource.start(startTime, instrumentKey.start / instrumentKey.sampleRate);
864
907
  return note;
865
908
  }
@@ -884,8 +927,8 @@ export class Midy {
884
927
  if (!instrumentKey)
885
928
  return;
886
929
  const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
887
- note.gainNode.connect(channel.gainL);
888
- note.gainNode.connect(channel.gainR);
930
+ note.volumeNode.connect(channel.gainL);
931
+ note.volumeNode.connect(channel.gainR);
889
932
  if (channel.sostenutoPedal) {
890
933
  channel.sostenutoNotes.set(noteNumber, note);
891
934
  }
@@ -919,17 +962,14 @@ export class Midy {
919
962
  const velocityRate = (velocity + 127) / 127;
920
963
  const volEndTime = stopTime +
921
964
  note.instrumentKey.volRelease * velocityRate;
922
- note.gainNode.gain
965
+ note.volumeNode.gain
923
966
  .cancelScheduledValues(stopTime)
924
967
  .linearRampToValueAtTime(0, volEndTime);
925
- const maxFreq = this.audioContext.sampleRate / 2;
926
- const baseFreq = this.centToHz(note.instrumentKey.initialFilterFc);
927
- const adjustedBaseFreq = Math.min(maxFreq, baseFreq);
928
- const modEndTime = stopTime +
968
+ const modRelease = stopTime +
929
969
  note.instrumentKey.modRelease * velocityRate;
930
970
  note.filterNode.frequency
931
971
  .cancelScheduledValues(stopTime)
932
- .linearRampToValueAtTime(adjustedBaseFreq, modEndTime);
972
+ .linearRampToValueAtTime(0, modRelease);
933
973
  note.ending = true;
934
974
  this.scheduleTask(() => {
935
975
  note.bufferSource.loop = false;
@@ -938,16 +978,18 @@ export class Midy {
938
978
  note.bufferSource.onended = () => {
939
979
  scheduledNotes[i] = null;
940
980
  note.bufferSource.disconnect();
981
+ note.volumeNode.disconnect();
941
982
  note.filterNode.disconnect();
942
- note.gainNode.disconnect();
943
- if (note.modLFOGain)
944
- note.modLFOGain.disconnect();
945
- if (note.vibLFOGain)
946
- note.vibLFOGain.disconnect();
947
- if (note.modLFO)
948
- note.modLFO.stop();
949
- if (note.vibLFO)
950
- note.vibLFO.stop();
983
+ if (note.volumeDepth)
984
+ note.volumeDepth.disconnect();
985
+ if (note.modulationDepth)
986
+ note.modulationDepth.disconnect();
987
+ if (note.modulationLFO)
988
+ note.modulationLFO.stop();
989
+ if (note.vibratoDepth)
990
+ note.vibratoDepth.disconnect();
991
+ if (note.vibratoLFO)
992
+ note.vibratoLFO.stop();
951
993
  resolve();
952
994
  };
953
995
  note.bufferSource.stop(volEndTime);
@@ -963,10 +1005,10 @@ export class Midy {
963
1005
  const channel = this.channels[channelNumber];
964
1006
  const promises = [];
965
1007
  channel.sustainPedal = false;
966
- channel.scheduledNotes.forEach((scheduledNotes) => {
967
- scheduledNotes.forEach((scheduledNote) => {
968
- if (scheduledNote) {
969
- const { noteNumber } = scheduledNote;
1008
+ channel.scheduledNotes.forEach((noteList) => {
1009
+ noteList.forEach((note) => {
1010
+ if (note) {
1011
+ const { noteNumber } = note;
970
1012
  const promise = this.releaseNote(channelNumber, noteNumber, velocity);
971
1013
  promises.push(promise);
972
1014
  }
@@ -1017,8 +1059,8 @@ export class Midy {
1017
1059
  if (channel.polyphonicKeyPressure.amplitudeControl !== 1) {
1018
1060
  if (activeNotes.has(noteNumber)) {
1019
1061
  const activeNote = activeNotes.get(noteNumber);
1020
- const gain = activeNote.gainNode.gain.value;
1021
- activeNote.gainNode.gain
1062
+ const gain = activeNote.volumeNode.gain.value;
1063
+ activeNote.volumeNode.gain
1022
1064
  .cancelScheduledValues(now)
1023
1065
  .setValueAtTime(gain * pressure, now);
1024
1066
  }
@@ -1037,8 +1079,8 @@ export class Midy {
1037
1079
  const activeNotes = this.getActiveNotes(channel, now);
1038
1080
  if (channel.channelPressure.amplitudeControl !== 1) {
1039
1081
  activeNotes.forEach((activeNote) => {
1040
- const gain = activeNote.gainNode.gain.value;
1041
- activeNote.gainNode.gain
1082
+ const gain = activeNote.volumeNode.gain.value;
1083
+ activeNote.volumeNode.gain
1042
1084
  .cancelScheduledValues(now)
1043
1085
  .setValueAtTime(gain * pressure, now);
1044
1086
  });
@@ -1061,7 +1103,7 @@ export class Midy {
1061
1103
  case 0:
1062
1104
  return this.setBankMSB(channelNumber, value);
1063
1105
  case 1:
1064
- return this.setModulation(channelNumber, value);
1106
+ return this.setModulationDepth(channelNumber, value);
1065
1107
  case 5:
1066
1108
  return this.setPortamentoTime(channelNumber, value);
1067
1109
  case 6:
@@ -1128,18 +1170,19 @@ export class Midy {
1128
1170
  const now = this.audioContext.currentTime;
1129
1171
  const activeNotes = this.getActiveNotes(channel, now);
1130
1172
  activeNotes.forEach((activeNote) => {
1131
- if (activeNote.modLFO) {
1132
- const { gainNode, instrumentKey } = activeNote;
1133
- gainNode.gain.setValueAtTime(this.cbToRatio(instrumentKey.modLfoToVolume + channel.modulation), now);
1173
+ if (activeNote.modulationDepth) {
1174
+ activeNote.modulationDepth.gain.setValueAtTime(channel.modulationDepth, now);
1134
1175
  }
1135
1176
  else {
1177
+ const semitoneOffset = this.calcSemitoneOffset(channel);
1178
+ this.setPitch(activeNote, semitoneOffset);
1136
1179
  this.startModulation(channel, activeNote, now);
1137
1180
  }
1138
1181
  });
1139
1182
  }
1140
- setModulation(channelNumber, modulation) {
1183
+ setModulationDepth(channelNumber, modulation) {
1141
1184
  const channel = this.channels[channelNumber];
1142
- channel.modulation = (modulation / 127) * channel.modulationDepthRange;
1185
+ channel.modulationDepth = (modulation / 127) * channel.modulationDepthRange;
1143
1186
  this.updateModulation(channel);
1144
1187
  }
1145
1188
  setPortamentoTime(channelNumber, portamentoTime) {
@@ -1241,21 +1284,15 @@ export class Midy {
1241
1284
  }
1242
1285
  setVibratoRate(channelNumber, vibratoRate) {
1243
1286
  const channel = this.channels[channelNumber];
1244
- channel.vibratoRate = vibratoRate / 127 * 4 + 3; // 3-7Hz
1287
+ channel.vibratoRate = vibratoRate / 64;
1245
1288
  }
1246
1289
  setVibratoDepth(channelNumber, vibratoDepth) {
1247
1290
  const channel = this.channels[channelNumber];
1248
- channel.vibratoDepth = vibratoDepth / 127;
1291
+ channel.vibratoDepth = vibratoDepth / 64;
1249
1292
  }
1250
1293
  setVibratoDelay(channelNumber, vibratoDelay) {
1251
- // Access Virus: 0-10sec
1252
- // Elektron: 0-5sec
1253
- // Korg: 0-5sec
1254
- // Nord: 0-5sec
1255
- // Roland: 0-5sec
1256
- // Yamaha: 0-8sec
1257
1294
  const channel = this.channels[channelNumber];
1258
- channel.vibratoDelay = vibratoDelay / 127 * 5; // 0-5sec
1295
+ channel.vibratoDelay = vibratoDelay / 64;
1259
1296
  }
1260
1297
  limitData(channel, minMSB, maxMSB, minLSB, maxLSB) {
1261
1298
  if (maxLSB < channel.dataLSB) {
@@ -1377,47 +1414,23 @@ export class Midy {
1377
1414
  handleModulationDepthRangeRPN(channelNumber) {
1378
1415
  const channel = this.channels[channelNumber];
1379
1416
  this.limitData(channel, 0, 127, 0, 127);
1380
- const modulationDepthRange = dataMSB + dataLSB / 128;
1417
+ const modulationDepthRange = (dataMSB + dataLSB / 128) * 100;
1381
1418
  this.setModulationDepthRange(channelNumber, modulationDepthRange);
1382
1419
  }
1383
1420
  setModulationDepthRange(channelNumber, modulationDepthRange) {
1384
1421
  const channel = this.channels[channelNumber];
1385
1422
  channel.modulationDepthRange = modulationDepthRange;
1386
- channel.modulation = (modulation / 127) * channel.modulationDepthRange;
1423
+ channel.modulationDepth = (modulation / 127) * modulationDepthRange;
1387
1424
  this.updateModulation(channel);
1388
1425
  }
1389
1426
  allSoundOff(channelNumber) {
1390
- const now = this.audioContext.currentTime;
1391
- const channel = this.channels[channelNumber];
1392
- const velocity = 0;
1393
- const stopPedal = true;
1394
- const promises = [];
1395
- channel.scheduledNotes.forEach((noteList) => {
1396
- const activeNote = this.getActiveNote(noteList, now);
1397
- if (activeNote) {
1398
- const notePromise = this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, stopPedal);
1399
- promises.push(notePromise);
1400
- }
1401
- });
1402
- return promises;
1427
+ return this.stopChannelNotes(channelNumber, 0, true);
1403
1428
  }
1404
1429
  resetAllControllers(channelNumber) {
1405
1430
  Object.assign(this.channels[channelNumber], this.effectSettings);
1406
1431
  }
1407
1432
  allNotesOff(channelNumber) {
1408
- const now = this.audioContext.currentTime;
1409
- const channel = this.channels[channelNumber];
1410
- const velocity = 0;
1411
- const stopPedal = false;
1412
- const promises = [];
1413
- channel.scheduledNotes.forEach((noteList) => {
1414
- const activeNote = this.getActiveNote(noteList, now);
1415
- if (activeNote) {
1416
- const notePromise = this.scheduleNoteRelease(channelNumber, activeNote.noteNumber, velocity, now, stopPedal);
1417
- promises.push(notePromise);
1418
- }
1419
- });
1420
- return promises;
1433
+ return this.stopChannelNotes(channelNumber, 0, false);
1421
1434
  }
1422
1435
  omniOff() {
1423
1436
  this.omni = false;
@@ -1777,9 +1790,9 @@ Object.defineProperty(Midy, "channelSettings", {
1777
1790
  portamentoTime: 0,
1778
1791
  reverbSendLevel: 0,
1779
1792
  chorusSendLevel: 0,
1780
- vibratoRate: 5,
1781
- vibratoDepth: 0.5,
1782
- vibratoDelay: 2.5,
1793
+ vibratoRate: 1,
1794
+ vibratoDepth: 1,
1795
+ vibratoDelay: 1,
1783
1796
  bank: 121 * 128,
1784
1797
  bankMSB: 121,
1785
1798
  bankLSB: 0,
@@ -1789,7 +1802,7 @@ Object.defineProperty(Midy, "channelSettings", {
1789
1802
  pitchBend: 0,
1790
1803
  fineTuning: 0, // cb
1791
1804
  coarseTuning: 0, // cb
1792
- modulationDepthRange: 0.5, // cb
1805
+ modulationDepthRange: 50, // cent
1793
1806
  }
1794
1807
  });
1795
1808
  Object.defineProperty(Midy, "effectSettings", {
@@ -1798,7 +1811,7 @@ Object.defineProperty(Midy, "effectSettings", {
1798
1811
  writable: true,
1799
1812
  value: {
1800
1813
  expression: 1,
1801
- modulation: 0,
1814
+ modulationDepth: 0,
1802
1815
  sustainPedal: false,
1803
1816
  portamento: false,
1804
1817
  sostenutoPedal: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marmooo/midy",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "A MIDI player/synthesizer written in JavaScript that supports GM-Lite/GM1 and SF2/SF3.",
5
5
  "repository": {
6
6
  "type": "git",