@marmooo/midy 0.1.1 → 0.1.2

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.
@@ -147,8 +147,8 @@ class MidyGMLite {
147
147
  });
148
148
  this.audioContext = audioContext;
149
149
  this.masterGain = new GainNode(audioContext);
150
- this.masterGain.connect(audioContext.destination);
151
150
  this.channels = this.createChannels(audioContext);
151
+ this.masterGain.connect(audioContext.destination);
152
152
  this.GM1SystemOn();
153
153
  }
154
154
  initSoundFontTable() {
@@ -192,6 +192,7 @@ class MidyGMLite {
192
192
  const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
193
193
  gainL.connect(merger, 0, 0);
194
194
  gainR.connect(merger, 0, 1);
195
+ merger.connect(this.masterGain);
195
196
  return {
196
197
  gainL,
197
198
  gainR,
@@ -494,10 +495,6 @@ class MidyGMLite {
494
495
  }
495
496
  return noteList[0];
496
497
  }
497
- connectEffects(channel, gainNode) {
498
- gainNode.connect(channel.merger);
499
- merger.connect(this.masterGain);
500
- }
501
498
  cbToRatio(cb) {
502
499
  return Math.pow(10, cb / 200);
503
500
  }
@@ -511,14 +508,10 @@ class MidyGMLite {
511
508
  return instrumentKey.playbackRate(noteNumber) *
512
509
  Math.pow(2, semitoneOffset / 12);
513
510
  }
514
- setVolumeEnvelope(channel, note) {
515
- const { instrumentKey, startTime, velocity } = note;
511
+ setVolumeEnvelope(note) {
512
+ const { instrumentKey, startTime } = note;
516
513
  note.gainNode = new GainNode(this.audioContext, { gain: 0 });
517
- let volume = (velocity / 127) * channel.volume * channel.expression;
518
- if (volume === 0)
519
- volume = 1e-6; // exponentialRampToValueAtTime() requires a non-zero value
520
- const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation) *
521
- volume;
514
+ const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
522
515
  const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
523
516
  const volDelay = startTime + instrumentKey.volDelay;
524
517
  const volAttack = volDelay + instrumentKey.volAttack;
@@ -578,7 +571,7 @@ class MidyGMLite {
578
571
  const note = new Note(noteNumber, velocity, startTime, instrumentKey);
579
572
  note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
580
573
  note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
581
- this.setVolumeEnvelope(channel, note);
574
+ this.setVolumeEnvelope(note);
582
575
  this.setFilterEnvelope(channel, note);
583
576
  if (channel.modulation > 0) {
584
577
  const delayModLFO = startTime + instrumentKey.delayModLFO;
@@ -601,7 +594,8 @@ class MidyGMLite {
601
594
  if (!instrumentKey)
602
595
  return;
603
596
  const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
604
- this.connectEffects(channel, note.gainNode);
597
+ note.gainNode.connect(channel.gainL);
598
+ note.gainNode.connect(channel.gainR);
605
599
  const scheduledNotes = channel.scheduledNotes;
606
600
  if (scheduledNotes.has(noteNumber)) {
607
601
  scheduledNotes.get(noteNumber).push(note);
@@ -704,13 +698,13 @@ class MidyGMLite {
704
698
  channel.program = program;
705
699
  }
706
700
  handlePitchBendMessage(channelNumber, lsb, msb) {
707
- const pitchBend = msb * 128 + lsb;
701
+ const pitchBend = msb * 128 + lsb - 8192;
708
702
  this.setPitchBend(channelNumber, pitchBend);
709
703
  }
710
704
  setPitchBend(channelNumber, pitchBend) {
711
705
  const channel = this.channels[channelNumber];
712
706
  const prevPitchBend = channel.pitchBend;
713
- channel.pitchBend = (pitchBend - 8192) / 8192;
707
+ channel.pitchBend = pitchBend / 8192;
714
708
  const detuneChange = (channel.pitchBend - prevPitchBend) *
715
709
  channel.pitchBendRange * 100;
716
710
  this.updateDetune(channel, detuneChange);
@@ -880,7 +874,7 @@ class MidyGMLite {
880
874
  channel.scheduledNotes.forEach((noteList) => {
881
875
  const activeNote = this.getActiveNote(noteList, now);
882
876
  if (activeNote) {
883
- const notePromise = this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, stopPedal);
877
+ const notePromise = this.scheduleNoteRelease(channelNumber, activeNote.noteNumber, velocity, now, stopPedal);
884
878
  promises.push(notePromise);
885
879
  }
886
880
  });
package/script/midy.d.ts CHANGED
@@ -93,6 +93,19 @@ export class Midy {
93
93
  };
94
94
  masterGain: any;
95
95
  channels: any[];
96
+ reverbEffect: {
97
+ input: any;
98
+ output: any;
99
+ };
100
+ chorusEffect: {
101
+ input: any;
102
+ output: any;
103
+ sendGain: any;
104
+ lfo: any;
105
+ lfoGain: any;
106
+ delayNodes: any[];
107
+ feedbackGains: any[];
108
+ };
96
109
  initSoundFontTable(): any[];
97
110
  addSoundFont(soundFont: any): void;
98
111
  loadSoundFont(soundFontUrl: any): Promise<void>;
@@ -101,19 +114,6 @@ export class Midy {
101
114
  gainL: any;
102
115
  gainR: any;
103
116
  merger: any;
104
- reverbEffect: {
105
- input: any;
106
- output: any;
107
- };
108
- chorusEffect: {
109
- input: any;
110
- output: any;
111
- sendGain: any;
112
- lfo: any;
113
- lfoGain: any;
114
- delayNodes: any[];
115
- feedbackGains: any[];
116
- };
117
117
  };
118
118
  createChannels(audioContext: any): any[];
119
119
  createNoteBuffer(instrumentKey: any, isSF3: any): Promise<any>;
@@ -147,7 +147,7 @@ export class Midy {
147
147
  createCombFilter(audioContext: any, input: any, delay: any, feedback: any): any;
148
148
  createAllpassFilter(audioContext: any, input: any, delay: any, feedback: any): any;
149
149
  generateDistributedArray(center: any, count: any, varianceRatio?: number, randomness?: number): any[];
150
- createSchroederReverb(audioContext: any, combDelays: any, combFeedbacks: any, allpassDelays: any, allpassFeedbacks: any): {
150
+ createSchroederReverb(audioContext: any, combFeedbacks: any, combDelays: any, allpassFeedbacks: any, allpassDelays: any): {
151
151
  input: any;
152
152
  output: any;
153
153
  };
@@ -160,12 +160,11 @@ export class Midy {
160
160
  delayNodes: any[];
161
161
  feedbackGains: any[];
162
162
  };
163
- connectEffects(channel: any, gainNode: any): void;
164
163
  cbToRatio(cb: any): number;
165
164
  centToHz(cent: any): number;
166
165
  calcSemitoneOffset(channel: any): any;
167
166
  calcPlaybackRate(instrumentKey: any, noteNumber: any, semitoneOffset: any): number;
168
- setVolumeEnvelope(channel: any, note: any): void;
167
+ setVolumeEnvelope(note: any): void;
169
168
  setFilterEnvelope(channel: any, note: any): void;
170
169
  startModulation(channel: any, note: any, time: any): void;
171
170
  startVibrato(channel: any, note: any, time: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"midy.d.ts","sourceRoot":"","sources":["../src/midy.js"],"names":[],"mappings":"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"}
package/script/midy.js CHANGED
@@ -85,7 +85,7 @@ class Midy {
85
85
  writable: true,
86
86
  value: {
87
87
  time: this.getReverbTime(64),
88
- feedback: 0.25,
88
+ feedback: 0.8,
89
89
  }
90
90
  });
91
91
  Object.defineProperty(this, "chorus", {
@@ -227,8 +227,12 @@ class Midy {
227
227
  this.audioContext = audioContext;
228
228
  this.options = { ...this.defaultOptions, ...options };
229
229
  this.masterGain = new GainNode(audioContext);
230
- this.masterGain.connect(audioContext.destination);
231
230
  this.channels = this.createChannels(audioContext);
231
+ this.reverbEffect = this.options.reverbAlgorithm(audioContext);
232
+ this.chorusEffect = this.createChorusEffect(audioContext);
233
+ this.chorusEffect.output.connect(this.masterGain);
234
+ this.reverbEffect.output.connect(this.masterGain);
235
+ this.masterGain.connect(audioContext.destination);
232
236
  this.GM2SystemOn();
233
237
  }
234
238
  initSoundFontTable() {
@@ -272,14 +276,11 @@ class Midy {
272
276
  const merger = new ChannelMergerNode(audioContext, { numberOfInputs: 2 });
273
277
  gainL.connect(merger, 0, 0);
274
278
  gainR.connect(merger, 0, 1);
275
- const reverbEffect = this.options.reverbAlgorithm(audioContext);
276
- const chorusEffect = this.createChorusEffect(audioContext);
279
+ merger.connect(this.masterGain);
277
280
  return {
278
281
  gainL,
279
282
  gainR,
280
283
  merger,
281
- reverbEffect,
282
- chorusEffect,
283
284
  };
284
285
  }
285
286
  createChannels(audioContext) {
@@ -695,7 +696,7 @@ class Midy {
695
696
  }
696
697
  // https://hajim.rochester.edu/ece/sites/zduan/teaching/ece472/reading/Schroeder_1962.pdf
697
698
  // M.R.Schroeder, "Natural Sounding Artificial Reverberation", J.Audio Eng. Soc., vol.10, p.219, 1962
698
- createSchroederReverb(audioContext, combDelays, combFeedbacks, allpassDelays, allpassFeedbacks) {
699
+ createSchroederReverb(audioContext, combFeedbacks, combDelays, allpassFeedbacks, allpassDelays) {
699
700
  const input = new GainNode(audioContext);
700
701
  const output = new GainNode(audioContext);
701
702
  const mergerGain = new GainNode(audioContext);
@@ -754,21 +755,6 @@ class Midy {
754
755
  feedbackGains,
755
756
  };
756
757
  }
757
- connectEffects(channel, gainNode) {
758
- gainNode.connect(channel.merger);
759
- channel.merger.connect(this.masterGain);
760
- if (0 < channel.reverbSendLevel) {
761
- channel.merger.connect(channel.reverbEffect.input);
762
- channel.reverbEffect.output.connect(this.masterGain);
763
- }
764
- if (0 < channel.chorusSendLevel) {
765
- channel.merger.connect(channel.chorusEffect.input);
766
- channel.reverbEffect.output.connect(this.masterGain);
767
- }
768
- if (0 < this.chorus.sendToReverb) {
769
- channel.chorusEffect.sendGain.connect(channel.reverbEffect.input);
770
- }
771
- }
772
758
  cbToRatio(cb) {
773
759
  return Math.pow(10, cb / 200);
774
760
  }
@@ -785,14 +771,10 @@ class Midy {
785
771
  return instrumentKey.playbackRate(noteNumber) *
786
772
  Math.pow(2, semitoneOffset / 12);
787
773
  }
788
- setVolumeEnvelope(channel, note) {
789
- const { instrumentKey, startTime, velocity } = note;
774
+ setVolumeEnvelope(note) {
775
+ const { instrumentKey, startTime } = note;
790
776
  note.gainNode = new GainNode(this.audioContext, { gain: 0 });
791
- let volume = (velocity / 127) * channel.volume * channel.expression;
792
- if (volume === 0)
793
- volume = 1e-6; // exponentialRampToValueAtTime() requires a non-zero value
794
- const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation) *
795
- volume;
777
+ const attackVolume = this.cbToRatio(-instrumentKey.initialAttenuation);
796
778
  const sustainVolume = attackVolume * (1 - instrumentKey.volSustain);
797
779
  const volDelay = startTime + instrumentKey.volDelay;
798
780
  const volAttack = volDelay + instrumentKey.volAttack;
@@ -865,7 +847,7 @@ class Midy {
865
847
  const note = new Note(noteNumber, velocity, startTime, instrumentKey);
866
848
  note.bufferSource = await this.createNoteBufferNode(instrumentKey, isSF3);
867
849
  note.bufferSource.playbackRate.value = this.calcPlaybackRate(instrumentKey, noteNumber, semitoneOffset);
868
- this.setVolumeEnvelope(channel, note);
850
+ this.setVolumeEnvelope(note);
869
851
  this.setFilterEnvelope(channel, note);
870
852
  if (channel.modulation > 0) {
871
853
  const delayModLFO = startTime + instrumentKey.delayModLFO;
@@ -905,7 +887,8 @@ class Midy {
905
887
  if (!instrumentKey)
906
888
  return;
907
889
  const note = await this.createNote(channel, instrumentKey, noteNumber, velocity, startTime, isSF3);
908
- this.connectEffects(channel, note.gainNode);
890
+ note.gainNode.connect(channel.gainL);
891
+ note.gainNode.connect(channel.gainR);
909
892
  if (channel.sostenutoPedal) {
910
893
  channel.sostenutoNotes.set(noteNumber, note);
911
894
  }
@@ -1065,13 +1048,13 @@ class Midy {
1065
1048
  }
1066
1049
  }
1067
1050
  handlePitchBendMessage(channelNumber, lsb, msb) {
1068
- const pitchBend = msb * 128 + lsb;
1051
+ const pitchBend = msb * 128 + lsb - 8192;
1069
1052
  this.setPitchBend(channelNumber, pitchBend);
1070
1053
  }
1071
1054
  setPitchBend(channelNumber, pitchBend) {
1072
1055
  const channel = this.channels[channelNumber];
1073
1056
  const prevPitchBend = channel.pitchBend;
1074
- channel.pitchBend = (pitchBend - 8192) / 8192;
1057
+ channel.pitchBend = pitchBend / 8192;
1075
1058
  const detuneChange = (channel.pitchBend - prevPitchBend) *
1076
1059
  channel.pitchBendRange * 100;
1077
1060
  this.updateDetune(channel, detuneChange);
@@ -1217,20 +1200,30 @@ class Midy {
1217
1200
  this.channels[channelNumber].portamento = value >= 64;
1218
1201
  }
1219
1202
  setReverbSendLevel(channelNumber, reverbSendLevel) {
1220
- const now = this.audioContext.currentTime;
1221
1203
  const channel = this.channels[channelNumber];
1222
- const reverbEffect = channel.reverbEffect;
1223
- channel.reverbSendLevel = reverbSendLevel / 127;
1224
- reverbEffect.output.gain.cancelScheduledValues(now);
1225
- reverbEffect.output.gain.setValueAtTime(channel.reverbSendLevel, now);
1204
+ const reverbEffect = this.reverbEffect;
1205
+ if (0 < reverbSendLevel) {
1206
+ const now = this.audioContext.currentTime;
1207
+ channel.reverbSendLevel = reverbSendLevel / 127;
1208
+ reverbEffect.output.gain.cancelScheduledValues(now);
1209
+ reverbEffect.output.gain.setValueAtTime(channel.reverbSendLevel, now);
1210
+ }
1211
+ else if (channel.reverbSendLevel !== 0) {
1212
+ channel.merger.disconnect(reverbEffect.input);
1213
+ }
1226
1214
  }
1227
1215
  setChorusSendLevel(channelNumber, chorusSendLevel) {
1228
- const now = this.audioContext.currentTime;
1229
1216
  const channel = this.channels[channelNumber];
1230
- const chorusEffect = channel.chorusEffect;
1231
- channel.chorusSendLevel = chorusSendLevel / 127;
1232
- chorusEffect.output.gain.cancelScheduledValues(now);
1233
- chorusEffect.output.gain.setValueAtTime(channel.chorusSendLevel, now);
1217
+ const chorusEffect = this.chorusEffect;
1218
+ if (0 < chorusSendLevel) {
1219
+ const now = this.audioContext.currentTime;
1220
+ channel.chorusSendLevel = chorusSendLevel / 127;
1221
+ chorusEffect.output.gain.cancelScheduledValues(now);
1222
+ chorusEffect.output.gain.setValueAtTime(channel.chorusSendLevel, now);
1223
+ }
1224
+ else if (channel.chorusSendLevel !== 0) {
1225
+ channel.merger.disconnect(chorusEffect.input);
1226
+ }
1234
1227
  }
1235
1228
  setSostenutoPedal(channelNumber, value) {
1236
1229
  const isOn = value >= 64;
@@ -1423,7 +1416,7 @@ class Midy {
1423
1416
  channel.scheduledNotes.forEach((noteList) => {
1424
1417
  const activeNote = this.getActiveNote(noteList, now);
1425
1418
  if (activeNote) {
1426
- const notePromise = this.scheduleNoteRelease(channelNumber, noteNumber, velocity, now, stopPedal);
1419
+ const notePromise = this.scheduleNoteRelease(channelNumber, activeNote.noteNumber, velocity, now, stopPedal);
1427
1420
  promises.push(notePromise);
1428
1421
  }
1429
1422
  });
@@ -1592,11 +1585,9 @@ class Midy {
1592
1585
  }
1593
1586
  setReverbType(type) {
1594
1587
  this.reverb.time = this.getReverbTimeFromType(type);
1595
- this.reverb.feedback = (type === 8) ? 0.1 : 0.2;
1596
- const { audioContext, channels, options } = this;
1597
- for (let i = 0; i < channels.length; i++) {
1598
- channels[i].reverbEffect = options.reverbAlgorithm(audioContext);
1599
- }
1588
+ this.reverb.feedback = (type === 8) ? 0.9 : 0.8;
1589
+ const { audioContext, options } = this;
1590
+ this.reverbEffect = options.reverbAlgorithm(audioContext);
1600
1591
  }
1601
1592
  getReverbTimeFromType(type) {
1602
1593
  switch (type) {
@@ -1738,15 +1729,17 @@ class Midy {
1738
1729
  return value * 0.00763;
1739
1730
  }
1740
1731
  setChorusSendToReverb(value) {
1741
- const now = this.audioContext.currentTime;
1742
1732
  const sendToReverb = this.getChorusSendToReverb(value);
1743
- this.chorus.sendToReverb = sendToReverb;
1744
- for (let i = 0; i < this.channels.length; i++) {
1745
- const chorusEffect = this.channels[i].chorusEffect;
1746
- chorusEffect.sendGain.gain
1733
+ if (0 < sendToReverb) {
1734
+ const now = this.audioContext.currentTime;
1735
+ this.chorus.sendToReverb = sendToReverb;
1736
+ this.chorusEffect.sendGain.gain
1747
1737
  .cancelScheduledValues(now)
1748
1738
  .setValueAtTime(sendToReverb, now);
1749
1739
  }
1740
+ else if (this.chorus.sendToReverb !== 0) {
1741
+ this.chorusEffect.sendGain.disconnect(this.reverbEffect.input);
1742
+ }
1750
1743
  }
1751
1744
  getChorusSendToReverb(value) {
1752
1745
  return value * 0.00787;